From 3d4db97dfbc958c4155a53dc21953706400f146e Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 27 Jan 2020 17:50:20 -0800 Subject: [PATCH 0001/1218] Update the name in the main MD readme files. --- .../standard-bug-report-for-gapid.md | 10 ++--- BUILD.bazel | 4 +- BUILDING.md | 12 +++--- CONTRIBUTING.md | 40 +++++++++---------- DEVDOC.md | 18 ++++----- README.md | 23 +++++------ 6 files changed, 52 insertions(+), 55 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/standard-bug-report-for-gapid.md b/.github/ISSUE_TEMPLATE/standard-bug-report-for-gapid.md index 5f97e5b6dc..179d0e904c 100644 --- a/.github/ISSUE_TEMPLATE/standard-bug-report-for-gapid.md +++ b/.github/ISSUE_TEMPLATE/standard-bug-report-for-gapid.md @@ -1,6 +1,6 @@ --- -name: Standard Bug report for GAPID -about: Create an actionable bug-report for GAPID +name: Standard Bug report for Android GPU Inspector +about: Create an actionable bug-report for Android GPU Inspector title: '' labels: '' assignees: '' @@ -8,7 +8,7 @@ assignees: '' --- **Environment information:** - - GAPID version: + - AGI version: - Host OS: [e.g. Linux] If tracing on Android: - Device model: @@ -27,5 +27,5 @@ Please paste a stacktrace here if it's available. If applicable, add screenshots to help explain your problem. **Additional debugging information** -- Please attach the generated _gapis.log_ and _gapic.log_ files you will find in the temp folder (e.g. /tmp/ on linux). -- If using Android: Please attach a full logcat dump (```adb logcat -d > logcat-full.txt```) that contains logs since GAPID was started. +- Please attach the generated _gapis.log_ and _gapic.log_ files you will find in the temp folder (e.g. /tmp/ on linux). +- If using Android: Please attach a full logcat dump (```adb logcat -d > logcat-full.txt```) that contains logs since AGI was started. diff --git a/BUILD.bazel b/BUILD.bazel index cecd17b31a..273078a555 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -12,9 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Description: -# -# Gapid is a graphics API debugger. +# Root BUILD file for Android GPU Inspector. licenses(["notice"]) # Apache 2.0 diff --git a/BUILDING.md b/BUILDING.md index f66b0ca94e..94190f0ff6 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,19 +1,19 @@ -# Building GAPID +# Building Android GPU Inspector -GAPID uses the [Bazel build system](https://bazel.build/). The recommended version of Bazel is **1.2.0**. +AGI uses the [Bazel build system](https://bazel.build/). The recommended version of Bazel is **1.2.0**. -Bazel is able to fetch most of the dependencies required to build GAPID, but currently the Android SDK and NDK both need to be downloaded and installed by hand. +Bazel is able to fetch most of the dependencies required to build AGI, but currently the Android SDK and NDK both need to be downloaded and installed by hand. Please see the following OS specific guides for setting up the build environment. -After setting up the build environment, GAPID can be built in a terminal with: +After setting up the build environment, AGI can be built in a terminal with: ``` -cd +cd bazel build pkg ``` -The build output will be at `/bazel-bin/pkg`. +The build output will be at `/bazel-bin/pkg`. --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1e82b5f282..976c8c0337 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,32 +5,32 @@ just a few small guidelines you need to follow. ## Check out the source -Do the following to check out the GAPID source code on GitHub: +Do the following to check out the Android GPU Inspector source code on GitHub: 1. Sign up for GitHub at https://github.com/ if you don’t already have an account. 1. (Optional) Set up an SSH key to [connect to your account using SSH]. 1. (Optional) [Add a GPG signing key to your account]. -1. Go to the project landing page at https://github.com/google/gapid. +1. Go to the project landing page at https://github.com/google/agi. 1. [Fork the repository]. This creates a copy of the repository in your account. 1. Create a work folder on your workstation. The rest of this document assumes `~/work`, adjust as needed. -1. On _your_ GAPID project page, [clone your copy of the repository] and add it to your local work folder: +1. On _your_ AGI project page, [clone your copy of the repository] and add it to your local work folder: ``` cd ~/work git clone - cd gapid + cd agi ``` 1. Add the Google remote repository to your local repository: ``` - git remote add goog git@github.com:google/gapid.git + git remote add goog git@github.com:google/agi.git git fetch goog ``` ## (Optional) Configure git -Use the following commands to configure git for GAPID development: +Use the following commands to configure git for AGI development: ``` # Assume the remote branch has the same name as your local branch to make pushing changes easier -git config push.default current +git config push.default current # Default to pushing to your fork (assuming the above directions) git config remote.pushDefault origin # Make git clean up all the remote tags it creates when you delete remote branches @@ -38,13 +38,13 @@ git config fetch.prune true git config user.name # Add --global to make this a global setting git config user.email # Can also be a global setting # If you added a GPG signing key, run the following commands: -git config user.signingkey +git config user.signingkey git config commit.gpgsign true ``` -## Build GAPID for the first time +## Build Android GPU Inspector for the first time -Follow the [build instructions] in the GAPID repository. +Follow the [build instructions] in the AGI repository. ## Sign the Contributor License Agreement @@ -58,17 +58,17 @@ You generally only need to submit a CLA once, so if you've already submitted one ## Open a pull request (PR) -Do the following to contribute to the GAPID project: +Do the following to contribute to the AGI project: 1. Prepare your changes on a dedicated branch in your local repository: ``` git checkout -b - ``` -1. Make changes, commit the changes, and squash them into a single commit. + ``` +1. Make changes, commit the changes, and squash them into a single commit. 1. Use the presubmit script to check code formatting and other things: ``` - # Install clang-format 6.0 - sudo apt-get install -y clang-format-6.0 + # Install clang-format 6.0 + sudo apt-get install -y clang-format-6.0 export CLANG_FORMAT=clang-format-6.0 # Run the script ./kokoro/presubmit/presubmit.sh @@ -81,10 +81,10 @@ Do the following to contribute to the GAPID project: ``` 1. Push to your GitHub repo: ``` - git push + git push ``` -1. Visit https://github.com/google/gapid to see a pop-up dialog inviting you to open a PR; click on the dialog to create a PR. See [Creating a pull request from a fork] for more information. -1. All submissions, including submissions by project members, require review. You can request specific reviewers for your PR or leave the reviewers section blank. A GAPID team member will review the request. +1. Visit https://github.com/google/agi to see a pop-up dialog inviting you to open a PR; click on the dialog to create a PR. See [Creating a pull request from a fork] for more information. +1. All submissions, including submissions by project members, require review. You can request specific reviewers for your PR or leave the reviewers section blank. An AGI team member will review the request. Consult [GitHub Help] for more information on using pull requests. @@ -92,6 +92,6 @@ Consult [GitHub Help] for more information on using pull requests. [Add a GPG signing key to your account]: https://help.github.com/en/articles/adding-a-new-gpg-key-to-your-github-account [Fork the repository]: https://help.github.com/en/articles/fork-a-repo [clone your copy of the repository]: https://help.github.com/en/articles/cloning-a-repository -[build instructions]: https://github.com/google/gapid/blob/master/BUILDING.md +[build instructions]: https://github.com/google/agi/blob/master/BUILDING.md [Creating a pull request from a fork]: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork -[GitHub Help]: https://help.github.com/articles/about-pull-requests/ \ No newline at end of file +[GitHub Help]: https://help.github.com/articles/about-pull-requests/ diff --git a/DEVDOC.md b/DEVDOC.md index 1d60928715..d51e720b89 100644 --- a/DEVDOC.md +++ b/DEVDOC.md @@ -1,4 +1,4 @@ -# GAPID Developer Documentation +# Android GPU Inspector Developer Documentation ## Setup Golang development @@ -9,18 +9,18 @@ tools: ```sh # Make sure to build to have all compile-time generated files -cd +cd bazel build pkg -# Prepare a gapid-gofuse directory **outside of the gapid checkout directory** -mkdir /gapid-gofuse +# Prepare a agi-gofuse directory **outside of the AGI checkout directory** +mkdir /agi-gofuse # Run gofuse with the previous directory as a target -bazel run //cmd/gofuse -- -dir +bazel run //cmd/gofuse -- -dir -# Add gapid-gofuse directory to your GOPATH environment variable. +# Add agi-gofuse directory to your GOPATH environment variable. # On Linux, with a bash shell, you can add the following to your ~/.bashrc file: -export GOPATH="${GOPATH:+${GOPATH}:}" +export GOPATH="${GOPATH:+${GOPATH}:}" # On other configurations, please search online how to add/edit environment variables. ``` @@ -31,7 +31,7 @@ as described [here](https://blogs.windows.com/windowsdeveloper/2016/12/02/symlin After adding the gofuse directory to your GOPATH, Go tools should work as expected. You can edit files under the newly populated gofuse directory. You -should still compile under the original checkout directory of GAPID. +should still compile under the original AGI checkout directory. > Despite its name, the gofuse command does NOT use FUSE (filesystem in userspace). > It just creates directories and links to source files, including generated files. @@ -112,7 +112,7 @@ dlv exec --init my-delve-init-script.txt ### Integration with an IDE If you want to interact with the debugger via your editor or IDE, be aware that -delve will think file paths start from the gapid top directory, and not your +delve will think file paths start from the AGI top directory, and not your root directory. This is very likely due to Bazel compilation. You may have to find workarounds if you call delve from an editor/IDE which consider the file paths to start from another directory, typically your root directory. There may diff --git a/README.md b/README.md index 944426312a..32e79dd57a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GAPID: Graphics API Debugger +# Android GPU Inspector [![GoDoc](https://godoc.org/github.com/google/gapid?status.svg)](https://godoc.org/github.com/google/gapid) [![Gitter](https://badges.gitter.im/google/gapid.svg)](https://gitter.im/google/gapid?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -11,23 +11,23 @@ ## Downloads -**[Download the latest version of GAPID here.](https://github.com/google/gapid/releases)** +**[Download the latest version of AGI here.](https://github.com/google/agi/releases)** -*Unstable* developer releases are [here](https://github.com/google/gapid-dev-releases/releases). +*Unstable* developer releases are [here](https://github.com/google/agi-dev-releases/releases). ## Documentation **[User documentation can be found at gapid.dev](https://gapid.dev)** -The [developer documentation](DEVDOC.md) contains some hints for GAPID +The [developer documentation](DEVDOC.md) contains some hints for AGI developers. See also the README files under some source directories. ## About -GAPID is a collection of tools that allows you to inspect, tweak and replay calls from an application to a graphics driver. +Android GPU Inspector is a collection of tools that allows you to inspect, tweak and replay calls from an application to a graphics driver. -GAPID can trace any Android [debuggable application](https://developer.android.com/guide/topics/manifest/application-element.html#debug), or if you have root access to the device any application can be traced. -GAPID can also trace any desktop Vulkan application. +Android GPU Inspector can trace any Android [debuggable application](https://developer.android.com/guide/topics/manifest/application-element.html#debug), or if you have root access to the device any application can be traced. +AGI can also trace any desktop Vulkan application. @@ -58,19 +58,19 @@ GAPID can also trace any desktop Vulkan application. ## Building -**See [Building GAPID](BUILDING.md).** +**See [Building Android GPU Inspector](BUILDING.md).** ## Running the client -After building GAPID, you can run the client from `/bazel-bin/pkg/gapid`. +After building AGI, you can run the client from `/bazel-bin/pkg/gapid`. ## Command-Line Interface -GAPID exposes most of its functionality via a CLI *gapit*. You can find auto-generated documentation [here](https://gapid.dev/cli/). +AGI exposes most of its functionality via a CLI *gapit*. You can find auto-generated documentation [here](https://gapid.dev/cli/). ## Project Structure -GAPID consists of the following sub-components: +Android GPU Inspector consists of the following sub-components: ### [`gapii`](gapii): Graphics API Interceptor A layer that sits between the application / game and the GPU driver, recording all the calls and memory accesses. @@ -86,4 +86,3 @@ The frontend user interface application. Provides visual inspection of the captu ### [`gapil`](gapil): Graphics API Language A new domain specific language to describe a graphics API in its entirety. Combined with our template system to generate huge parts of the interceptor, server and replay systems. - From 70fc7801d87e4f5dd774d9b616b42b0aa70f9f2a Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 10:28:50 -0800 Subject: [PATCH 0002/1218] Reset the AGI version to 0.9.0. --- .bazelrc | 4 +-- cmd/gapir/cc/main.cpp | 4 +-- core/app/BUILD.bazel | 4 +-- core/app/default_version.go.in | 8 ++--- core/cc/BUILD.bazel | 4 +-- core/cc/version.h.in | 12 ++++---- gapic/src/main/BUILD.bazel | 4 +-- .../google/gapid/util/GapidVersion.java.in | 4 +-- tools/build/BUILD.bazel | 4 +-- tools/build/build.properties.in | 10 +++---- version.bzl | 30 +++++++++---------- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/.bazelrc b/.bazelrc index 8ba84ebeef..08f818a67e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Bazel RC file for the GAPID build. +# Bazel RC file for the AGI build. # Import any user defined rules. try-import %workspace%/user.bazelrc @@ -29,7 +29,7 @@ build --cxxopt="-std=c++11" --host_cxxopt="-std=c++11" build --fat_apk_cpu armeabi-v7a,arm64-v8a,x86 # Default version defines -build --define GAPID_BUILD_NUMBER=0 --define GAPID_BUILD_SHA=developer +build --define AGI_BUILD_NUMBER=0 --define AGI_BUILD_SHA=developer # Without this, bazel wraps each cc_library with "--whole-archive" flags for the # linker when building the dynamic library, which leads to over-bloated libs. diff --git a/cmd/gapir/cc/main.cpp b/cmd/gapir/cc/main.cpp index d21bf2dd7d..61441f24ca 100644 --- a/cmd/gapir/cc/main.cpp +++ b/cmd/gapir/cc/main.cpp @@ -681,7 +681,7 @@ void android_main(struct android_app* app) { Options::PrintHelp(); return; } else if (opts.version) { - GAPID_INFO("GAPIR version " GAPID_VERSION_AND_BUILD "\n"); + GAPID_INFO("GAPIR version " AGI_VERSION_AND_BUILD "\n"); return; } else if (opts.mode == kConflict) { GAPID_ERROR("Argument conflicts."); @@ -974,7 +974,7 @@ int main(int argc, const char* argv[]) { Options::PrintHelp(); return EXIT_SUCCESS; } else if (opts.version) { - printf("GAPIR version " GAPID_VERSION_AND_BUILD "\n"); + printf("GAPIR version " AGI_VERSION_AND_BUILD "\n"); return EXIT_SUCCESS; } else if (opts.mode == kConflict) { GAPID_ERROR("Argument conflicts."); diff --git a/core/app/BUILD.bazel b/core/app/BUILD.bazel index f825943ca1..a238fab998 100644 --- a/core/app/BUILD.bazel +++ b/core/app/BUILD.bazel @@ -13,7 +13,7 @@ # limitations under the License. load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("//:version.bzl", "gapid_version") +load("//:version.bzl", "agi_version") go_library( name = "go_default_library", @@ -49,7 +49,7 @@ go_library( ], ) -gapid_version( +agi_version( name = "version", out = "default_version.go", template = "default_version.go.in", diff --git a/core/app/default_version.go.in b/core/app/default_version.go.in index c844470775..4fe0c0d316 100644 --- a/core/app/default_version.go.in +++ b/core/app/default_version.go.in @@ -16,9 +16,9 @@ package app func init() { Version = VersionSpec{ - Major: @GAPID_VERSION_MAJOR@, - Minor: @GAPID_VERSION_MINOR@, - Point: @GAPID_VERSION_POINT@, - Build: "@GAPID_BUILD_SHA@", + Major: @AGI_VERSION_MAJOR@, + Minor: @AGI_VERSION_MINOR@, + Point: @AGI_VERSION_POINT@, + Build: "@AGI_BUILD_SHA@", } } diff --git a/core/cc/BUILD.bazel b/core/cc/BUILD.bazel index fde4ab418a..a12bf9d267 100644 --- a/core/cc/BUILD.bazel +++ b/core/cc/BUILD.bazel @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//:version.bzl", "gapid_version") +load("//:version.bzl", "agi_version") load("//tools/build:rules.bzl", "cc_copts") cc_library( @@ -63,7 +63,7 @@ cc_library( ], ) -gapid_version( +agi_version( name = "version", out = "version.h", template = "version.h.in", diff --git a/core/cc/version.h.in b/core/cc/version.h.in index 800288e242..fa28fd4b99 100644 --- a/core/cc/version.h.in +++ b/core/cc/version.h.in @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef GAPID_VERSION_AND_BUILD -#define GAPID_VERSION_AND_BUILD \ - "@GAPID_VERSION_MAJOR@." \ - "@GAPID_VERSION_MINOR@." \ - "@GAPID_VERSION_POINT@." \ - "@GAPID_BUILD_SHA@" +#ifndef AGI_VERSION_AND_BUILD +#define AGI_VERSION_AND_BUILD \ + "@AGI_VERSION_MAJOR@." \ + "@AGI_VERSION_MINOR@." \ + "@AGI_VERSION_POINT@." \ + "@AGI_BUILD_SHA@" #endif diff --git a/gapic/src/main/BUILD.bazel b/gapic/src/main/BUILD.bazel index fbf3fde0e5..3ed9f1fb04 100644 --- a/gapic/src/main/BUILD.bazel +++ b/gapic/src/main/BUILD.bazel @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//:version.bzl", "gapid_version") +load("//:version.bzl", "agi_version") load("//tools/build:rules.bzl", "java_grpc_library") java_library( @@ -33,7 +33,7 @@ java_library( ], ) -gapid_version( +agi_version( name = "version", out = "com/google/gapid/util/GapidVersion.java", template = "com/google/gapid/util/GapidVersion.java.in", diff --git a/gapic/src/main/com/google/gapid/util/GapidVersion.java.in b/gapic/src/main/com/google/gapid/util/GapidVersion.java.in index e9d77267ca..126a1e77ec 100644 --- a/gapic/src/main/com/google/gapid/util/GapidVersion.java.in +++ b/gapic/src/main/com/google/gapid/util/GapidVersion.java.in @@ -17,7 +17,7 @@ package com.google.gapid.util; /** * Current version specifier. */ -@javax.annotation.Generated("by GAPID bazel") +@javax.annotation.Generated("by AGI bazel") public interface GapidVersion { - public static final Version GAPID_VERSION = new Version(@GAPID_VERSION_MAJOR@, @GAPID_VERSION_MINOR@, @GAPID_VERSION_POINT@, "@GAPID_BUILD_SHA@"); + public static final Version GAPID_VERSION = new Version(@AGI_VERSION_MAJOR@, @AGI_VERSION_MINOR@, @AGI_VERSION_POINT@, "@AGI_BUILD_SHA@"); } diff --git a/tools/build/BUILD.bazel b/tools/build/BUILD.bazel index 1e6fb01f52..61a8fc2ade 100644 --- a/tools/build/BUILD.bazel +++ b/tools/build/BUILD.bazel @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//:version.bzl", "gapid_version") +load("//:version.bzl", "agi_version") -gapid_version( +agi_version( name = "build_properties", out = "build.properties", template = ":build_host_and_time", diff --git a/tools/build/build.properties.in b/tools/build/build.properties.in index 8b3500b97e..04ed745883 100644 --- a/tools/build/build.properties.in +++ b/tools/build/build.properties.in @@ -1,6 +1,6 @@ -Version.Major=@GAPID_VERSION_MAJOR@ -Version.Minor=@GAPID_VERSION_MINOR@ -Version.Micro=@GAPID_VERSION_POINT@ +Version.Major=@AGI_VERSION_MAJOR@ +Version.Minor=@AGI_VERSION_MINOR@ +Version.Micro=@AGI_VERSION_POINT@ -Build.Number=@GAPID_BUILD_NUMBER@ -Build.SHA=@GAPID_BUILD_SHA@ +Build.Number=@AGI_BUILD_NUMBER@ +Build.SHA=@AGI_BUILD_SHA@ diff --git a/version.bzl b/version.bzl index 50f8cafdbe..6140d6dfce 100644 --- a/version.bzl +++ b/version.bzl @@ -12,32 +12,32 @@ # See the License for the specific language governing permissions and # limitations under the License. -# True source of GAPID versions. +# True source of AGI versions. # Increment these numbers immediately after releasing a new version. -GAPID_VERSION_MAJOR="1" -GAPID_VERSION_MINOR="7" -GAPID_VERSION_POINT="0" +AGI_VERSION_MAJOR="0" +AGI_VERSION_MINOR="9" +AGI_VERSION_POINT="0" # See bazel.rc. Can be overriden on the command line with: -# bazel build --define GAPID_BUILD_NUMBER=<#> --define GAPID_BUILD_SHA= -GAPID_BUILD_NUMBER="$(GAPID_BUILD_NUMBER)" -GAPID_BUILD_SHA="$(GAPID_BUILD_SHA)" +# bazel build --define AGI_BUILD_NUMBER=<#> --define AGI_BUILD_SHA= +AGI_BUILD_NUMBER="$(AGI_BUILD_NUMBER)" +AGI_BUILD_SHA="$(AGI_BUILD_SHA)" -def _gapid_version(ctx): +def _agi_version(ctx): ctx.actions.expand_template( template = ctx.file.template, output = ctx.outputs.out, substitutions = { - "@GAPID_VERSION_MAJOR@": GAPID_VERSION_MAJOR, - "@GAPID_VERSION_MINOR@": GAPID_VERSION_MINOR, - "@GAPID_VERSION_POINT@": GAPID_VERSION_POINT, - "@GAPID_BUILD_NUMBER@": ctx.var.get("GAPID_BUILD_NUMBER"), - "@GAPID_BUILD_SHA@": ctx.var.get("GAPID_BUILD_SHA"), + "@AGI_VERSION_MAJOR@": AGI_VERSION_MAJOR, + "@AGI_VERSION_MINOR@": AGI_VERSION_MINOR, + "@AGI_VERSION_POINT@": AGI_VERSION_POINT, + "@AGI_BUILD_NUMBER@": ctx.var.get("AGI_BUILD_NUMBER"), + "@AGI_BUILD_SHA@": ctx.var.get("AGI_BUILD_SHA"), } ) -gapid_version = rule( - implementation=_gapid_version, +agi_version = rule( + implementation=_agi_version, attrs = { "template": attr.label( mandatory = True, From a9c65c6c497071eb304a5841402394f6e39a38bf Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 10:39:10 -0800 Subject: [PATCH 0003/1218] Update the Linux build and package scripts. --- kokoro/linux-test/test.sh | 6 ++--- kokoro/linux/build-dev.sh | 2 +- kokoro/linux/build.sh | 6 ++--- kokoro/linux/gapid.desktop | 8 +++---- kokoro/linux/gapid.menu | 6 ++--- kokoro/linux/package.sh | 45 ++++++++++++++++++-------------------- 6 files changed, 35 insertions(+), 38 deletions(-) diff --git a/kokoro/linux-test/test.sh b/kokoro/linux-test/test.sh index ead2a7f1b3..67093c33be 100755 --- a/kokoro/linux-test/test.sh +++ b/kokoro/linux-test/test.sh @@ -17,7 +17,7 @@ set -ex BUILD_ROOT=$PWD -SRC=$PWD/github/gapid/ +SRC=$PWD/github/agi/ # Get bazel BAZEL_VERSION=1.2.0 @@ -40,8 +40,8 @@ function test { $BUILD_ROOT/bazel/bin/bazel \ --output_base="${TMP}/bazel_out" \ test -c opt --config symbols \ - --define GAPID_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ - --define GAPID_BUILD_SHA="$BUILD_SHA" \ + --define AGI_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ + --define AGI_BUILD_SHA="$BUILD_SHA" \ --test_tag_filters=-needs_gpu \ $@ echo $(date): Tests completed. diff --git a/kokoro/linux/build-dev.sh b/kokoro/linux/build-dev.sh index 288ffb8445..0fec683469 100644 --- a/kokoro/linux/build-dev.sh +++ b/kokoro/linux/build-dev.sh @@ -19,4 +19,4 @@ devdate=`date '+%Y%m%d'` export DEV_PREFIX="dev-${devdate}-" -. $PWD/github/gapid/kokoro/linux/build.sh +. $PWD/github/agi/kokoro/linux/build.sh diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index dcebb487ec..25a17102f9 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -17,7 +17,7 @@ set -ex BUILD_ROOT=$PWD -SRC=$PWD/github/gapid/ +SRC=$PWD/github/agi/ # Get bazel. BAZEL_VERSION=1.2.0 @@ -48,8 +48,8 @@ function build { $BUILD_ROOT/bazel/bin/bazel \ --output_base="${TMP}/bazel_out" \ build -c opt --config symbols \ - --define GAPID_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ - --define GAPID_BUILD_SHA="$BUILD_SHA" \ + --define AGI_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ + --define AGI_BUILD_SHA="$BUILD_SHA" \ $@ echo $(date): Build completed. } diff --git a/kokoro/linux/gapid.desktop b/kokoro/linux/gapid.desktop index b0c7f4448d..e4ae181f39 100644 --- a/kokoro/linux/gapid.desktop +++ b/kokoro/linux/gapid.desktop @@ -1,10 +1,10 @@ [Desktop Entry] Encoding=UTF-8 Type=Application -Name=GAPID -Comment=Graphics API Debugger +Name=Android GPU Inspector +Comment=Android GPU Inspector Categories=Development;Debugger;Graphics;3DGraphics -Icon=/opt/gapid/icon.png -Exec=/opt/gapid/gapid %f +Icon=/opt/agi/icon.png +Exec=/opt/agi/gapid %f Terminal=false MimeType=application/x-gfxtrace diff --git a/kokoro/linux/gapid.menu b/kokoro/linux/gapid.menu index 63aa9b00af..5fafeb4588 100644 --- a/kokoro/linux/gapid.menu +++ b/kokoro/linux/gapid.menu @@ -1,3 +1,3 @@ -?package(gapid):needs="X11" section="Applications/Programming"\ - title="GAPID" longtitle="Graphics API Debugger" command="/opt/gapid/gapid"\ - icon="/opt/gapid/icon.png" +?package(agi):needs="X11" section="Applications/Programming"\ + title="AGI" longtitle="Android GPU Inspector" command="/opt/agi/gapid"\ + icon="/opt/agi/icon.png" diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh index 244e04da73..06dea6faff 100755 --- a/kokoro/linux/package.sh +++ b/kokoro/linux/package.sh @@ -44,49 +44,46 @@ VERSION=$(awk -F= 'BEGIN {major=0; minor=0; micro=0} END {print major"."minor"."micro}' $BIN/pkg/build.properties) # Combine package contents. -mkdir -p gapid/DEBIAN gapid/opt/gapid gapid/usr/share/applications gapid/usr/share/menu gapid/usr/share/mime/packages -cp -r $BIN/pkg/* gapid/opt/gapid -cp "$SRC/../../gapic/res/icons/logo_256.png" gapid/opt/gapid/icon.png -cp "$SRC/gapid.desktop" gapid/usr/share/applications/google-gapid.desktop -cp "$SRC/gapid.menu" gapid/usr/share/menu/google-gapid.menu -cp "$SRC/gapid-mime.xml" gapid/usr/share/mime/packages/gapid.xml +mkdir -p agi/DEBIAN agi/opt/agi agi/usr/share/applications agi/usr/share/menu agi/usr/share/mime/packages +cp -r $BIN/pkg/* agi/opt/agi +cp "$SRC/../../gapic/res/icons/logo_256.png" agi/opt/agi/icon.png +cp "$SRC/gapid.desktop" agi/usr/share/applications/google-agi.desktop +cp "$SRC/gapid.menu" agi/usr/share/menu/google-agi.menu +cp "$SRC/gapid-mime.xml" agi/usr/share/mime/packages/agi.xml # Create the dpkg config file. -cat > gapid/DEBIAN/control < agi/DEBIAN/control < -Description: GAPID is a collection of tools that allows you to inspect, tweak - and replay calls from an application to a graphics driver. +Description: Android Graphics Inspector is a collection of tools that allows you + to inspect, tweak and replay calls from an application to a graphics driver. . - GAPID can trace any Android debuggable application, or if you have root access + AGI can trace any Android debuggable application, or if you have root access to the device any application can be traced. -Homepage: https://github.com/google/gapid -Installed-Size: $(du -s gapid/opt | cut -f1) +Homepage: https://github.com/google/agi +Installed-Size: $(du -s agi/opt | cut -f1) EOF # Fix up permissions (root ownership is faked below). -find gapid/ -type f -exec chmod 644 {} + -chmod 755 gapid/opt/gapid/gapi[drst] gapid/opt/gapid/device-info -find gapid/ -type d -exec chmod 755 {} + -find gapid/ -type d -exec chmod g-s {} + +find agi/ -type f -exec chmod 644 {} + +chmod 755 agi/opt/agi/gapi[drst] agi/opt/agi/device-info +find agi/ -type d -exec chmod 755 {} + +find agi/ -type d -exec chmod g-s {} + # Package up zip file. -cd gapid/opt/ -zip -r ../../gapid-$VERSION-linux.zip gapid/ +cd agi/opt/ +zip -r ../../agi-$VERSION-linux.zip agi/ cd ../../ -# TODO Copy the GAPIR symbols -# cp ../current/gapir.sym gapir-$VERSION-linux.sym - # Build the .deb package. echo "$(date): Building package." -fakeroot dpkg-deb -v --build gapid -mv gapid.deb gapid-$VERSION-linux.deb +fakeroot dpkg-deb -v --build agi +mv agi.deb agi-$VERSION-linux.deb echo "$(date): Done." # Copy the symbol file to the output. From 849e4ef3dfb2452ae2b5612c9875abdf317cd80c Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 11:16:49 -0800 Subject: [PATCH 0004/1218] Update the presubmit build script. --- kokoro/presubmit/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/presubmit/build.sh b/kokoro/presubmit/build.sh index 5409a5eee4..80c4e34b96 100755 --- a/kokoro/presubmit/build.sh +++ b/kokoro/presubmit/build.sh @@ -17,7 +17,7 @@ set -ex BUILD_ROOT=$PWD -SRC=$PWD/github/gapid/ +SRC=$PWD/github/agi/ # Get bazel. BAZEL_VERSION=1.2.0 From b8b28357667d0073ed160d55fc5a547029cc9caf Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 11:08:59 -0800 Subject: [PATCH 0005/1218] Update the Windows build and package scripts. --- kokoro/windows/build-dev.bat | 2 +- kokoro/windows/build.bat | 14 +++---- kokoro/windows/gapid.wxs | 72 ++++++++++++++++++------------------ kokoro/windows/package.bat | 25 ++++++------- 4 files changed, 55 insertions(+), 58 deletions(-) diff --git a/kokoro/windows/build-dev.bat b/kokoro/windows/build-dev.bat index 00f1745784..a8a3c96a3b 100644 --- a/kokoro/windows/build-dev.bat +++ b/kokoro/windows/build-dev.bat @@ -22,4 +22,4 @@ for /f "tokens=1,2,3,4 delims=/ " %%a in ('date /t') do set devdate=%%d%%b%%c set DEV_PREFIX=dev-%devdate%- -call %cd%\github\gapid\kokoro\windows\build.bat +call %cd%\github\agi\kokoro\windows\build.bat diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat index 4e1840067a..2045aff9e5 100644 --- a/kokoro/windows/build.bat +++ b/kokoro/windows/build.bat @@ -17,7 +17,7 @@ Windows Build Script. :start set BUILD_ROOT=%cd% -set SRC=%cd%\github\gapid +set SRC=%cd%\github\agi REM Use a fixed JDK. set JAVA_HOME=c:\Program Files\Java\jdk1.8.0_144 @@ -68,21 +68,21 @@ if "%KOKORO_GITHUB_COMMIT%." == "." ( REM Build each API package separately first, as the go-compiler needs ~8GB of RAM for each package. %BUILD_ROOT%\bazel build -c opt --config symbols ^ - --define GAPID_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ - --define GAPID_BUILD_SHA="%BUILD_SHA%" ^ + --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ + --define AGI_BUILD_SHA="%BUILD_SHA%" ^ //gapis/api/gles:go_default_library if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% %BUILD_ROOT%\bazel build -c opt --config symbols ^ - --define GAPID_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ - --define GAPID_BUILD_SHA="%BUILD_SHA%" ^ + --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ + --define AGI_BUILD_SHA="%BUILD_SHA%" ^ //gapis/api/vulkan:go_default_library if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% REM Build everything else. %BUILD_ROOT%\bazel build -c opt --config symbols ^ - --define GAPID_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ - --define GAPID_BUILD_SHA="%BUILD_SHA%" ^ + --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ + --define AGI_BUILD_SHA="%BUILD_SHA%" ^ //:pkg //:symbols //cmd/smoketests //cmd/vulkan_sample:vulkan_sample if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% echo %DATE% %TIME% diff --git a/kokoro/windows/gapid.wxs b/kokoro/windows/gapid.wxs index e36d6251cb..d0e44710eb 100644 --- a/kokoro/windows/gapid.wxs +++ b/kokoro/windows/gapid.wxs @@ -12,19 +12,19 @@ See the License for the specific language governing permissions and limitations under the License. --> - + - + UpgradeCode="7187CA6A-4A6D-4187-B6B2-1E100176A91D" + Language="1033" Codepage="1252" Version="$(var.AGIVersion)"> - - + @@ -37,60 +37,60 @@ - + - + - + - + - + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + + - - + + - + diff --git a/kokoro/windows/package.bat b/kokoro/windows/package.bat index 682ab57ce5..81354c8e0f 100644 --- a/kokoro/windows/package.bat +++ b/kokoro/windows/package.bat @@ -51,25 +51,22 @@ awk -F= 'BEGIN {major=0; minor=0; micro=0}^ set /p VERSION= Date: Tue, 28 Jan 2020 11:09:08 -0800 Subject: [PATCH 0006/1218] Update the MacOS build and package scripts. --- kokoro/macos/Info.plist | 10 +++++----- kokoro/macos/build-dev.sh | 2 +- kokoro/macos/build.sh | 6 +++--- kokoro/macos/dmg-settings.py | 6 +++--- kokoro/macos/package.sh | 27 ++++++++++++--------------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/kokoro/macos/Info.plist b/kokoro/macos/Info.plist index 9824cf49ab..6332cfc46f 100644 --- a/kokoro/macos/Info.plist +++ b/kokoro/macos/Info.plist @@ -7,15 +7,15 @@ CFBundleExecutable gapid CFBundleIconFile - GAPID.icns + AGI.icns CFBundlePackageType APPL CFBundleName - GAPID + AGI CFBundleDisplayName - Graphics API Debugger + Android GPU Inspector CFBundleIdentifier - com.google.GAPID + com.google.agi CFBundleInfoDictionaryVersion 6 NSHumanReadableCopyright @@ -30,7 +30,7 @@ gfxtrace CFBundleTypeIconFile - GAPID.icns + AGI.icns CFBundleTypeName Graphics API Trace CFBundleTypeRole diff --git a/kokoro/macos/build-dev.sh b/kokoro/macos/build-dev.sh index 58b8236091..0284ebf4de 100644 --- a/kokoro/macos/build-dev.sh +++ b/kokoro/macos/build-dev.sh @@ -19,4 +19,4 @@ devdate=`date '+%Y%m%d'` export DEV_PREFIX="dev-${devdate}-" -. $PWD/github/gapid/kokoro/macos/build.sh +. $PWD/github/agi/kokoro/macos/build.sh diff --git a/kokoro/macos/build.sh b/kokoro/macos/build.sh index a8afe7ca2f..d9bae12081 100755 --- a/kokoro/macos/build.sh +++ b/kokoro/macos/build.sh @@ -17,7 +17,7 @@ set -ex BUILD_ROOT=$PWD -SRC=$PWD/github/gapid/ +SRC=$PWD/github/agi/ # Setup the Android SDK and NDK curl -L -k -O -s https://dl.google.com/android/repository/tools_r25.2.3-macosx.zip @@ -49,8 +49,8 @@ function build { $BUILD_ROOT/bazel/bin/bazel \ --output_base="${TMP}/bazel_out" \ build -c opt --config symbols \ - --define GAPID_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ - --define GAPID_BUILD_SHA="$BUILD_SHA" \ + --define AGI_BUILD_NUMBER="$KOKORO_BUILD_NUMBER" \ + --define AGI_BUILD_SHA="$BUILD_SHA" \ --strategy CppLink=local \ $@ echo $(date): Build completed. diff --git a/kokoro/macos/dmg-settings.py b/kokoro/macos/dmg-settings.py index 67c24fb1d6..0f3a3f491a 100644 --- a/kokoro/macos/dmg-settings.py +++ b/kokoro/macos/dmg-settings.py @@ -15,11 +15,11 @@ # DMG configuration for dmgbuild. format = 'UDZO' -files = [ 'GAPID.app' ] +files = [ 'AGI.app' ] symlinks = { 'Applications': '/Applications' } -badge_icon = 'GAPID.app/Contents/Resources/GAPID.icns' +badge_icon = 'AGI.app/Contents/Resources/AGI.icns' icon_locations = { - 'GAPID.app': (120, 172), + 'AGI.app': (120, 172), 'Applications': (360, 172), '.background.tiff': (1000, 1000), # hide '.VolumeIcon.icns': (1000, 1000), # hide diff --git a/kokoro/macos/package.sh b/kokoro/macos/package.sh index e5184240ca..872d07edb8 100755 --- a/kokoro/macos/package.sh +++ b/kokoro/macos/package.sh @@ -44,34 +44,31 @@ VERSION=$(awk -F= 'BEGIN {major=0; minor=0; micro=0} END {print major"."minor"."micro}' $BIN/pkg/build.properties) # Combine package contents. -mkdir -p gapid/jre -cp -r $BIN/pkg/* gapid/ -"$SRC/copy_jre.sh" gapid/jre +mkdir -p agi/jre +cp -r $BIN/pkg/* agi/ +"$SRC/copy_jre.sh" agi/jre # Create a zip file. -zip -r gapid-$VERSION-macos.zip gapid/ +zip -r agi-$VERSION-macos.zip agi/ # Create a .app package -mkdir -p GAPID.app/Contents/MacOS/ -cp -r gapid/* GAPID.app/Contents/MacOS/ -cp "$SRC/Info.plist" GAPID.app/Contents/ +mkdir -p AGI.app/Contents/MacOS/ +cp -r agi/* AGI.app/Contents/MacOS/ +cp "$SRC/Info.plist" AGI.app/Contents/ -mkdir -p GAPID.iconset GAPID.app/Contents/Resources +mkdir -p AGI.iconset AGI.app/Contents/Resources for i in 512 256 128 64 32 16; do - cp "$SRC/../../gapic/res/icons/logo_${i}.png" GAPID.iconset/icon_${i}x${i}.png - cp "$SRC/../../gapic/res/icons/logo_$((i*2)).png" GAPID.iconset/icon_${i}x${i}\@2x.png + cp "$SRC/../../gapic/res/icons/logo_${i}.png" AGI.iconset/icon_${i}x${i}.png + cp "$SRC/../../gapic/res/icons/logo_$((i*2)).png" AGI.iconset/icon_${i}x${i}\@2x.png done -iconutil -c icns -o GAPID.app/Contents/Resources/GAPID.icns GAPID.iconset - -# TODO Copy the GAPIR Symbols -# cp ../current/gapir.sym gapir-$VERSION-macos.sym +iconutil -c icns -o AGI.app/Contents/Resources/AGI.icns AGI.iconset # Make a dmg file. pip install --upgrade --user dmgbuild pyobjc-framework-Quartz cp "$SRC"/background*.png . cp "$SRC/dmg-settings.py" . # Path to dmgbuild must match where pip installs it -~/Library/Python/3.7/bin/dmgbuild -s dmg-settings.py GAPID gapid-$VERSION-macos.dmg +~/Library/Python/3.7/bin/dmgbuild -s dmg-settings.py AGI agi-$VERSION-macos.dmg # Copy the symbol file to the output. [ -f "$BIN/cmd/gapir/cc/gapir.sym" ] && cp "$BIN/cmd/gapir/cc/gapir.sym" gapir-$VERSION-macos.sym From 426f83bbd5b18b241fdfb1043f62f6c7c0965a59 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 11:19:32 -0800 Subject: [PATCH 0007/1218] Update all the Kokoro build configurations. --- kokoro/linux-test/presubmit.cfg | 2 +- kokoro/linux/common.cfg | 6 +++--- kokoro/linux/dev.cfg | 2 +- kokoro/macos/common.cfg | 6 +++--- kokoro/macos/dev.cfg | 2 +- kokoro/presubmit/common.cfg | 2 +- kokoro/windows/common.cfg | 6 +++--- kokoro/windows/dev.cfg | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/kokoro/linux-test/presubmit.cfg b/kokoro/linux-test/presubmit.cfg index cf913d9419..3a4bf28248 100644 --- a/kokoro/linux-test/presubmit.cfg +++ b/kokoro/linux-test/presubmit.cfg @@ -14,4 +14,4 @@ # Presubmit build configuration. -build_file: "gapid/kokoro/linux-test/test.sh" +build_file: "agi/kokoro/linux-test/test.sh" diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index b8ea6ea826..7b3896c142 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -build_file: "gapid/kokoro/linux/build.sh" +build_file: "agi/kokoro/linux/build.sh" action { define_artifacts { - regex: "out/dist/gapid*.deb" - regex: "out/dist/gapid*.zip" + regex: "out/dist/agi*.deb" + regex: "out/dist/agi*.zip" regex: "out/dist/gapir*.sym" strip_prefix: "out/dist" } diff --git a/kokoro/linux/dev.cfg b/kokoro/linux/dev.cfg index ffa4eecfa0..591a86d7c4 100644 --- a/kokoro/linux/dev.cfg +++ b/kokoro/linux/dev.cfg @@ -13,4 +13,4 @@ # limitations under the License. # Dev build configuration. -build_file: "gapid/kokoro/linux/build-dev.sh" +build_file: "agi/kokoro/linux/build-dev.sh" diff --git a/kokoro/macos/common.cfg b/kokoro/macos/common.cfg index 81410fa5fb..ef0e260017 100644 --- a/kokoro/macos/common.cfg +++ b/kokoro/macos/common.cfg @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -build_file: "gapid/kokoro/macos/build.sh" +build_file: "agi/kokoro/macos/build.sh" action { define_artifacts { - regex: "out/dist/gapid*.dmg" - regex: "out/dist/gapid*.zip" + regex: "out/dist/agi*.dmg" + regex: "out/dist/agi*.zip" regex: "out/dist/gapir*.sym" strip_prefix: "out/dist" } diff --git a/kokoro/macos/dev.cfg b/kokoro/macos/dev.cfg index 2148b130d3..e3754d3f7d 100644 --- a/kokoro/macos/dev.cfg +++ b/kokoro/macos/dev.cfg @@ -13,4 +13,4 @@ # limitations under the License. # Dev build configuration. -build_file: "gapid/kokoro/macos/build-dev.sh" +build_file: "agi/kokoro/macos/build-dev.sh" diff --git a/kokoro/presubmit/common.cfg b/kokoro/presubmit/common.cfg index 70c715cefe..a3936fb441 100644 --- a/kokoro/presubmit/common.cfg +++ b/kokoro/presubmit/common.cfg @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -build_file: "gapid/kokoro/presubmit/build.sh" +build_file: "agi/kokoro/presubmit/build.sh" diff --git a/kokoro/windows/common.cfg b/kokoro/windows/common.cfg index 4e9ce4782d..59a5796a1b 100644 --- a/kokoro/windows/common.cfg +++ b/kokoro/windows/common.cfg @@ -12,11 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -build_file: "gapid/kokoro/windows/build.bat" +build_file: "agi/kokoro/windows/build.bat" action { define_artifacts { - regex: "out/dist/gapid*.msi" - regex: "out/dist/gapid*.zip" + regex: "out/dist/agi*.msi" + regex: "out/dist/agi*.zip" regex: "out/dist/gapir*.sym" strip_prefix: "out/dist" } diff --git a/kokoro/windows/dev.cfg b/kokoro/windows/dev.cfg index 7441b2d0e9..b5913a921e 100644 --- a/kokoro/windows/dev.cfg +++ b/kokoro/windows/dev.cfg @@ -13,4 +13,4 @@ # limitations under the License. # Dev build configuration. -build_file: "gapid/kokoro/windows/build-dev.bat" +build_file: "agi/kokoro/windows/build-dev.bat" From 02bda1f89b8324ec00f939eea4cb6e9fe13f9836 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 28 Jan 2020 11:15:12 -0800 Subject: [PATCH 0008/1218] Update the Kokoro README file. --- kokoro/README.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/kokoro/README.md b/kokoro/README.md index 28db75e9fa..be567604fe 100644 --- a/kokoro/README.md +++ b/kokoro/README.md @@ -15,7 +15,7 @@ A `.zip` file is built containing the application, dependant DLLs and the JRE. The file structure within the `.zip` archive is: ``` -gapid\ +agi\ ├─ jre\... ├─ lib\ │ ├─ GraphicsSpyLayer.json @@ -37,23 +37,22 @@ gapid\ └─ libwinpthread-1.dll ``` -Plans are in place to also build an executable installer. The installer will -allows the user to install the package anywhere, suggesting -`%PROGRAMFILES%\gapid`. The installer will install GAPID into the selected -folder with the same structure as mentioned aboe. +An MSI installer is also built. The installer allows the user to install the +package anywhere, suggesting `%PROGRAMFILES%\agi`. The installer will install +AGI into the selected folder with the same structure as mentioned above. ## MacOS -The built package consists of a `.dmg` disk image containing the `GAPID.app` +The built package consists of a `.dmg` disk image containing the `AGI.app` application and link to `/Applications` to make "installing" easy. The -`GAPID.app` can be run from anywhere and follows the following structure: +`AGI.app` can be run from anywhere and follows the following structure: ``` -GAPID.app/ +AGI.app/ └─ Contents/ ├─ MacOS/ │ └─ - ├─ Resources/GAPID.icns + ├─ Resources/AGI.icns └─ Info.plist ``` @@ -61,7 +60,7 @@ Along with the `.dmg` disk image, a `.zip` file with the same content's as inside the `Contents/MacOS/` folder of the `.app` package is built: ``` -/ +/ ├─ jre/... ├─ lib/ │ ├─ gapic.jar @@ -77,14 +76,14 @@ inside the `Contents/MacOS/` folder of the `.app` package is built: └─ gapit ``` -When running the `.app` application, the `gapid` script is invoked. When +When running the `.app` application, the `gapid` executable is invoked. When using the `.zip` file, the only way to run the application is via the -terminal by running the `gapid` script or the executables. +terminal by running the `gapid` executable. ## Linux A Debian `.deb` package and a `.zip` file with the same contents are built. -The package installs into `/opt/gapid`, while archives can be expanded anywhere. +The package installs into `/opt/agi`, while archives can be expanded anywhere. The Debian package depends on `openjdk-8-jre` and neither it nor the `.zip` archives contain the JRE. The launcher script looks for `java` first in `$JAVA_HOME`, then on the `$PATH`, and finally the hard-coded @@ -92,7 +91,7 @@ archives contain the JRE. The launcher script looks for `java` first in package provides. The file layout is: ``` -/{opt|wherever}/gapid/ +/{opt|wherever}/agi/ ├─ lib/ │ ├─ gapic.jar │ ├─ GraphicsSpyLayer.json From db31dc2f484e6445f10ac88ddec501cf6a60807e Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 31 Jan 2020 12:42:01 -0800 Subject: [PATCH 0009/1218] Point to the AGI build badges instead of the GAPID ones. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32e79dd57a..e6952214fa 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ [![GoDoc](https://godoc.org/github.com/google/gapid?status.svg)](https://godoc.org/github.com/google/gapid) [![Gitter](https://badges.gitter.im/google/gapid.svg)](https://gitter.im/google/gapid?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Linux -[![Linux Build Status](https://gapid-build.storage.googleapis.com/badges/build_status_linux.svg)](https://gapid-build.storage.googleapis.com/badges/build_result_linux.html) +[![Linux Build Status](https://agi-build.storage.googleapis.com/badges/build_status_linux.svg)](https://agi-build.storage.googleapis.com/badges/build_result_linux.html) MacOS -[![MacOS Build Status](https://gapid-build.storage.googleapis.com/badges/build_status_macos.svg)](https://gapid-build.storage.googleapis.com/badges/build_result_macos.html) +[![MacOS Build Status](https://agi-build.storage.googleapis.com/badges/build_status_macos.svg)](https://agi-build.storage.googleapis.com/badges/build_result_macos.html) Windows -[![Windows Build Status](https://gapid-build.storage.googleapis.com/badges/build_status_windows.svg)](https://gapid-build.storage.googleapis.com/badges/build_result_windows.html) +[![Windows Build Status](https://agi-build.storage.googleapis.com/badges/build_status_windows.svg)](https://agi-build.storage.googleapis.com/badges/build_result_windows.html) ## Downloads From 2286e89cd06feb467022f3850b0b8ea929163365 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 7 Feb 2020 03:12:57 -0800 Subject: [PATCH 0010/1218] gapid.dev -> gpuinspector.dev --- README.md | 20 +++++++++---------- .../com/google/gapid/views/AboutDialog.java | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e6952214fa..00c799aab1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ## Documentation -**[User documentation can be found at gapid.dev](https://gapid.dev)** +**[User documentation can be found at gpuinspector.dev](https://gpuinspector.dev)** The [developer documentation](DEVDOC.md) contains some hints for AGI developers. See also the README files under some source directories. @@ -32,25 +32,25 @@ AGI can also trace any desktop Vulkan application.
@@ -66,7 +66,7 @@ After building AGI, you can run the client from `/bazel-bin/pkg/gapi ## Command-Line Interface -AGI exposes most of its functionality via a CLI *gapit*. You can find auto-generated documentation [here](https://gapid.dev/cli/). +AGI exposes most of its functionality via a CLI *gapit*. You can find auto-generated documentation [here](https://gpuinspector.dev/cli/). ## Project Structure diff --git a/gapic/src/main/com/google/gapid/views/AboutDialog.java b/gapic/src/main/com/google/gapid/views/AboutDialog.java index 897a761fb4..ebffbe2a87 100644 --- a/gapic/src/main/com/google/gapid/views/AboutDialog.java +++ b/gapic/src/main/com/google/gapid/views/AboutDialog.java @@ -51,7 +51,7 @@ * Dialog showing some basic info about our application. */ public class AboutDialog { - private static final String HELP_URL = "https://google.github.io/gapid"; + private static final String HELP_URL = "https://gpuinspector.dev"; private static final Logger LOG = Logger.getLogger(AboutDialog.class.getName()); private AboutDialog() { From b0f58794f8033ce9a0935ec75715cc6e5c0216f9 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 7 Feb 2020 03:27:06 -0800 Subject: [PATCH 0011/1218] More GAPID -> AGI in the readme files. --- DEVDOC.md | 16 ++++++++-------- README.md | 2 +- gapic/docs/shaders.md | 2 +- gapic/readme.md | 8 ++++---- gapii/README.md | 2 +- gapir/README.md | 2 +- gapis/README.md | 4 ++-- gapis/api/templates/README.md | 8 ++++---- gapis/api/vulkan/README.md | 2 +- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/DEVDOC.md b/DEVDOC.md index d51e720b89..50a112b5f8 100644 --- a/DEVDOC.md +++ b/DEVDOC.md @@ -41,7 +41,7 @@ should still compile under the original AGI checkout directory. In terms of editor, [VsCode](https://code.visualstudio.com/) has good Go support thanks to its [Go extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go). -With the GOPATH setup to gofuse and opening the `` directory, +With the GOPATH setup to gofuse and opening the `` directory, as the root of your workspace, you should get some jump-to-definition and autocomplete features working. Make sure to edit the files through their link found under the gofuse directory. @@ -123,13 +123,13 @@ See the workaround for VSCode below, any help to fix it for other IDEs is very w #### Integration with VSCode and Delve -To use the delve debugger for Go with VSCode to debug `gapis`. These steps can be followed: +Follow these steps to use the delve debugger for Go with VSCode to debug `gapis`. -1. Make sure to complete Golang Setup for GAPID. +1. Make sure to complete the Golang setup above for AGI. -2. Create a `launch.json` under the workspace directory with `Ctrl + Shift + P` and `Debug: Open launch.json` +2. Create a `launch.json` file under the workspace directory with `Ctrl + Shift + P` and `Debug: Open launch.json` -3. Paste this as one of the launch configurations. This will ensure that there is a launch configuration for attaching to Delve. +3. Paste the following as one of the launch configurations. This will ensure that there is a launch configuration for attaching to Delve. ``` { ... @@ -142,7 +142,7 @@ To use the delve debugger for Go with VSCode to debug `gapis`. These steps can b "mode": "remote", "apiVersion": 2, "remotePath": "gapis/", - "cwd": "${workspaceFolder}/src/github.com/google/gapid/gapis", + "cwd": "${workspaceFolder}/src/github.com/google/agi/gapis", "dlvLoadConfig": { "followPointers": true, "maxVariableRecurse": 1, @@ -159,7 +159,7 @@ To use the delve debugger for Go with VSCode to debug `gapis`. These steps can b ``` As an example, `` could be `127.0.0.1` and `` could be `1234`. -4. Start delve in headless mode at gapid check-in folder. +4. Start delve in headless mode in the AGI root folder. ``` dlv exec --headless --listen=: --api-version 2 ./bazel-bin/pkg/gapis -- ``` @@ -171,7 +171,7 @@ dlv exec --headless --listen=127.0.0.1:1234 --api-version 2 ./bazel-bin/pkg/gapi 5. Start debugging with `Debug->Start Debugging` (on Linux with `F5`) and make sure `Attach to Delve` is selected as the launch configuration. -6. Now VSCode can interact with Delve and can be used for debugging `gapis` in VSCode UI instead of command line. Enjoy your debugging :) +6. Now VSCode can interact with Delve and can be used for debugging `gapis` in VSCode UI instead of the command line. Enjoy your debugging :) ## How to debug via printing message diff --git a/README.md b/README.md index 00c799aab1..a8e6625bb5 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ AGI can also trace any desktop Vulkan application. ## Running the client -After building AGI, you can run the client from `/bazel-bin/pkg/gapid`. +After building AGI, you can run the client from `/bazel-bin/pkg/gapid`. ## Command-Line Interface diff --git a/gapic/docs/shaders.md b/gapic/docs/shaders.md index b0d020ad73..c7afb19d1b 100644 --- a/gapic/docs/shaders.md +++ b/gapic/docs/shaders.md @@ -6,7 +6,7 @@ the same file. Special "comment markers" are used to indicate which shader the following lines of code belong to. These program files are stored in the -[shader resource](https://github.com/google/gapid/tree/master/gapic/res/shaders) +[shader resource](https://github.com/google/agi/tree/master/gapic/res/shaders) directory in files ending with the ```.glsl``` extension. The name of the file is used as the identifier of the shader program. diff --git a/gapic/readme.md b/gapic/readme.md index cabf4a7bcd..afe886000e 100644 --- a/gapic/readme.md +++ b/gapic/readme.md @@ -1,4 +1,4 @@ -## Setting up Eclipse to build GAPIC +## Setting up Eclipse to build the AGI UI 1. Create the `bazel-external` link: 1. `ln -s $(bazel info output_base)/external bazel-external` @@ -6,16 +6,16 @@ 3. Open the Eclipse Preferences and navigate to **General** -> **Workspace** -> **Linked Resources**. 4. Click **New...** to define a new path variable: 1. Set the name to `GAPIC_PLATFORM_SRC`. - 2. Set the value to the your platform's folder inside the gapic/src/platform folder of the gapid checkout. + 2. Set the value to the your platform's folder inside the gapic/src/platform folder of the AGI checkout. e.g. `/gapic/src/platform/linux` 3. Click **OK** to create the variable. 5. Click **OK** to dismiss the preferences dialog. 6. Run the bazel build to build all the generated code. 7. Select **File** -> **Import** and then **General** -> **Existing Project into Workspace** and click **Next**. - 1. Enter the location of your gapid checkout into the root directory box. + 1. Enter the location of your AGI checkout into the root directory box. 2. Click **Select All**. You should see a project named gapic. 3. **IMPORTANT**: Uncheck **Copy projects into workspace** 4. Click "Finish". 8. Set up Run Configurations. - 1. In Arguments tab: give the --gapid flag. E.g.: `--gapid /bazel-bin/pkg`, replace `` with your local project path. + 1. In Arguments tab: give the --gapid flag. E.g.: `--gapid /bazel-bin/pkg`, replace `` with your local project path. 2. In Dependencies tab: add the lwjgl native jars. Find and add `/gapic/bazel-external/org_lwjgl_core_natives_linux/jar/lwjgl-3.2.0.jar`, `/gapic/bazel-external/org_lwjgl_opengl_natives_linux/jar/lwjgl-opengl-3.2.0.jar`. Folder name and jar name may vary based on your operating system. diff --git a/gapii/README.md b/gapii/README.md index 0232612b6b..bcbd3e8fcc 100644 --- a/gapii/README.md +++ b/gapii/README.md @@ -1,6 +1,6 @@ # Graphics API Interceptor (GAPII) -The Graphics API Interceptor is the GAPID component responsible for intercepting and capturing all commands issued by an application to the graphics driver. +The Graphics API Interceptor is the AGI component responsible for intercepting and capturing all commands issued by an application to the graphics driver. GAPII can be packaged as a dynamically-loaded library (`.so`, `.dll`) or as an archive linked into the application at build time (`.a`, `.lib`). diff --git a/gapir/README.md b/gapir/README.md index 98dfaf2ee4..e995959d37 100644 --- a/gapir/README.md +++ b/gapir/README.md @@ -53,7 +53,7 @@ accessed. ## Data types -The GAPID virtual-machine supports the following primitive data types: +The AGI virtual-machine supports the following primitive data types: Type | Description --------------- | ---------------------------------------------------- diff --git a/gapis/README.md b/gapis/README.md index ad98add1ec..28bbda0964 100644 --- a/gapis/README.md +++ b/gapis/README.md @@ -1,6 +1,6 @@ # Graphics API Server (GAPIS) -The Graphics API Server is the central component of the GAPID tool suite, providing the interface between the client and the replay systems. +The Graphics API Server is the central component of the AGI tool suite, providing the interface between the client and the replay systems. GAPIS has been designed to support multiple graphics APIs. The client does not need to have any knowledge of any graphics APIs, making implementing new clients relatively trivial. @@ -131,7 +131,7 @@ Again, most of this logic is handled by `Builder` ### Compatibility -One of GAPID's core goals is to support replays on targets different to those used to create the capture. For example, we may want to capture an OpenGL ES 2.0 application, and replay the capture using a desktop OpenGL 4.0 context. +One of AGI's core goals is to support replays on targets different to those used to create the capture. For example, we may want to capture an OpenGL ES 2.0 application, and replay the capture using a desktop OpenGL 4.0 context. OpenGL has the concept of core and compatibility profiles - as functions are marked as deprecated between OpenGL versions, the compatibility profile will still permit the deprecated functionality, the core profile will error. Most drivers and devices will offer compatibility profiles, but certain targets, including macOS, only supports core profiles for OpenGL 3+. diff --git a/gapis/api/templates/README.md b/gapis/api/templates/README.md index bbded63f5a..03e67b278a 100644 --- a/gapis/api/templates/README.md +++ b/gapis/api/templates/README.md @@ -1,10 +1,10 @@ # Templates -GAPID uses the golang [template] package with its API file parser/compiler to generate Go, C++ and Java code. +AGI uses the golang [template] package with its API file parser/compiler to generate Go, C++ and Java code. The .api files are parsed, and a `.tmpl` file is used to generate one or more output files using the `apic` tool. -GAPID's template system exposes a few extensions to the standard golang template system: +AGI's template system exposes a few extensions to the standard golang template system: ## Macros @@ -50,7 +50,7 @@ being the faster option: ## File macros -GAPID also adds support for emitting multiple files from a single `.tmpl` source using the `file` function. +AGI also adds support for emitting multiple files from a single `.tmpl` source using the `file` function. `file` is identical to `Macro`, but it takes one additional argument for the output file name: ```go @@ -63,7 +63,7 @@ will adopt the same extension. ## Special symbols -To try and help with the formatting of the generated output, GAPID's templates support a number of custom unicode symbols: +To try and help with the formatting of the generated output, AGI's templates support a number of custom unicode symbols: ### `»` Begin indentation of a block diff --git a/gapis/api/vulkan/README.md b/gapis/api/vulkan/README.md index 36724eb5a2..c634b3c9e4 100644 --- a/gapis/api/vulkan/README.md +++ b/gapis/api/vulkan/README.md @@ -37,7 +37,7 @@ a list of the commands that are run during that submission. From there you can query information about any call in the program. ## Performance -We are still tuning performance for Vulkan in GAPID. For Posix based platforms +We are still tuning performance for Vulkan in AGI. For Posix based platforms we handle persistently mapped coherent memory efficiently, but for Windows this is currently in progress. Large blocks of mapped coherent memory can greatly reduce replay performance and increase trace size. From ae2ab9bf14b047a9deb07cd5d36f5912b713f33d Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 7 Feb 2020 03:27:20 -0800 Subject: [PATCH 0012/1218] Use AGI in the strings file. --- gapis/messages/en-us.stb.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gapis/messages/en-us.stb.md b/gapis/messages/en-us.stb.md index 14e6817c57..92cc179832 100644 --- a/gapis/messages/en-us.stb.md +++ b/gapis/messages/en-us.stb.md @@ -221,8 +221,8 @@ The file cannot be read. # ERR_FILE_TOO_NEW -The file was created by a more recent version of GAPID and cannot be read. +The file was created by a more recent version of AGI and cannot be read. # ERR_FILE_TOO_OLD -The file was created by an old version of GAPID and cannot be read. +The file was created by an old version of AGI and cannot be read. From 074402da1c19e6264df2a7b09727da06a49c32f2 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 7 Feb 2020 03:47:43 -0800 Subject: [PATCH 0013/1218] Use .agic instead of .gapic for the settings file. --- gapic/src/main/com/google/gapid/models/Settings.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gapic/src/main/com/google/gapid/models/Settings.java b/gapic/src/main/com/google/gapid/models/Settings.java index db620b3bc9..3888b3e845 100644 --- a/gapic/src/main/com/google/gapid/models/Settings.java +++ b/gapic/src/main/com/google/gapid/models/Settings.java @@ -51,13 +51,13 @@ /** * Stores various settings based on user interactions with the UI to maintain customized looks and * other shortcuts between runs. E.g. size and location of the window, directory of the last opened - * file, options for the last trace, etc. The settings are persisted in a ".gapic" file in the + * file, options for the last trace, etc. The settings are persisted in a ".agic" file in the * user's home directory. */ public class Settings { private static final Logger LOG = Logger.getLogger(Settings.class.getName()); - private static final String SETTINGS_FILE = ".gapic"; + private static final String SETTINGS_FILE = ".agic"; private static final int MAX_RECENT_FILES = 16; private static final int CURRENT_VERSION = 1; From 9e7b05b1e94f154b737a62dcfefada3b26750492 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 7 Feb 2020 09:54:21 -0800 Subject: [PATCH 0014/1218] Change some strings in the UI to use AGI. --- .../src/main/com/google/gapid/util/Messages.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gapic/src/main/com/google/gapid/util/Messages.java b/gapic/src/main/com/google/gapid/util/Messages.java index 6e2434e2f3..a5cc9dba12 100644 --- a/gapic/src/main/com/google/gapid/util/Messages.java +++ b/gapic/src/main/com/google/gapid/util/Messages.java @@ -18,7 +18,7 @@ import static com.google.gapid.util.GapidVersion.GAPID_VERSION; public interface Messages { - public static final String WINDOW_TITLE = "Graphics API Debugger"; + public static final String WINDOW_TITLE = "Android GPU Inspector"; public static final String LOADING_CAPTURE = "Loading capture..."; public static final String CAPTURE_LOAD_FAILURE = "Failed to load capture."; public static final String NO_FRAMES_IN_CONTEXT = "No frames in selected context."; @@ -55,15 +55,16 @@ public interface Messages { public static final String SELECT_ACTIVITY = "Select an Application to Trace"; public static final String WELCOME_TITLE = WINDOW_TITLE + " - Welcome"; public static final String WELCOME_SUBTITLE = "Get started with " + WINDOW_TITLE; - public static final String WELCOME_TEXT = "GAPID allows you to inspect, tweak, and replay calls" + + public static final String WELCOME_TEXT = "AGI allows you to inspect, tweak, and replay calls" + " from an application to a\ngraphics API. To begin, let us know where adb is located on" + " your computer."; public static final String WELCOME_BUTTON = "Get Started"; public static final String ANALYTICS_OPTION = - "Help improve GAPID by sending usage statistics to Google"; + "Help improve Android GPU Inspector by sending usage statistics to Google"; public static final String CRASH_REPORTING_OPTION = - "Help GAPID identify issues by sending crash reports to Google"; - public static final String UPDATE_CHECK_OPTION = "Automatically check for GAPID updates (please restart GAPID to force an update check)"; + "Help Android GPU Inspector identify issues by sending crash reports to Google"; + public static final String UPDATE_CHECK_OPTION = "Automatically check for AGI updates " + + "(please restart AGI to force an update check)"; public static final String UPDATE_CHECK_DEV_RELEASE_OPTION = "Include unstable developer releases"; public static final String PRIVACY_POLICY = "Google's APIs Terms of Service and Privacy Policy" + @@ -73,7 +74,7 @@ public interface Messages { public static final String ERROR_MESSAGE = "The application encountered an error:\n%s\n\nPlease check the logs for details."; public static final String BUG_BODY = - "GAPID Version: " + GAPID_VERSION.toString() + "\n" + + "AGI Version: " + GAPID_VERSION.toString() + "\n" + "OS: " + OS.name + " " + OS.arch + "\n\n" + "Please provide detailed steps that led to the error and copy-paste the stack trace.\n" + "Extra details from the logs and the trace file would be extra helpful.\n\n"; @@ -81,6 +82,6 @@ public interface Messages { "Failed to create an OpenGL context. OpenGL is required to use this application."; public static final String GEO_SEMANTICS_TITLE = "Vertex Semantics"; public static final String GEO_SEMANTICS_HINT = "Manually configure the vertex stream semantics:"; - public static final String QUERY_VIEW_WINDOW_TITLE = "GAPID - Query Shell"; + public static final String QUERY_VIEW_WINDOW_TITLE = "AGI - Query Shell"; public static final String KEYBOARD_MOUSE_HELP_TITLE = "Keyboard/Mouse Shortcut Help"; } From ba24464382ba930677f06cd34c5b2912e39f5285 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Mon, 10 Feb 2020 18:24:55 +0000 Subject: [PATCH 0015/1218] Name all read-me files README.md (#13) --- core/data/pack/{README.MD => README.md} | 0 gapic/{readme.md => README.md} | 2 +- .../shadertools/cc/{README.txt => README.md} | 29 ++++++++++++------- 3 files changed, 19 insertions(+), 12 deletions(-) rename core/data/pack/{README.MD => README.md} (100%) rename gapic/{readme.md => README.md} (90%) rename gapis/shadertools/cc/{README.txt => README.md} (74%) diff --git a/core/data/pack/README.MD b/core/data/pack/README.md similarity index 100% rename from core/data/pack/README.MD rename to core/data/pack/README.md diff --git a/gapic/readme.md b/gapic/README.md similarity index 90% rename from gapic/readme.md rename to gapic/README.md index afe886000e..71bd7e1d6f 100644 --- a/gapic/readme.md +++ b/gapic/README.md @@ -17,5 +17,5 @@ 3. **IMPORTANT**: Uncheck **Copy projects into workspace** 4. Click "Finish". 8. Set up Run Configurations. - 1. In Arguments tab: give the --gapid flag. E.g.: `--gapid /bazel-bin/pkg`, replace `` with your local project path. + 1. In Arguments tab: give the `--gapid` flag. E.g.: `--gapid /bazel-bin/pkg`, replace `` with your local project path. 2. In Dependencies tab: add the lwjgl native jars. Find and add `/gapic/bazel-external/org_lwjgl_core_natives_linux/jar/lwjgl-3.2.0.jar`, `/gapic/bazel-external/org_lwjgl_opengl_natives_linux/jar/lwjgl-opengl-3.2.0.jar`. Folder name and jar name may vary based on your operating system. diff --git a/gapis/shadertools/cc/README.txt b/gapis/shadertools/cc/README.md similarity index 74% rename from gapis/shadertools/cc/README.txt rename to gapis/shadertools/cc/README.md index cd331da55a..841cf82cff 100644 --- a/gapis/shadertools/cc/README.txt +++ b/gapis/shadertools/cc/README.md @@ -1,3 +1,5 @@ +# Shadertools, libmanager + /** * Karolina Gawryszczak * 18.10.2016 @@ -5,6 +7,7 @@ Library libmanager provides 2 function: +``` -> code_with_debug_info_t* convertGlsl(const char*, size_t, options_t*); 1. compiles GLSL source code in ES version to spirv code (using glslang tool) 2. makes some changes in compiled spirv code (using my class SpvManager; those changes depend on provided options). @@ -12,8 +15,11 @@ Library libmanager provides 2 function: 4. again, compiles source code in desktop version (again, using glslang tool) -> void deleteGlslCodeWithDebug(code_with_debug_info_t*); +``` Options: + +``` typedef struct options_t { bool is_fragment_shader; bool is_vertex_shader; @@ -31,21 +37,22 @@ Options: bool disassemble; /* Return disassemble code after all changes. */ } options_t; +``` Usage: - Simple library usage is shown in main.cpp program. - ./main - - -Tests: - - script tests/run_tests.py - - script takes one argument 'step', which is a number. - Variable 'width' means how many files you want to test. - Files from (step * width) to ((step + 1) * width) will be tested. - - Creates output files in test/shaders/ directory. - Output file name: .out3 +Simple library usage is shown in main.cpp program. +``` +./main ` +``` +Tests: +- script tests/run_tests.py + - script takes one argument 'step', which is a number. + Variable 'width' means how many files you want to test. + Files from (step * width) to ((step + 1) * width) will be tested. + - Creates output files in test/shaders/ directory. + Output file name: .out3 From e33cd1dd5d02628ae1fae932800865ec1a1fb1a1 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 06:46:16 -0800 Subject: [PATCH 0016/1218] Renames the main launcher from gapid to agi. git mv cmd/gapid cmd/agi --- BUILD.bazel | 6 +++--- cmd/{gapid => agi}/BUILD.bazel | 4 ++-- cmd/{gapid => agi}/console_other.go | 0 cmd/{gapid => agi}/console_windows.go | 0 cmd/{gapid => agi}/main.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename cmd/{gapid => agi}/BUILD.bazel (94%) rename cmd/{gapid => agi}/console_other.go (100%) rename cmd/{gapid => agi}/console_windows.go (100%) rename cmd/{gapid => agi}/main.go (98%) diff --git a/BUILD.bazel b/BUILD.bazel index 273078a555..46b9993d01 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -41,8 +41,8 @@ gazelle( # Alias meant to be used with 'bazel run -- '. alias( - name = "gapid", - actual = "//cmd/gapid", + name = "agi", + actual = "//cmd/agi", ) alias( @@ -161,7 +161,7 @@ copy_tree( copy_to( name = "pkg-root", srcs = [ - "//cmd/gapid", + "//cmd/agi", "//cmd/gapir/cc:gapir", "//cmd/gapis", "//cmd/gapit", diff --git a/cmd/gapid/BUILD.bazel b/cmd/agi/BUILD.bazel similarity index 94% rename from cmd/gapid/BUILD.bazel rename to cmd/agi/BUILD.bazel index 4c483927bc..bd80411f02 100644 --- a/cmd/gapid/BUILD.bazel +++ b/cmd/agi/BUILD.bazel @@ -21,13 +21,13 @@ go_library( "console_windows.go", "main.go", ], - importpath = "github.com/google/gapid/cmd/gapid", + importpath = "github.com/google/gapid/cmd/agi", visibility = ["//visibility:private"], ) # BUG: This isn't go_stripped_binary due to issue #1753. go_binary( - name = "gapid", + name = "agi", args = [ "--jar", "$(location //gapic:gapic_deploy.jar)", diff --git a/cmd/gapid/console_other.go b/cmd/agi/console_other.go similarity index 100% rename from cmd/gapid/console_other.go rename to cmd/agi/console_other.go diff --git a/cmd/gapid/console_windows.go b/cmd/agi/console_windows.go similarity index 100% rename from cmd/gapid/console_windows.go rename to cmd/agi/console_windows.go diff --git a/cmd/gapid/main.go b/cmd/agi/main.go similarity index 98% rename from cmd/gapid/main.go rename to cmd/agi/main.go index cd57a6f5a5..cfcfe3257b 100644 --- a/cmd/gapid/main.go +++ b/cmd/agi/main.go @@ -71,7 +71,7 @@ func run() int { fmt.Println(" --jar Path to the gapic JAR to use") fmt.Println(" --vm Path to the JVM to use") fmt.Println(" --vmarg Extra argument for the JVM (repeatable)") - fmt.Println(" --console Run GAPID inside a terminal console") + fmt.Println(" --console Run AGI inside a terminal console") fmt.Println(" --verbose-startup Log verbosely in the launcher") }() } From 917afdb297d4c8f38db118eb23962bbdda8cf79e Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 06:48:14 -0800 Subject: [PATCH 0017/1218] Remove the gapit dependency from //cmd/agi. The UI no longer uses gapit for anything. --- cmd/agi/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/agi/BUILD.bazel b/cmd/agi/BUILD.bazel index bd80411f02..96c262e599 100644 --- a/cmd/agi/BUILD.bazel +++ b/cmd/agi/BUILD.bazel @@ -34,7 +34,6 @@ go_binary( ], data = [ "//cmd/gapis", - "//cmd/gapit", "//gapic:gapic_deploy.jar", "//gapis/messages:stb", ], From a33168e00b3713d3b2054bc6c74b13026e9474e3 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:09:20 -0800 Subject: [PATCH 0018/1218] Look for the agi runfiles manifest, rather than gapid. --- gapic/src/main/com/google/gapid/server/GapiPaths.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/server/GapiPaths.java b/gapic/src/main/com/google/gapid/server/GapiPaths.java index 94645b23fb..2342fe85ba 100644 --- a/gapic/src/main/com/google/gapid/server/GapiPaths.java +++ b/gapic/src/main/com/google/gapid/server/GapiPaths.java @@ -52,7 +52,7 @@ public final class GapiPaths { private static final String USER_HOME_GAPID_ROOT = "gapid"; private static final String GAPID_PKG_SUBDIR = "pkg"; private static final String GAPID_ROOT_ENV_VAR = "GAPID"; - private static final String RUNFILES_MANIFEST = "gapid.runfiles_manifest"; + private static final String RUNFILES_MANIFEST = "agi.runfiles_manifest"; private static GapiPaths tools; From 23a0dc9465ee339b38ef436731ad00548e9f4f48 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:14:20 -0800 Subject: [PATCH 0019/1218] Fix the Linux packaging scripts to match the new launcher. --- kokoro/linux/gapid.desktop | 2 +- kokoro/linux/gapid.menu | 2 +- kokoro/linux/package.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kokoro/linux/gapid.desktop b/kokoro/linux/gapid.desktop index e4ae181f39..9cff18e2cd 100644 --- a/kokoro/linux/gapid.desktop +++ b/kokoro/linux/gapid.desktop @@ -5,6 +5,6 @@ Name=Android GPU Inspector Comment=Android GPU Inspector Categories=Development;Debugger;Graphics;3DGraphics Icon=/opt/agi/icon.png -Exec=/opt/agi/gapid %f +Exec=/opt/agi/agi %f Terminal=false MimeType=application/x-gfxtrace diff --git a/kokoro/linux/gapid.menu b/kokoro/linux/gapid.menu index 5fafeb4588..adcceac7c5 100644 --- a/kokoro/linux/gapid.menu +++ b/kokoro/linux/gapid.menu @@ -1,3 +1,3 @@ ?package(agi):needs="X11" section="Applications/Programming"\ - title="AGI" longtitle="Android GPU Inspector" command="/opt/agi/gapid"\ + title="AGI" longtitle="Android GPU Inspector" command="/opt/agi/agi"\ icon="/opt/agi/icon.png" diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh index 06dea6faff..c9cde4f619 100755 --- a/kokoro/linux/package.sh +++ b/kokoro/linux/package.sh @@ -71,7 +71,7 @@ EOF # Fix up permissions (root ownership is faked below). find agi/ -type f -exec chmod 644 {} + -chmod 755 agi/opt/agi/gapi[drst] agi/opt/agi/device-info +chmod 755 agi/opt/agi/agi agi/opt/agi/gapi[rst] agi/opt/agi/device-info find agi/ -type d -exec chmod 755 {} + find agi/ -type d -exec chmod g-s {} + From 4baca05ca08bd19ce300956fe83be0b9d3c1126c Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:17:21 -0800 Subject: [PATCH 0020/1218] Fix the Windows packaging scripts to match the new launcher. --- kokoro/windows/gapid.wxs | 10 +++++----- kokoro/windows/package.bat | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kokoro/windows/gapid.wxs b/kokoro/windows/gapid.wxs index d0e44710eb..0f4c708ae9 100644 --- a/kokoro/windows/gapid.wxs +++ b/kokoro/windows/gapid.wxs @@ -47,7 +47,7 @@ + Target="[!agi.exe]" WorkingDirectory="APPLICATIONROOTDIRECTORY" Icon="agi.ico" /> @@ -65,16 +65,16 @@ - + - + - + - + diff --git a/kokoro/windows/package.bat b/kokoro/windows/package.bat index 81354c8e0f..ec1d21b4a7 100644 --- a/kokoro/windows/package.bat +++ b/kokoro/windows/package.bat @@ -40,7 +40,7 @@ if exist "%BUILD_OUT%\dist" ( rmdir /Q /S "%BUILD_OUT%\dist" ) -mkdir "%BUILD_OUT%\dist\gapid" +mkdir "%BUILD_OUT%\dist\agi" pushd "%BUILD_OUT%\dist" awk -F= 'BEGIN {major=0; minor=0; micro=0}^ From f3c4dc1a74f995f986d321f88427b31a6c261688 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:19:02 -0800 Subject: [PATCH 0021/1218] Fix the MacOS packaging scripts to match the new launcher. --- kokoro/macos/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/macos/Info.plist b/kokoro/macos/Info.plist index 6332cfc46f..7066d10ed6 100644 --- a/kokoro/macos/Info.plist +++ b/kokoro/macos/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion English CFBundleExecutable - gapid + agi CFBundleIconFile AGI.icns CFBundlePackageType From c3fda36fef9d074a684ee984145f24e8303646ce Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:09:46 -0800 Subject: [PATCH 0022/1218] Create Pipeline Strip in Pipeline View (#16) Also handles hovering and arrows over disabled stages Use stack layout in Pipeline View --- .../com/google/gapid/views/PipelineView.java | 445 +++++++++++------- 1 file changed, 283 insertions(+), 162 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index 08ad4869ea..95d1fe5b6b 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -15,6 +15,7 @@ */ package com.google.gapid.views; +import static com.google.gapid.util.Colors.lerp; import static com.google.gapid.util.Loadable.MessageType.Error; import static com.google.gapid.util.Loadable.MessageType.Info; import static com.google.gapid.util.Logging.throttleLogRpcError; @@ -62,20 +63,26 @@ import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Button; import java.util.ArrayList; import java.util.List; +import java.util.HashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; @@ -90,6 +97,10 @@ public class PipelineView extends Composite protected final LoadablePanel loading; protected final Theme theme; protected final Composite stagesContainer; + protected final Color hoverColor; + + protected String selectedStage = null; + protected Button hoveredButton = null; public PipelineView(Composite parent, Models models, Widgets widgets) { super(parent, SWT.NONE); @@ -101,12 +112,17 @@ public PipelineView(Composite parent, Models models, Widgets widgets) { loading = LoadablePanel.create(this, widgets, panel -> createComposite(panel, new FillLayout(SWT.VERTICAL))); - stagesContainer = createComposite(loading.getContents(), new FillLayout()); + stagesContainer = createComposite(loading.getContents(), new GridLayout(1, false)); + + RGB selectRGB = getDisplay().getSystemColor(SWT.COLOR_BLUE).getRGB(); + RGB unselectRGB = getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(); + hoverColor = new Color(getDisplay(), lerp(selectRGB, unselectRGB, 0.5f)); models.capture.addListener(this); models.commands.addListener(this); models.resources.addListener(this); addListener(SWT.Dispose, e -> { + hoverColor.dispose(); models.capture.removeListener(this); models.commands.removeListener(this); models.resources.removeListener(this); @@ -184,202 +200,297 @@ protected void onUiThreadError(Loadable.Message error) { protected void setPipelines(List pipelines) { loading.stopLoading(); disposeAllChildren(stagesContainer); - TabFolder folder = createStandardTabFolder(stagesContainer); - createPipelineTabs(folder, pipelines); + createPipelineTabs(stagesContainer, pipelines); stagesContainer.requestLayout(); } - private void createPipelineTabs(TabFolder folder, List pipelines) { + private void createPipelineTabs(Composite folder, List pipelines) { + HashMap stageMap = new HashMap(); + if (!pipelines.isEmpty()) { - for (API.Pipeline result : pipelines) { - List stages = result.getStagesList(); + RowLayout stripLayout = new RowLayout(); + stripLayout.fill = true; + stripLayout.spacing = 0; + stripLayout.wrap = true; + Composite stripComposite = withLayoutData( createComposite(folder, stripLayout), + new GridData(SWT.FILL, SWT.TOP, true, false)); + Label separator = withLayoutData( new Label(folder, SWT.SEPARATOR | SWT.HORIZONTAL), + new GridData(SWT.FILL, SWT.TOP, true, false)); + + StackLayout stageStack = new StackLayout(); + Composite stageComposite = withLayoutData( createComposite(folder, stageStack), + new GridData(SWT.FILL, SWT.FILL, true, true)); + + for (int pipeIndex = 0; pipeIndex < pipelines.size(); pipeIndex++) { + List stages = pipelines.get(pipeIndex).getStagesList(); + + for (int stageIndex = 0; stageIndex < stages.size(); stageIndex++) { + API.Stage stage = stages.get(stageIndex); + Button stageButton = new Button(stripComposite, SWT.FLAT); + stageMap.put(stage.getDebugName(), new StageUI(stageButton, createStage(stageComposite, stage))); + + stageButton.setText(stage.getDebugName()); + stageButton.addListener(SWT.Selection, e -> { + stageStack.topControl = stageMap.get(stage.getDebugName()).stageComposite; + stageComposite.layout(); + StageUI stageUI = stageMap.get(selectedStage); + if (stageUI != null) { + stageUI.stageButton.redraw(); + } + selectedStage = stage.getDebugName(); + stageButton.redraw(); + }); - for (API.Stage stage : stages) { - TabItem item = createStandardTabItem(folder, stage.getDebugName()); + stageButton.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + stageButton.setFont(theme.bigBoldFont()); + stageButton.setToolTipText(stage.getStageName()); - Composite stageGroup = createComposite(folder, new GridLayout()); + if (!stage.getEnabled()) { + stageButton.setEnabled(false); + stageButton.addListener(SWT.Paint, e -> { + Rectangle areaSize = stageButton.getBounds(); + e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); + e.gc.setLineWidth((int)(areaSize.height * 0.1)); + e.gc.drawLine(0, areaSize.height / 2, areaSize.width, areaSize.height / 2); + }); + } else { + stageButton.addListener(SWT.Paint, e -> { + Rectangle areaSize = stageButton.getBounds(); + e.gc.setLineWidth((int)(areaSize.height * 0.1)); + + if (hoveredButton == stageButton || stageMap.get(selectedStage).stageButton == stageButton) { + e.gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLUE)); + } else { + e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); + } + e.gc.drawPolygon(new int[] {0, 0, areaSize.width - 1, 0, areaSize.width - 1, areaSize.height - 1, 0, areaSize.height - 1}); + }); + + stageButton.addListener(SWT.MouseEnter, e -> { + hoveredButton = stageButton; + stageButton.setBackground(hoverColor); + }); + + stageButton.addListener(SWT.MouseExit, e -> { + hoveredButton = null; + stageButton.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + }); + } - FillLayout nameLayout = new FillLayout(SWT.VERTICAL); - nameLayout.marginHeight = 5; - Composite nameComposite = withLayoutData( createComposite(stageGroup, nameLayout), - new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); + if (stageIndex != stages.size()-1) { + Label arrowSpace = new Label(stripComposite, SWT.FILL); + arrowSpace.setText(" "); + arrowSpace.setFont(theme.bigBoldFont()); + API.Stage nextStage = stages.get(stageIndex+1); + + arrowSpace.addListener(SWT.Paint, e -> { + Rectangle areaSize = arrowSpace.getBounds(); + int lineLength = (int)(areaSize.width * 0.8); + int triangleBaseLength = (int)(areaSize.height * 0.2); + + e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); + e.gc.setLineWidth((int)(areaSize.height * 0.1)); + e.gc.drawLine(0, areaSize.height / 2, lineLength, areaSize.height / 2); + + if (nextStage.getEnabled()) { + e.gc.fillPolygon(new int[] {lineLength, areaSize.height / 2 + triangleBaseLength, areaSize.width, areaSize.height / 2, lineLength, areaSize.height / 2 - triangleBaseLength}); + } else { + e.gc.drawLine(lineLength, areaSize.height / 2, areaSize.width, areaSize.height / 2); + } + }); + } + } - Label stageName = createLabel(nameComposite, stage.getStageName() + " (" + stage.getDebugName() + ")"); - stageName.setFont(theme.bigBoldFont()); + if (pipeIndex != pipelines.size()-1) { + Label pipeSeparator = new Label(stripComposite, SWT.FILL); + pipeSeparator.setText(" "); + pipeSeparator.setFont(theme.bigBoldFont()); + } - item.setControl(stageGroup); + if (selectedStage == null || stageMap.get(selectedStage) == null) { + selectedStage = pipelines.get(0).getStagesList().get(0).getDebugName(); + } - if (!stage.getEnabled()) { - continue; - } + stageStack.topControl = stageMap.get(selectedStage).stageComposite; + } + } + } - FillLayout dataLayout = new FillLayout(SWT.VERTICAL); - dataLayout.spacing = 5; - Composite dataComposite = withLayoutData( createComposite(stageGroup, dataLayout), + private Composite createStage(Composite parent, API.Stage currentStage) { + Composite stageGroup = createComposite(parent, new GridLayout()); + FillLayout nameLayout = new FillLayout(SWT.VERTICAL); + nameLayout.marginHeight = 5; + Composite nameComposite = withLayoutData( createComposite(stageGroup, nameLayout), + new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); + + Label stageName = createLabel(nameComposite, currentStage.getStageName() + " (" + currentStage.getDebugName() + ")"); + stageName.setFont(theme.bigBoldFont()); + + FillLayout dataLayout = new FillLayout(SWT.VERTICAL); + dataLayout.spacing = 5; + Composite dataComposite = withLayoutData( createComposite(stageGroup, dataLayout), + new GridData(SWT.FILL, SWT.FILL, true, true)); + + for (API.DataGroup dataGroup : currentStage.getGroupsList()) { + Group dataGroupComposite = createGroup(dataComposite, dataGroup.getGroupName()); + dataGroupComposite.setFont(theme.subTitleFont()); + + switch (dataGroup.getDataCase()) { + case KEY_VALUES: + dataGroupComposite.setLayout(new GridLayout(1, false)); + ScrolledComposite scrollComposite = withLayoutData( createScrolledComposite(dataGroupComposite, + new FillLayout(), SWT.V_SCROLL | SWT.H_SCROLL), new GridData(SWT.FILL, SWT.FILL, true, true)); - for (API.DataGroup dataGroup : stage.getGroupsList()) { - Group dataGroupComposite = createGroup(dataComposite, dataGroup.getGroupName()); - dataGroupComposite.setFont(theme.subTitleFont()); - - switch (dataGroup.getDataCase()) { - case KEY_VALUES: - dataGroupComposite.setLayout(new GridLayout(1, false)); - ScrolledComposite scrollComposite = withLayoutData( createScrolledComposite(dataGroupComposite, - new FillLayout(), SWT.V_SCROLL | SWT.H_SCROLL), - new GridData(SWT.FILL, SWT.FILL, true, true)); - - GridLayout gridLayout = new GridLayout(2, false); - gridLayout.marginWidth = 5; - gridLayout.marginHeight = 5; - gridLayout.horizontalSpacing = -1; - gridLayout.verticalSpacing = -1; - Composite contentComposite = createComposite(scrollComposite, gridLayout); - - List kvpList = dataGroup.getKeyValues().getKeyValuesList(); - - boolean dynamicExists = false; - - for (API.KeyValuePair kvp : kvpList) { - GridLayout kvpLayout = new GridLayout(1, false); - kvpLayout.marginHeight = 5; - kvpLayout.marginWidth = 5; - Composite keyComposite = withLayoutData( createComposite(contentComposite, kvpLayout, SWT.BORDER), - new GridData(SWT.FILL, SWT.TOP, false, false)); - - withLayoutData( createBoldLabel(keyComposite, kvp.getName() + (kvp.getDynamic() ? "*:" : ":")), - new GridData(SWT.RIGHT, SWT.CENTER, true, true)); - - if (!dynamicExists && kvp.getDynamic()) { - dataGroupComposite.setText(dataGroup.getGroupName() + " (* value set dynamically)"); - dynamicExists = true; - } - - Composite valueComposite = withLayoutData( createComposite(contentComposite, kvpLayout, SWT.BORDER), - new GridData(SWT.FILL, SWT.TOP, false, false)); - - DataValue dv = convertDataValue(kvp.getValue()); - if (dv.link != null) { - withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> models.follower.onFollow(dv.link)), - new GridData(SWT.LEFT, SWT.CENTER, true, true)); - } else { - withLayoutData( createLabel(valueComposite, dv.displayValue), - new GridData(SWT.LEFT, SWT.CENTER, true, true)); - } - } + GridLayout gridLayout = new GridLayout(2, false); + gridLayout.marginWidth = 5; + gridLayout.marginHeight = 5; + gridLayout.horizontalSpacing = -1; + gridLayout.verticalSpacing = -1; + Composite contentComposite = createComposite(scrollComposite, gridLayout); - scrollComposite.setContent(contentComposite); - scrollComposite.setExpandVertical(true); - scrollComposite.setExpandHorizontal(true); - scrollComposite.addListener(SWT.Resize, event -> { - Rectangle scrollArea = scrollComposite.getClientArea(); - - int currentNumColumns = gridLayout.numColumns; - int numChildren = contentComposite.getChildren().length; - Point tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); - - if (tableSize.x < scrollArea.width) { - while (tableSize.x < scrollArea.width && gridLayout.numColumns < numChildren) { - gridLayout.numColumns += 2; - tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); - } - - if (tableSize.x > scrollArea.width) { - gridLayout.numColumns -= 2; - } - } else { - while (tableSize.x > scrollArea.width && gridLayout.numColumns >= 4) { - gridLayout.numColumns -= 2; - tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); - } - } - - if (gridLayout.numColumns != currentNumColumns) { - scrollComposite.layout(); - } - - scrollComposite.setMinHeight(contentComposite.computeSize(scrollArea.width, SWT.DEFAULT).y); - }); - - break; - - case TABLE: - if (dataGroup.getTable().getDynamic()) { - dataGroupComposite.setText(dataGroup.getGroupName() + " (table was set dynamically)"); - } + List kvpList = dataGroup.getKeyValues().getKeyValuesList(); - TableViewer groupTable = createTableViewer(dataGroupComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - List rows = dataGroup.getTable().getRowsList(); + boolean dynamicExists = false; - groupTable.setContentProvider(ArrayContentProvider.getInstance()); + for (API.KeyValuePair kvp : kvpList) { + GridLayout kvpLayout = new GridLayout(1, false); + kvpLayout.marginHeight = 5; + kvpLayout.marginWidth = 5; + Composite keyComposite = withLayoutData( createComposite(contentComposite, kvpLayout, SWT.BORDER), + new GridData(SWT.FILL, SWT.TOP, false, false)); - for (int i = 0; i < dataGroup.getTable().getHeadersCount(); i++) { - int col = i; - TableViewerColumn tvc = createTableColumn(groupTable, dataGroup.getTable().getHeaders(i)); + Label keyLabel = withLayoutData( createBoldLabel(keyComposite, kvp.getName() + (kvp.getDynamic() ? "*:" : ":")), + new GridData(SWT.RIGHT, SWT.CENTER, true, true)); - StyledCellLabelProvider cellLabelProvider = new StyledCellLabelProvider() { - @Override - public void update(ViewerCell cell) { - DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); + if (!dynamicExists && kvp.getDynamic()) { + dataGroupComposite.setText(dataGroup.getGroupName() + " (* value set dynamically)"); + dynamicExists = true; + } - cell.setText(dv.displayValue); + Composite valueComposite = withLayoutData( createComposite(contentComposite, kvpLayout, SWT.BORDER), + new GridData(SWT.FILL, SWT.TOP, false, false)); - if (dv.link != null) { - StyleRange style = new StyleRange(); - theme.linkStyler().applyStyles(style); - style.length = dv.displayValue.length(); - cell.setStyleRanges(new StyleRange[] { style }); - } + DataValue dv = convertDataValue(kvp.getValue()); + if (dv.link != null) { + withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> models.follower.onFollow(dv.link)), + new GridData(SWT.LEFT, SWT.CENTER, true, true)); + } else { + withLayoutData( createLabel(valueComposite, dv.displayValue), + new GridData(SWT.LEFT, SWT.CENTER, true, true)); + } + } - super.update(cell); - } - }; + scrollComposite.setContent(contentComposite); + scrollComposite.setExpandVertical(true); + scrollComposite.setExpandHorizontal(true); + scrollComposite.addListener(SWT.Resize, event -> { + Rectangle scrollArea = scrollComposite.getClientArea(); - tvc.setLabelProvider(cellLabelProvider); - } + int currentNumColumns = gridLayout.numColumns; + int numChildren = contentComposite.getChildren().length; + Point tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); - groupTable.setInput(rows); + if (tableSize.x < scrollArea.width) { + while (tableSize.x < scrollArea.width && gridLayout.numColumns < numChildren) { + gridLayout.numColumns += 2; + tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + } - packColumns(groupTable.getTable()); + if (tableSize.x > scrollArea.width) { + gridLayout.numColumns -= 2; + } + } else { + while (tableSize.x > scrollArea.width && gridLayout.numColumns >= 4) { + gridLayout.numColumns -= 2; + tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + } + } + + if (gridLayout.numColumns != currentNumColumns) { + scrollComposite.layout(); + } - groupTable.getTable().addListener(SWT.MouseDown, e -> { - ViewerCell cell = groupTable.getCell(new Point(e.x, e.y)); + scrollComposite.setMinHeight(contentComposite.computeSize(scrollArea.width, SWT.DEFAULT).y); + }); - if (cell != null) { - DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(cell.getColumnIndex())); + break; - if (dv.link != null) { - models.follower.onFollow(dv.link); - return; - } - } - }); + case TABLE: + if (dataGroup.getTable().getDynamic()) { + dataGroupComposite.setText(dataGroup.getGroupName() + " (table was set dynamically)"); + } - break; + TableViewer groupTable = createTableViewer(dataGroupComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + List rows = dataGroup.getTable().getRowsList(); - case SHADER: - SourceViewer viewer = new SourceViewer( - dataGroupComposite, null, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); - StyledText textWidget = viewer.getTextWidget(); - textWidget.setFont(theme.monoSpaceFont()); - textWidget.setKeyBinding(ST.SELECT_ALL, ST.SELECT_ALL); - viewer.configure(new GlslSourceConfiguration(theme)); - viewer.setEditable(false); - viewer.setDocument( - GlslSourceConfiguration.createDocument(dataGroup.getShader().getSource())); + groupTable.setContentProvider(ArrayContentProvider.getInstance()); - break; + for (int i = 0; i < dataGroup.getTable().getHeadersCount(); i++) { + int col = i; + TableViewerColumn tvc = createTableColumn(groupTable, dataGroup.getTable().getHeaders(i)); - case DATA_NOT_SET: - // Ignore; - break; - } + StyledCellLabelProvider cellLabelProvider = new StyledCellLabelProvider() { + @Override + public void update(ViewerCell cell) { + DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); + + cell.setText(dv.displayValue); + + if (dv.link != null) { + StyleRange style = new StyleRange(); + theme.linkStyler().applyStyles(style); + style.length = dv.displayValue.length(); + cell.setStyleRanges(new StyleRange[] { style }); + } + + super.update(cell); + } + }; + + tvc.setLabelProvider(cellLabelProvider); } - stageGroup.requestLayout(); - } + groupTable.setInput(rows); + + packColumns(groupTable.getTable()); + + groupTable.getTable().addListener(SWT.MouseDown, e -> { + ViewerCell cell = groupTable.getCell(new Point(e.x, e.y)); + + if (cell != null) { + DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(cell.getColumnIndex())); + + if (dv.link != null) { + models.follower.onFollow(dv.link); + return; + } + } + }); + + break; + + case SHADER: + SourceViewer viewer = new SourceViewer( + dataGroupComposite, null, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER); + StyledText textWidget = viewer.getTextWidget(); + textWidget.setFont(theme.monoSpaceFont()); + textWidget.setKeyBinding(ST.SELECT_ALL, ST.SELECT_ALL); + viewer.configure(new GlslSourceConfiguration(theme)); + viewer.setEditable(false); + viewer.setDocument( + GlslSourceConfiguration.createDocument(dataGroup.getShader().getSource())); + + break; + + case DATA_NOT_SET: + // Ignore; + break; } } + + stageGroup.requestLayout(); + return stageGroup; } @Override @@ -548,4 +659,14 @@ public DataValue(String displayValue) { this.displayValue = displayValue; } } + + private static class StageUI { + public Button stageButton; + public Composite stageComposite; + + public StageUI(Button stageButton, Composite stageComposite) { + this.stageButton = stageButton; + this.stageComposite = stageComposite; + } + } } From d91f693abca54b23dfc088a557d81d98a30659f1 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:47:14 -0800 Subject: [PATCH 0023/1218] Add tooltips for Enums in Pipeline View (#17) --- .../com/google/gapid/views/PipelineView.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index 95d1fe5b6b..be60ca5513 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -54,6 +54,7 @@ import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; @@ -76,6 +77,7 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Button; @@ -350,7 +352,7 @@ private Composite createStage(Composite parent, API.Stage currentStage) { Composite contentComposite = createComposite(scrollComposite, gridLayout); List kvpList = dataGroup.getKeyValues().getKeyValuesList(); - + boolean dynamicExists = false; for (API.KeyValuePair kvp : kvpList) { @@ -386,7 +388,7 @@ private Composite createStage(Composite parent, API.Stage currentStage) { scrollComposite.setExpandHorizontal(true); scrollComposite.addListener(SWT.Resize, event -> { Rectangle scrollArea = scrollComposite.getClientArea(); - + int currentNumColumns = gridLayout.numColumns; int numChildren = contentComposite.getChildren().length; Point tableSize = contentComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); @@ -633,11 +635,20 @@ protected static DataValue convertDataValue(API.DataValue val) { } case ENUMVAL: - return new DataValue(val.getEnumVal().getDisplayValue()); + DataValue enumDV = new DataValue(val.getEnumVal().getDisplayValue()); + enumDV.tooltipValue = val.getEnumVal().getStringValue(); + return enumDV; + case BITFIELD: Joiner joiner = Joiner.on((val.getBitfield().getCombined()) ? "" : " | "); - return new DataValue(joiner.join(val.getBitfield().getSetDisplayNamesList())); + DataValue bitDV = new DataValue(joiner.join(val.getBitfield().getSetDisplayNamesList())); + if (val.getBitfield().getCombined()) { + joiner = Joiner.on(" | "); + } + bitDV.tooltipValue = joiner.join(val.getBitfield().getSetBitnamesList()); + return bitDV; + case LINK: DataValue dv = convertDataValue(val.getLink().getDisplayVal()); @@ -652,11 +663,13 @@ protected static DataValue convertDataValue(API.DataValue val) { private static class DataValue { public String displayValue; + public String tooltipValue; public Path.Any link; public DataValue(String displayValue) { this.link = null; this.displayValue = displayValue; + this.tooltipValue = null; } } From e954fa0fe65b2094652377ac0e9f05f8aeac61c0 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Mon, 10 Feb 2020 20:08:10 -0800 Subject: [PATCH 0024/1218] Force prerelease driver for tracing and replay (#18) --- core/os/android/adb/bind.go | 2 ++ core/os/android/adb/commands.go | 52 ++++++++++++++++++++----------- gapii/client/adb.go | 19 ++++++++++- gapir/client/device_connection.go | 2 +- gapis/perfetto/android/trace.go | 9 ++++-- 5 files changed, 62 insertions(+), 22 deletions(-) diff --git a/core/os/android/adb/bind.go b/core/os/android/adb/bind.go index 43835e4421..aa8ecdbdc3 100644 --- a/core/os/android/adb/bind.go +++ b/core/os/android/adb/bind.go @@ -38,6 +38,8 @@ type Device interface { RemoveForward(ctx context.Context, local Port) error // GraphicsDriver queries and returns info on the preview graphics driver. GraphicsDriver(ctx context.Context) (Driver, error) + // PrereleaseGraphicsDriver queries and returns info on the prerelease graphics driver. + PrereleaseGraphicsDriver(ctx context.Context) (Driver, error) } // Driver contains the information about a graphics driver. diff --git a/core/os/android/adb/commands.go b/core/os/android/adb/commands.go index a60c775ec8..70586a84ce 100644 --- a/core/os/android/adb/commands.go +++ b/core/os/android/adb/commands.go @@ -381,6 +381,39 @@ func extrasFlags(extras []android.ActionExtra) []string { return flags } +func (b *binding) resolveDriverPath(ctx context.Context, driver string) (Driver, error) { + path, err := b.Shell("pm", "path", driver).Call(ctx) + if err != nil { + return Driver{}, err + } + // Check the package path of the driver. + if !strings.HasPrefix(path, "package:") { + return Driver{}, nil + } + path = path[8:] + if path == "" { + return Driver{}, nil + } + + return Driver{ + Package: driver, + Path: path, + }, nil +} + +// PrereleaseGraphicsDriver queries and returns info on the prerelease graphics driver. +func (b *binding) PrereleaseGraphicsDriver(ctx context.Context) (Driver, error) { + driver, err := b.SystemProperty(ctx, driverProperty) + if err != nil { + return Driver{}, err + } + if driver == "" { + // There is no prerelease driver. + return Driver{}, nil + } + return b.resolveDriverPath(ctx, driver) +} + // DriverPackage queries and returns the package of the preview graphics driver. func (b *binding) GraphicsDriver(ctx context.Context) (Driver, error) { // Check if there is an override setup. @@ -399,22 +432,5 @@ func (b *binding) GraphicsDriver(ctx context.Context) (Driver, error) { return Driver{}, nil } } - - // Check the package path of the driver. - path, err := b.Shell("pm", "path", driver).Call(ctx) - if err != nil { - return Driver{}, err - } - if !strings.HasPrefix(path, "package:") { - return Driver{}, nil - } - path = path[8:] - if path == "" { - return Driver{}, nil - } - - return Driver{ - Package: driver, - Path: path, - }, nil + return b.resolveDriverPath(ctx, driver) } diff --git a/gapii/client/adb.go b/gapii/client/adb.go index bbda8a650d..a4385a27ba 100644 --- a/gapii/client/adb.go +++ b/gapii/client/adb.go @@ -72,6 +72,23 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity abi = p.Device.Instance().GetConfiguration().PreferredABI(nil) } + driver, err := d.PrereleaseGraphicsDriver(ctx) + if err != nil { + return nil, nil, log.Err(ctx, err, "Failed to locate pre-release driver package") + } + + cleanup := app.Cleanup(func(ctx context.Context) {}) + // Force the traced app to use the pre-release driver, or fail early + if driver.Package != "" && a != nil && a.Package != nil { + nextCleanup, err := adb.SetupPrereleaseDriver(ctx, d, a.Package) + cleanup = cleanup.Then(nextCleanup) + if err != nil { + return nil, cleanup.Invoke(ctx), err + } + } else { + return nil, cleanup.Invoke(ctx), log.Err(ctx, nil, "Failed to locate pre-release driver package") + } + // For NativeBridge emulated devices opt for the native ABI of the emulator. abi = d.NativeBridgeABI(ctx, abi) @@ -106,7 +123,7 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity if err := d.Forward(ctx, adb.TCPPort(port), adb.NamedAbstractSocket(pipe)); err != nil { return nil, nil, log.Err(ctx, err, "Setting up port forwarding for gapii") } - cleanup := app.Cleanup(func(ctx context.Context) { + cleanup = cleanup.Then(func(ctx context.Context) { d.RemoveForward(ctx, port) }) diff --git a/gapir/client/device_connection.go b/gapir/client/device_connection.go index b8712a4855..f728fe4b11 100644 --- a/gapir/client/device_connection.go +++ b/gapir/client/device_connection.go @@ -278,7 +278,7 @@ func newADB(ctx context.Context, d adb.Device, abi *device.ABI, launchArgs []str log.I(ctx, "Launching GAPIR...") // Configure GAPIR to be traceable for replay profiling - cleanup, err := perfetto_android.SetupProfileLayersSource(ctx, d, apk.Name, abi) + cleanup, err := perfetto_android.SetupProfileLayersSource(ctx, d, apk.InstalledPackage, abi) if err != nil { // TODO(apbodnar) Fail here if we know we need render stages diff --git a/gapis/perfetto/android/trace.go b/gapis/perfetto/android/trace.go index 5332cf3d02..dd2e242e16 100644 --- a/gapis/perfetto/android/trace.go +++ b/gapis/perfetto/android/trace.go @@ -61,7 +61,11 @@ func hasRenderStageEnabled(perfettoConfig *perfetto_pb.TraceConfig) bool { } // SetupProfileLayersSource configures the device to allow packages to be used as layer sources for profiling -func SetupProfileLayersSource(ctx context.Context, d adb.Device, packageName string, abi *device.ABI) (app.Cleanup, error) { +func SetupProfileLayersSource(ctx context.Context, d adb.Device, apk *android.InstalledPackage, abi *device.ABI) (app.Cleanup, error) { + cleanup, err := adb.SetupPrereleaseDriver(ctx, d, apk) + if err != nil { + return cleanup.Invoke(ctx), err + } driver, err := d.GraphicsDriver(ctx) if err != nil { return nil, err @@ -71,7 +75,8 @@ func SetupProfileLayersSource(ctx context.Context, d adb.Device, packageName str packages = append(packages, gapidapk.PackageName(abi)) } - cleanup, err := android.SetupLayers(ctx, d, packageName, packages, []string{}, true) + nextCleanup, err := android.SetupLayers(ctx, d, apk.Name, packages, []string{}, true) + cleanup = cleanup.Then(nextCleanup) if err != nil { return cleanup.Invoke(ctx), log.Err(ctx, err, "Failed to setup gpu.renderstages layer packages.") } From 4e125331a99ae50288c9f26636b892b081473217 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:29:29 -0800 Subject: [PATCH 0025/1218] Disable taking a GLES trace. --- gapis/trace/android/trace.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go index 8a6e2ab382..a97c5c7a8c 100644 --- a/gapis/trace/android/trace.go +++ b/gapis/trace/android/trace.go @@ -268,9 +268,11 @@ func NewTracer(dev bind.Device) tracer.Tracer { // TraceConfiguration returns the device's supported trace configuration. func (t *androidTracer) TraceConfiguration(ctx context.Context) (*service.DeviceTraceConfiguration, error) { apis := make([]*service.TraceTypeCapabilities, 0, 3) + /* Disabled in AGI. Use GAPID instead. if t.b.Instance().GetConfiguration().GetDrivers().GetOpengl().GetVersion() != "" { apis = append(apis, tracer.GLESTraceOptions()) } + */ if len(t.b.Instance().GetConfiguration().GetDrivers().GetVulkan().GetPhysicalDevices()) > 0 { apis = append(apis, tracer.VulkanTraceOptions()) } From 171f0e92bb898faf53dc0d6a1d5d29af0d82ab58 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 10 Feb 2020 07:57:16 -0800 Subject: [PATCH 0026/1218] Fail with a useful message when opening a GLES trace. --- gapis/capture/graphics.go | 8 ++++++++ gapis/messages/en-us.stb.md | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/gapis/capture/graphics.go b/gapis/capture/graphics.go index 395163721a..40fb69f666 100644 --- a/gapis/capture/graphics.go +++ b/gapis/capture/graphics.go @@ -282,6 +282,14 @@ func deserializeGFXTrace(ctx context.Context, r *Record, in io.Reader) (out *Gra if d.header == nil { return nil, log.Err(ctx, nil, "Capture was missing header chunk") } + + for _, api := range d.builder.apis { + if api.Name() == "gles" { + return nil, &service.ErrUnsupportedVersion{ + Reason: messages.ErrFileOpenGl(), + } + } + } return d.builder.build(r.Name, d.header), nil } diff --git a/gapis/messages/en-us.stb.md b/gapis/messages/en-us.stb.md index 92cc179832..b53f24a100 100644 --- a/gapis/messages/en-us.stb.md +++ b/gapis/messages/en-us.stb.md @@ -226,3 +226,7 @@ The file was created by a more recent version of AGI and cannot be read. # ERR_FILE_TOO_OLD The file was created by an old version of AGI and cannot be read. + +# ERR_FILE_OPEN_GL + +GLES traces are not supported in AGI. Please use GAPID instead. From 886701cc3ae175494edbc001de567fbbf6255816 Mon Sep 17 00:00:00 2001 From: Melih Yasin Yalcin Date: Tue, 11 Feb 2020 10:40:32 +0000 Subject: [PATCH 0027/1218] Fix the reporting issue in MEC by setting cmdID to 0 for all the (#14) initial commands while transforming commands. b/148923131 --- gapis/api/gles/replay.go | 2 +- gapis/api/sync/sync.go | 2 +- gapis/api/transform/transforms.go | 11 ++++++++--- gapis/api/vulkan/find_issues.go | 21 +++++++++++---------- gapis/api/vulkan/replay.go | 8 ++++---- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/gapis/api/gles/replay.go b/gapis/api/gles/replay.go index 4cd3d6c024..155acdaacf 100644 --- a/gapis/api/gles/replay.go +++ b/gapis/api/gles/replay.go @@ -293,7 +293,7 @@ func (a API) Replay( if profile == nil { cmds = []api.Cmd{} // DeadCommandRemoval generates commands. } - return transforms.Transform(ctx, cmds, out) + return transforms.TransformAll(ctx, cmds, 0, out) } func (a API) QueryIssues( diff --git a/gapis/api/sync/sync.go b/gapis/api/sync/sync.go index 77f4b9d148..0b76ac22ba 100644 --- a/gapis/api/sync/sync.go +++ b/gapis/api/sync/sync.go @@ -152,7 +152,7 @@ func MutationCmdsFor(ctx context.Context, c *path.Capture, data *Data, cmds []ap return cmds[0 : id+1], nil } w := &writer{rc.NewState(ctx), nil} - if err := transforms.Transform(ctx, cmds, w); err != nil { + if err := transforms.TransformAll(ctx, cmds, 0, w); err != nil { return nil, err } diff --git a/gapis/api/transform/transforms.go b/gapis/api/transform/transforms.go index 8a6b3ddc6c..0cabe59904 100644 --- a/gapis/api/transform/transforms.go +++ b/gapis/api/transform/transforms.go @@ -24,9 +24,9 @@ import ( // Transforms is a list of Transformer objects. type Transforms []Transformer -// Transform sequentially transforms the commands by each of the transformers in +// TransformAll sequentially transforms the commands by each of the transformers in // the list, before writing the final output to the output command Writer. -func (l Transforms) Transform(ctx context.Context, cmds []api.Cmd, out Writer) error { +func (l Transforms) TransformAll(ctx context.Context, cmds []api.Cmd, numberOfInitialCommands uint64, out Writer) error { chain := out for i := len(l) - 1; i >= 0; i-- { s := chain.State() @@ -43,7 +43,12 @@ func (l Transforms) Transform(ctx context.Context, cmds []api.Cmd, out Writer) e chain = TransformWriter{s, l[i], chain} } err := api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - return chain.MutateAndWrite(ctx, id, cmd) + captureCmdID := api.CmdNoID + if uint64(id) > numberOfInitialCommands { + captureCmdID = id - api.CmdID(numberOfInitialCommands) + } + + return chain.MutateAndWrite(ctx, captureCmdID, cmd) }) if err != nil { return err diff --git a/gapis/api/vulkan/find_issues.go b/gapis/api/vulkan/find_issues.go index 8943522aa8..70ee321fd1 100644 --- a/gapis/api/vulkan/find_issues.go +++ b/gapis/api/vulkan/find_issues.go @@ -63,7 +63,6 @@ func isValidationLayer(n string) bool { type findIssues struct { replay.EndOfReplay state *api.GlobalState - numInitialCmds int issues []replay.Issue reportCallbacks map[VkInstance]VkDebugReportCallbackEXT } @@ -71,7 +70,6 @@ type findIssues struct { func newFindIssues(ctx context.Context, c *capture.GraphicsCapture, numInitialCmds int) *findIssues { t := &findIssues{ state: c.NewState(ctx), - numInitialCmds: numInitialCmds, reportCallbacks: map[VkInstance]VkDebugReportCallbackEXT{}, } t.state.OnError = func(err interface{}) { @@ -286,18 +284,21 @@ func (t *findIssues) Flush(ctx context.Context, out transform.Writer) error { var issue replay.Issue msg := eMsg.GetMsg() label := eMsg.GetLabel() - if int(label) < t.numInitialCmds { + issue.Command = api.CmdID(label) + issue.Severity = service.Severity(uint32(eMsg.GetSeverity())) + + if issue.Command == api.CmdNoID { // The debug report is issued for state rebuilding command // TODO: Fix all the errors reported for initial commands. + // TODO: Provide a way for the UI to distinguish these issues + // from issues on command 0. issue.Command = api.CmdID(0) - issue.Error = fmt.Errorf("[State rebuilding command, linearized ID: %d]: %s", label, msg) - // For now hide such errors from the report view so users won't get confused. - return + issue.Error = fmt.Errorf("[State rebuilding command : %s] ", msg) + } else { + // The debug report is issued for a trace command + issue.Error = fmt.Errorf("%s", msg) } - // The debug report is issued for a trace command - issue.Command = api.CmdID(label - uint64(t.numInitialCmds)) - issue.Error = fmt.Errorf("%s", msg) - issue.Severity = service.Severity(uint32(eMsg.GetSeverity())) + t.issues = append(t.issues, issue) }) })) diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 38dadfa7f1..c8a32b7848 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -845,7 +845,7 @@ func (a API) GetInitialPayload(ctx context.Context, initialCmds, im, _ := initialcmds.InitialCommands(ctx, capture) out.State().Allocator.ReserveRanges(im) - return transforms.Transform(ctx, initialCmds, out) + return transforms.TransformAll(ctx, initialCmds, uint64(len(initialCmds)), out) } func (a API) CleanupResources(ctx context.Context, @@ -853,7 +853,7 @@ func (a API) CleanupResources(ctx context.Context, out transform.Writer) error { transforms := transform.Transforms{} transforms.Add(&destroyResourcesAtEOS{}) - return transforms.Transform(ctx, []api.Cmd{}, out) + return transforms.TransformAll(ctx, []api.Cmd{}, 0, out) } func (a API) Replay( @@ -1090,7 +1090,7 @@ func (a API) Replay( } } - _, err = expandCommands(optimize) + numberOfInitialCmds, err := expandCommands(optimize) if err != nil { return err } @@ -1173,7 +1173,7 @@ func (a API) Replay( transforms.Add(replay.NewMappingExporterWithPrint(ctx, "mappings.txt")) } - return transforms.Transform(ctx, cmds, out) + return transforms.TransformAll(ctx, cmds, uint64(numberOfInitialCmds), out) } func (a API) QueryFramebufferAttachment( From de9b983317388354d5b89b7d3561a3ba9da56410 Mon Sep 17 00:00:00 2001 From: John Plate Date: Tue, 11 Feb 2020 16:06:02 +0000 Subject: [PATCH 0028/1218] Update Kokoro to GCC 9.2 and Bazel 2.0.0 (#22) --- BUILDING.md | 8 ++++---- kokoro/linux-test/test.sh | 6 +++--- kokoro/linux/build.sh | 8 ++++---- kokoro/macos/build.sh | 2 +- kokoro/presubmit/build.sh | 2 +- kokoro/windows/build.bat | 10 ++++++---- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 94190f0ff6..33a3f5922a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,6 +1,6 @@ # Building Android GPU Inspector -AGI uses the [Bazel build system](https://bazel.build/). The recommended version of Bazel is **1.2.0**. +AGI uses the [Bazel build system](https://bazel.build/). The recommended version of Bazel is **2.0.0**. Bazel is able to fetch most of the dependencies required to build AGI, but currently the Android SDK and NDK both need to be downloaded and installed by hand. @@ -37,9 +37,9 @@ Using the msys64 shell at `C:\tools\msys64\mingw64`: 1. Update MSYS with: `pacman -Syu`. 2. If the update ends with “close the window and run it again”, close and reopen the window and repeat 1. 3. Fetch required tools with: `pacman -S curl git zip unzip patch` -4. Download gcc with: `curl -O http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-7.3.0-2-any.pkg.tar.xz` -5. Download gcc-libs with: `curl -O http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-libs-7.3.0-2-any.pkg.tar.xz` -6. Install gcc with: `pacman -U mingw-w64-x86_64-gcc*-7.3.0-2-any.pkg.tar.xz` +4. Download gcc with: `curl -O http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-9.2.0-2-any.pkg.tar.xz` +5. Download gcc-libs with: `curl -O http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-libs-9.2.0-2-any.pkg.tar.xz` +6. Install gcc with: `pacman -U mingw-w64-x86_64-gcc*-9.2.0-2-any.pkg.tar.xz` 7. Close the MSYS terminal ### Install Java Development Kit 8 diff --git a/kokoro/linux-test/test.sh b/kokoro/linux-test/test.sh index 67093c33be..0ecbf2f0fc 100755 --- a/kokoro/linux-test/test.sh +++ b/kokoro/linux-test/test.sh @@ -20,7 +20,7 @@ BUILD_ROOT=$PWD SRC=$PWD/github/agi/ # Get bazel -BAZEL_VERSION=1.2.0 +BAZEL_VERSION=2.0.0 curl -L -k -O -s https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh mkdir bazel bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel @@ -29,8 +29,8 @@ bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel sudo rm /etc/apt/sources.list.d/cuda.list* sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get -q update -sudo apt-get -qy install gcc-8 g++-8 -export CC=/usr/bin/gcc-8 +sudo apt-get -qy install gcc-9 g++-9 +export CC=/usr/bin/gcc-9 cd $SRC BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 25a17102f9..d7efc8492b 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -20,17 +20,17 @@ BUILD_ROOT=$PWD SRC=$PWD/github/agi/ # Get bazel. -BAZEL_VERSION=1.2.0 +BAZEL_VERSION=2.0.0 curl -L -k -O -s https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh mkdir bazel bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel -# Get GCC 8 +# Get GCC 9 sudo rm /etc/apt/sources.list.d/cuda.list* sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get -q update -sudo apt-get -qy install gcc-8 g++-8 -export CC=/usr/bin/gcc-8 +sudo apt-get -qy install gcc-9 g++-9 +export CC=/usr/bin/gcc-9 # Get the Android NDK curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip diff --git a/kokoro/macos/build.sh b/kokoro/macos/build.sh index d9bae12081..896f686bdc 100755 --- a/kokoro/macos/build.sh +++ b/kokoro/macos/build.sh @@ -30,7 +30,7 @@ export ANDROID_HOME=$PWD/android export ANDROID_NDK_HOME=$PWD/android/android-ndk-r20b # Get bazel. -BAZEL_VERSION=1.2.0 +BAZEL_VERSION=2.0.0 curl -L -k -O -s https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-darwin-x86_64.sh mkdir bazel sh bazel-${BAZEL_VERSION}-installer-darwin-x86_64.sh --prefix=$PWD/bazel diff --git a/kokoro/presubmit/build.sh b/kokoro/presubmit/build.sh index 80c4e34b96..16a3bf5227 100755 --- a/kokoro/presubmit/build.sh +++ b/kokoro/presubmit/build.sh @@ -20,7 +20,7 @@ BUILD_ROOT=$PWD SRC=$PWD/github/agi/ # Get bazel. -BAZEL_VERSION=1.2.0 +BAZEL_VERSION=2.0.0 curl -L -k -O -s https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh mkdir bazel bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat index 2045aff9e5..1f9012f138 100644 --- a/kokoro/windows/build.bat +++ b/kokoro/windows/build.bat @@ -41,17 +41,19 @@ unzip -q -d wix wix311-binaries.zip set WIX=%cd%\wix REM Fix up the MSYS environment. -wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-7.3.0-2-any.pkg.tar.xz -wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-libs-7.3.0-2-any.pkg.tar.xz +wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-binutils-2.33.1-1-any.pkg.tar.xz +wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-9.2.0-2-any.pkg.tar.xz +wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-libs-9.2.0-2-any.pkg.tar.xz c:\tools\msys64\usr\bin\bash --login -c "pacman -R --noconfirm catgets libcatgets" c:\tools\msys64\usr\bin\bash --login -c "pacman -Syu --noconfirm" c:\tools\msys64\usr\bin\bash --login -c "pacman -Sy --noconfirm mingw-w64-x86_64-crt-git patch" -c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-gcc*-7.3.0-2-any.pkg.tar.xz" +c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-binutils-2.33.1-1-any.pkg.tar.xz" +c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-gcc*-9.2.0-2-any.pkg.tar.xz" set PATH=c:\tools\msys64\mingw64\bin;c:\tools\msys64\usr\bin;%PATH% set BAZEL_SH=C:\tools\msys64\usr\bin\bash.exe REM Install Bazel. -set BAZEL_VERSION=1.2.0 +set BAZEL_VERSION=2.0.0 wget -q https://github.com/bazelbuild/bazel/releases/download/%BAZEL_VERSION%/bazel-%BAZEL_VERSION%-windows-x86_64.zip unzip -q bazel-%BAZEL_VERSION%-windows-x86_64.zip set PATH=C:\python27;%PATH% From d2ba72a6b2f9f7048abd4144717ddb54e2d46705 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 04:21:38 -0800 Subject: [PATCH 0029/1218] Remove the overdraw rendering mode as it's currently broken. --- .../main/com/google/gapid/views/FramebufferView.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/FramebufferView.java b/gapic/src/main/com/google/gapid/views/FramebufferView.java index 80c24c153a..c4e3df2a07 100644 --- a/gapic/src/main/com/google/gapid/views/FramebufferView.java +++ b/gapic/src/main/com/google/gapid/views/FramebufferView.java @@ -78,10 +78,6 @@ public class FramebufferView extends Composite .setMaxHeight(MAX_SIZE).setMaxWidth(MAX_SIZE) .setDrawMode(Service.DrawMode.WIREFRAME_ALL) .build(); - private static final Service.RenderSettings RENDER_OVERDRAW = Service.RenderSettings.newBuilder() - .setMaxHeight(MAX_SIZE).setMaxWidth(MAX_SIZE) - .setDrawMode(Service.DrawMode.OVERDRAW) - .build(); private final Models models; private final SingleInFlight rpcController = new SingleInFlight(); @@ -160,12 +156,7 @@ private ToolBar createToolBar(Theme theme) { models.analytics.postInteraction(View.Framebuffer, ClientAction.Wireframe); renderSettings = RENDER_WIREFRAME; updateBuffer(); - }, "Render wireframe geometry"), - createToggleToolItem(bar, theme.overdraw(), e -> { - models.analytics.postInteraction(View.Framebuffer, ClientAction.Overdraw); - renderSettings = RENDER_OVERDRAW; - updateBuffer(); - }, "Render overdraw")); + }, "Render wireframe geometry")); createSeparator(bar); return bar; } From 3bbe05345e72332c13599e21e95496a87127a7fe Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com> Date: Tue, 11 Feb 2020 13:51:40 -0800 Subject: [PATCH 0030/1218] Force stop already running gapidapk before starting (#28) The current instance of gapidapk is kept alive in the device and resumed during the loadDevices phase. This causes a prolonged wait and eventual failure to find the android device, if the driver is updated and gapid is launched without restarting the device. Bug: 149109076 --- gapidapk/deviceinfo.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gapidapk/deviceinfo.go b/gapidapk/deviceinfo.go index 987d7c4a05..0e99fe98ed 100644 --- a/gapidapk/deviceinfo.go +++ b/gapidapk/deviceinfo.go @@ -108,6 +108,9 @@ func fetchDeviceInfo(ctx context.Context, d adb.Device) error { return nil } + // Close any previous runs of the apk + apk.Stop(ctx) + driver, err := d.GraphicsDriver(ctx) if err != nil { return err From 9fcb0a815fb794df7a48844a9942b5d7f1fe5847 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 11 Feb 2020 14:38:37 -0800 Subject: [PATCH 0031/1218] Fix Vulkan sample cube distortion. (#25) Previously the submission will wait inside BOTTOM_OF_PIPE for the swapchain_image_ready_semaphores. This means that it will do all the rendering and writing out to the image before the swapchain image is actually ready. Instead we need to wait for the submission inside TOP_OF_PIPE so that the work is blocked until the image is ready. Bug: b/149113751 --- cmd/vulkan_sample/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/vulkan_sample/main.cpp b/cmd/vulkan_sample/main.cpp index e397bb7cb6..0c412fdef0 100644 --- a/cmd/vulkan_sample/main.cpp +++ b/cmd/vulkan_sample/main.cpp @@ -1717,7 +1717,7 @@ int main(int argc, const char** argv) { vkCmdEndRenderPass(render_command_buffers[frame_parity]); REQUIRE_SUCCESS(vkEndCommandBuffer(render_command_buffers[frame_parity])); - VkPipelineStageFlags flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkPipelineStageFlags flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; VkSubmitInfo submit{VK_STRUCTURE_TYPE_SUBMIT_INFO, nullptr, From fcd1cd4f8c027f068d4b4469f6583f14d7877a2f Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Tue, 11 Feb 2020 16:50:11 -0800 Subject: [PATCH 0032/1218] Fix replay profiling after command id changes (#32) --- gapis/api/vulkan/replay.go | 6 +----- gapis/api/vulkan/wait_for_perfetto.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index c8a32b7848..12348c52df 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -1062,14 +1062,10 @@ func (a API) Replay( if profile == nil { profile = &replay.EndOfReplay{} } - numInitialCommands, err := expandCommands(false) - if err != nil { - return err - } profile.AddResult(rr.Result) makeReadable.imagesOnly = true optimize = false - transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer, api.CmdID(numInitialCommands))) + transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer)) transforms.Add(&profilingLayers{}) transforms.Add(replay.NewMappingExporter(ctx, req.mappings)) if req.overrides.GetViewportSize() { diff --git a/gapis/api/vulkan/wait_for_perfetto.go b/gapis/api/vulkan/wait_for_perfetto.go index de9ec62038..f30eb9e488 100644 --- a/gapis/api/vulkan/wait_for_perfetto.go +++ b/gapis/api/vulkan/wait_for_perfetto.go @@ -46,7 +46,12 @@ func addVkDeviceWaitIdle(ctx context.Context, out transform.Writer) { } func (t *WaitForPerfetto) waitTest(ctx context.Context, id api.CmdID, cmd api.Cmd) bool { - if id == t.cmdId { + // Set the command id we care about once we're in the "real" commands + if id.IsReal() && t.cmdId == api.CmdNoID { + t.cmdId = id + } + + if id.IsReal() && id == t.cmdId { return true } return false @@ -68,7 +73,7 @@ func (t *WaitForPerfetto) PreLoop(ctx context.Context, out transform.Writer) {} func (t *WaitForPerfetto) PostLoop(ctx context.Context, out transform.Writer) {} func (t *WaitForPerfetto) BuffersCommands() bool { return false } -func NewWaitForPerfetto(traceOptions *service.TraceOptions, h *replay.SignalHandler, buffer *bytes.Buffer, cmdId api.CmdID) *WaitForPerfetto { +func NewWaitForPerfetto(traceOptions *service.TraceOptions, h *replay.SignalHandler, buffer *bytes.Buffer) *WaitForPerfetto { tcb := func(ctx context.Context, p *gapir.FenceReadyRequest) { go func() { trace.TraceBuffered(ctx, traceOptions.Device, h.StartSignal, h.StopSignal, h.ReadyFunc, traceOptions, buffer) @@ -84,7 +89,7 @@ func NewWaitForPerfetto(traceOptions *service.TraceOptions, h *replay.SignalHand h.StopFunc(ctx) } } - wfp := WaitForPerfetto{cmdId: cmdId} + wfp := WaitForPerfetto{cmdId: api.CmdNoID} wfp.wff = replay.WaitForFence{tcb, fcb, wfp.waitTest} return &wfp From 2106d569ed1fe1511f01319a3c212e09ae4fd69f Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 05:32:31 -0800 Subject: [PATCH 0033/1218] Trim down the atrace categories. --- .../com/google/gapid/perfetto/views/TraceConfigDialog.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index c91ff7795b..de1f9b421e 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -107,11 +107,7 @@ public class TraceConfigDialog extends DialogBase { "sched/sched_waking", }; private static final String[] CPU_SLICES_ATRACE = { - // TODO: this should come from the device. - "adb", "aidl", "am", "audio", "binder_driver", "binder_lock", "bionic", "camera", - "core_services", "dalvik", "database", "disk", "freq", "gfx", "hal", "idle", "input", - "ion", "memory", "memreclaim", "network", "nnapi", "pdx", "pm", "power", "res", "rro", "rs", - "sched", "sm", "ss", "sync", "vibrator", "video", "view", "webview", "wm", + "am", "audio", "gfx", "hal", "input", "pm", "power", "res", "rs", "sm", "video", "view", "wm", }; private static final String[] GPU_FREQ_FTRACE = { "power/gpu_frequency", From 823e35f36ff63290b48cce849745ea640ec12806 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 05:42:58 -0800 Subject: [PATCH 0034/1218] Updates to the ftrace categories we use. - Always listen to the process creation and ending categories to accurately track process metadata throughout the trace. - Remove unneeded sched/sched_process_exit - Add kmem/rss_stat if memory is selected. This used to be implied by "memory" atrace category. --- .../perfetto/views/TraceConfigDialog.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index de1f9b421e..2c1cab262b 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -88,24 +88,35 @@ public class TraceConfigDialog extends DialogBase { protected static final Logger LOG = Logger.getLogger(TraceConfigDialog.class.getName()); private static final int BUFFER_SIZE = 131072; + // Kernel ftrace buffer size per CPU. private static final int FTRACE_BUFFER_SIZE = 8192; + + // These ftrace categories are always enabled to track process creation and ending. + private static final String[] PROCESS_TRACKING_FTRACE = { + "sched/sched_process_free", + "task/task_newtask", + "task/task_rename", + }; + // These ftrace categories are used to track CPU slices. private static final String[] CPU_BASE_FTRACE = { "sched/sched_switch", - "sched/sched_process_exit", - "sched/sched_process_free", - "task/task_newtask", - "task/task_rename", "power/suspend_resume", }; + // These ftrace categories provide CPU frequency data. private static final String[] CPU_FREQ_FTRACE = { "power/cpu_frequency", "power/cpu_idle" }; + // These ftrace categories provide scheduling dependency data. private static final String[] CPU_CHAIN_FTRACE = { "sched/sched_wakeup", "sched/sched_wakeup_new", "sched/sched_waking", }; + // These ftrace categories provide memory usage data. + private static final String[] MEM_FTRACE = { + "kmem/rss_stat", + }; private static final String[] CPU_SLICES_ATRACE = { "am", "audio", "gfx", "hal", "input", "pm", "power", "res", "rs", "sm", "video", "view", "wm", }; @@ -197,14 +208,12 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( } PerfettoConfig.TraceConfig.Builder config = PerfettoConfig.TraceConfig.newBuilder(); - PerfettoConfig.FtraceConfig.Builder ftrace = null; - if (p.getCpuOrBuilder().getEnabled() || (p.getGpuOrBuilder().getEnabled())) { - ftrace = config.addDataSourcesBuilder() - .getConfigBuilder() - .setName("linux.ftrace") - .getFtraceConfigBuilder() - .setBufferSizeKb(FTRACE_BUFFER_SIZE); - } + PerfettoConfig.FtraceConfig.Builder ftrace = config.addDataSourcesBuilder() + .getConfigBuilder() + .setName("linux.ftrace") + .getFtraceConfigBuilder() + .addAllFtraceEvents(Arrays.asList(PROCESS_TRACKING_FTRACE)) + .setBufferSizeKb(FTRACE_BUFFER_SIZE); if (p.getCpuOrBuilder().getEnabled()) { // Record process names. @@ -261,6 +270,7 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( } if (p.getMemoryOrBuilder().getEnabled()) { + ftrace.addAllFtraceEvents(Arrays.asList(MEM_FTRACE)); config.addDataSourcesBuilder() .getConfigBuilder() .setName("linux.sys_stats") From 832918a5cdcefcd6fd83f51edfa40bc395c198c5 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 07:29:47 -0800 Subject: [PATCH 0035/1218] Fix how we get process data. - Always scan the process data at startup and write it into a separate buffer. - Always peridically scan the process data and include it in the main buffer. --- .../google/gapid/perfetto/models/Tracks.java | 11 ++++++ .../perfetto/views/TraceConfigDialog.java | 35 ++++++++++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java index dc9b55f603..f27314c303 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java @@ -21,6 +21,7 @@ import static com.google.gapid.perfetto.views.TrackContainer.single; import static java.util.stream.Collectors.toList; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.models.Perfetto; @@ -38,6 +39,7 @@ import com.google.gapid.perfetto.views.VulkanCounterPanel; import com.google.gapid.perfetto.views.VulkanEventPanel; import com.google.gapid.util.Scheduler; + import java.util.Collections; import java.util.List; import java.util.Objects; @@ -49,6 +51,10 @@ public class Tracks { // CPU usage percentage at which a process/thread is considered idle. private static final double IDLE_PERCENT_CUTOFF = 0.001; // 0.1%. + // Polled counters from the process_stats data source. + private static final ImmutableSet PROC_STATS_COUNTER = ImmutableSet.of( + "mem.virt", "mem.rss", "mem.locked", "oom_score_adj" + ); private Tracks() { } @@ -299,6 +305,11 @@ private static boolean shouldShowProcessCounter(CounterInfo counter) { return false; } + if (PROC_STATS_COUNTER.contains(counter.name)) { + // The process_stat counters are too infrequent to be helpful. + return false; + } + if ("VSYNC-app".equals(counter.name)) { // VSync has a custom UI. return false; diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 2c1cab262b..3b0e8b179c 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -87,10 +87,14 @@ public class TraceConfigDialog extends DialogBase { protected static final Logger LOG = Logger.getLogger(TraceConfigDialog.class.getName()); - private static final int BUFFER_SIZE = 131072; + private static final int MAIN_BUFFER_SIZE = 131072; + private static final int PROC_BUFFER_SIZE = 4096; + private static final int PROC_BUFFER = 1; // Kernel ftrace buffer size per CPU. private static final int FTRACE_BUFFER_SIZE = 8192; + private static final int PROC_SCAN_PERIOD = 2000; + // These ftrace categories are always enabled to track process creation and ending. private static final String[] PROCESS_TRACKING_FTRACE = { "sched/sched_process_free", @@ -214,15 +218,22 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .getFtraceConfigBuilder() .addAllFtraceEvents(Arrays.asList(PROCESS_TRACKING_FTRACE)) .setBufferSizeKb(FTRACE_BUFFER_SIZE); + // Record process names at startup into the metadata buffer. + config.addDataSourcesBuilder() + .getConfigBuilder() + .setName("linux.process_stats") + .setTargetBuffer(PROC_BUFFER) + .getProcessStatsConfigBuilder() + .setScanAllProcessesOnStart(true); + // Periodically record process information into the main buffer. + config.addDataSourcesBuilder() + .getConfigBuilder() + .setName("linux.process_stats") + .getProcessStatsConfigBuilder() + .setProcStatsPollMs(PROC_SCAN_PERIOD) + .setProcStatsCacheTtlMs(10 * PROC_SCAN_PERIOD); if (p.getCpuOrBuilder().getEnabled()) { - // Record process names. - config.addDataSourcesBuilder() - .getConfigBuilder() - .setName("linux.process_stats") - .getProcessStatsConfigBuilder() - .setScanAllProcessesOnStart(true); - ftrace.addAllFtraceEvents(Arrays.asList(CPU_BASE_FTRACE)); if (p.getCpuOrBuilder().getFrequency()) { ftrace.addAllFtraceEvents(Arrays.asList(CPU_FREQ_FTRACE)); @@ -308,9 +319,15 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( } } + // Buffer 0 (default): main buffer. + config.addBuffers(PerfettoConfig.TraceConfig.BufferConfig.newBuilder() + .setSizeKb((largeBuffer ? 8 : 1) * MAIN_BUFFER_SIZE) + .setFillPolicy(FillPolicy.DISCARD)); + // Buffer 1: Initial process metadata. config.addBuffers(PerfettoConfig.TraceConfig.BufferConfig.newBuilder() - .setSizeKb((largeBuffer ? 8 : 1) * BUFFER_SIZE) + .setSizeKb(PROC_BUFFER_SIZE) .setFillPolicy(FillPolicy.DISCARD)); + config.setFlushPeriodMs((int)SECONDS.toMillis(5)); return config; From 66ffdd7037aac4d01dde0325dd126745014ad633 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 08:17:34 -0800 Subject: [PATCH 0036/1218] Set the ftrace drain period in the trace config. Instructs the ftrace producer to drain the kernel ftrace buffer every 250ms. The buffer is 8Mb per CPU, which should be enough for than 1s. --- .../main/com/google/gapid/perfetto/views/TraceConfigDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 3b0e8b179c..444ba73560 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -94,6 +94,7 @@ public class TraceConfigDialog extends DialogBase { private static final int FTRACE_BUFFER_SIZE = 8192; private static final int PROC_SCAN_PERIOD = 2000; + private static final int FTRACE_DRAIN_PERIOD = 250; // These ftrace categories are always enabled to track process creation and ending. private static final String[] PROCESS_TRACKING_FTRACE = { @@ -217,6 +218,7 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .setName("linux.ftrace") .getFtraceConfigBuilder() .addAllFtraceEvents(Arrays.asList(PROCESS_TRACKING_FTRACE)) + .setDrainPeriodMs(FTRACE_DRAIN_PERIOD) .setBufferSizeKb(FTRACE_BUFFER_SIZE); // Record process names at startup into the metadata buffer. config.addDataSourcesBuilder() From b5f2fe204a17f3e48dedb6c0b763b4b1773e23d1 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 08:27:44 -0800 Subject: [PATCH 0037/1218] Disable the per-rail power counters. We don't currently support them in the UI. --- .../main/com/google/gapid/perfetto/views/TraceConfigDialog.java | 1 - 1 file changed, 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 444ba73560..15fa195bbf 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -298,7 +298,6 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .setName("android.power") .getAndroidPowerConfigBuilder() .setBatteryPollMs(p.getBatteryOrBuilder().getRate()) - .setCollectPowerRails(true) .addAllBatteryCounters(Arrays.asList(BAT_COUNTERS)); } From 9728353bd4e5509f6b89454fbf7a22f0052bf823 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 09:22:45 -0800 Subject: [PATCH 0038/1218] Enable the VulkanAPI producer if slices are selected. Not when counters are selected. --- .../com/google/gapid/perfetto/views/TraceConfigDialog.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 15fa195bbf..5775071a18 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -261,6 +261,9 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( config.addDataSourcesBuilder() .getConfigBuilder() .setName("gpu.renderstages"); + config.addDataSourcesBuilder() + .getConfigBuilder() + .setName("VulkanAPI"); } if (gpuCaps.getGpuCounterDescriptor().getSpecsCount() > 0 && gpu.getCounters() && gpu.getCounterIdsCount() > 0) { @@ -270,10 +273,6 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .getGpuCounterConfigBuilder() .setCounterPeriodNs(MILLISECONDS.toNanos(gpu.getCounterRate())); counters.addAllCounterIds(gpu.getCounterIdsList()); - - config.addDataSourcesBuilder() - .getConfigBuilder() - .setName("VulkanAPI"); } if (gpuCaps.getHasFrameLifecycle() && gpu.getSurfaceFlinger()) { config.addDataSourcesBuilder() From 364efe2e34aaacea62b30a0388bb5b0d9249302a Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 09:23:51 -0800 Subject: [PATCH 0039/1218] Write the trace into file if it's a long trace. --- .../perfetto/views/TraceConfigDialog.java | 23 +++++++++++++++---- .../com/google/gapid/views/TracerDialog.java | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 5775071a18..a77015aa85 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -33,7 +33,6 @@ import static com.google.gapid.widgets.Widgets.withLayoutData; import static com.google.gapid.widgets.Widgets.withMargin; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.logging.Level.WARNING; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -96,6 +95,11 @@ public class TraceConfigDialog extends DialogBase { private static final int PROC_SCAN_PERIOD = 2000; private static final int FTRACE_DRAIN_PERIOD = 250; + private static final int MAX_IN_MEM_DURATION = 15 * 1000; + private static final int FLUSH_PERIOD = 5000; + private static final int WRITE_PERIOD = 2000; + private static final long MAX_FILE_SIZE = 2l * 1024 * 1024 * 1024; + // These ftrace categories are always enabled to track process creation and ending. private static final String[] PROCESS_TRACKING_FTRACE = { "sched/sched_process_free", @@ -206,10 +210,10 @@ public static String getConfigSummary(Settings settings, Device.PerfettoCapabili } public static PerfettoConfig.TraceConfig.Builder getConfig( - Settings settings, Device.PerfettoCapability caps, String traceTarget) { + Settings settings, Device.PerfettoCapability caps, String traceTarget, int duration) { SettingsProto.PerfettoOrBuilder p = settings.perfetto(); if (p.getUseCustom()) { - return p.getCustomConfig().toBuilder(); + return p.getCustomConfig().toBuilder().setDurationMs(duration); } PerfettoConfig.TraceConfig.Builder config = PerfettoConfig.TraceConfig.newBuilder(); @@ -328,7 +332,13 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .setSizeKb(PROC_BUFFER_SIZE) .setFillPolicy(FillPolicy.DISCARD)); - config.setFlushPeriodMs((int)SECONDS.toMillis(5)); + config.setFlushPeriodMs(FLUSH_PERIOD); + config.setDurationMs(duration); + if (duration > MAX_IN_MEM_DURATION) { + config.setWriteIntoFile(true); + config.setFileWritePeriodMs(WRITE_PERIOD); + config.setMaxFileSizeBytes(MAX_FILE_SIZE); + } return config; } @@ -601,7 +611,10 @@ public BasicInputArea(Composite parent, Settings settings, Theme theme, withLayoutData(createLink(this, "Switch to advanced mode", e -> { // Remember the input thus far and turn it into a proto to be modified by the user. update(settings); - settings.writePerfetto().setCustomConfig(getConfig(settings, caps, "")); + settings.writePerfetto().setCustomConfig( + // Use a config that writes to file for custom by default. + getConfig(settings, caps, "", MAX_IN_MEM_DURATION + 1) + .clearDurationMs()); toAdvanced.run(); }), new GridData(SWT.END, SWT.BEGINNING, false, false)); diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index 2bcb5688c9..aea828629b 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -905,8 +905,8 @@ public TraceRequest getTraceRequest(Settings settings) { int durationMs = duration.getSelection() * 1000; // TODO: this isn't really unlimitted. durationMs = (durationMs == 0) ? (int)MINUTES.toMillis(10) : durationMs; - options.setPerfettoConfig(getConfig(settings, getPerfettoCaps(), traceTarget.getText()) - .setDurationMs(durationMs)); + options.setPerfettoConfig( + getConfig(settings, getPerfettoCaps(), traceTarget.getText(), durationMs)); } return new TraceRequest(output, options.build(), delay); From 0fd5081e467dbc1be65fcb3715e0ed517722d693 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 11 Feb 2020 09:29:13 -0800 Subject: [PATCH 0040/1218] Disable the command buffer recording CPU timing. It does not make sense to use this on Android, as we don't want to make the in-memory buffer that large. --- .../gapid/perfetto/views/TraceConfigDialog.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index a77015aa85..20cff6b33e 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -15,7 +15,6 @@ */ package com.google.gapid.perfetto.views; -import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.CpuTiming.CPU_TIMING_COMMAND_BUFFER; import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.CpuTiming.CPU_TIMING_DEVICE; import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.CpuTiming.CPU_TIMING_INSTANCE; import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.CpuTiming.CPU_TIMING_PHYSICAL_DEVICE; @@ -147,7 +146,6 @@ public class TraceConfigDialog extends DialogBase { private static final ImmutableMap VK_LABLES = ImmutableMap. builder() - .put(CPU_TIMING_COMMAND_BUFFER, "VkCommandBuffer") .put(CPU_TIMING_DEVICE, "VkDevice") .put(CPU_TIMING_INSTANCE, "VkInstance") .put(CPU_TIMING_PHYSICAL_DEVICE, "VkPhysicalDevice") @@ -304,12 +302,10 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( .addAllBatteryCounters(Arrays.asList(BAT_COUNTERS)); } - boolean largeBuffer = false; if (p.getVulkanOrBuilder().getEnabled()) { Device.VulkanProfilingLayers vkLayers = caps.getVulkanProfileLayers(); SettingsProto.Perfetto.VulkanOrBuilder vk = p.getVulkanOrBuilder(); if (vkLayers.getCpuTiming() && vk.getCpuTiming()) { - largeBuffer = true; config.addDataSourcesBuilder() .getConfigBuilder() .setName("VulkanCPUTiming") @@ -325,7 +321,7 @@ public static PerfettoConfig.TraceConfig.Builder getConfig( // Buffer 0 (default): main buffer. config.addBuffers(PerfettoConfig.TraceConfig.BufferConfig.newBuilder() - .setSizeKb((largeBuffer ? 8 : 1) * MAIN_BUFFER_SIZE) + .setSizeKb(MAIN_BUFFER_SIZE) .setFillPolicy(FillPolicy.DISCARD)); // Buffer 1: Initial process metadata. config.addBuffers(PerfettoConfig.TraceConfig.BufferConfig.newBuilder() @@ -433,7 +429,6 @@ private static class BasicInputArea extends Composite implements InputArea { private final Spinner batRate; private final Button vulkan; private final Button vulkanCPUTiming; - private final Button vulkanCPUTimingCommandBuffer; private final Button vulkanCPUTimingDevice; private final Button vulkanCPUTimingInstance; private final Button vulkanCPUTimingPhysicalDevice; @@ -569,15 +564,12 @@ public BasicInputArea(Composite parent, Settings settings, Theme theme, createCheckbox(cpuTimingGroup, "Device", hasCategory(sVk, CPU_TIMING_DEVICE)); vulkanCPUTimingQueue = createCheckbox(cpuTimingGroup, "Queue", hasCategory(sVk, CPU_TIMING_QUEUE)); - vulkanCPUTimingCommandBuffer = createCheckbox( - cpuTimingGroup, "CommandBuffer", hasCategory(sVk, CPU_TIMING_COMMAND_BUFFER)); } else { vulkanCPUTiming = null; vulkanCPUTimingInstance = null; vulkanCPUTimingPhysicalDevice = null; vulkanCPUTimingDevice = null; vulkanCPUTimingQueue = null; - vulkanCPUTimingCommandBuffer = null; } if (caps.getVulkanProfileLayers().getMemoryTracker()) { vulkanMemoryTracking = createCheckbox( @@ -602,7 +594,6 @@ public BasicInputArea(Composite parent, Settings settings, Theme theme, vulkanCPUTimingPhysicalDevice = null; vulkanCPUTimingDevice = null; vulkanCPUTimingQueue = null; - vulkanCPUTimingCommandBuffer = null; vulkanMemoryTracking = null; vulkanMemoryTrackingDevice = null; vulkanMemoryTrackingDriver = null; @@ -674,7 +665,6 @@ public void update(Settings settings) { if (vulkanCPUTiming != null) { sVk.setCpuTiming(vulkanCPUTiming.getSelection()); sVk.clearCpuTimingCategories(); - addCategory(vulkanCPUTimingCommandBuffer, sVk, CPU_TIMING_COMMAND_BUFFER); addCategory(vulkanCPUTimingDevice, sVk, CPU_TIMING_DEVICE); addCategory(vulkanCPUTimingPhysicalDevice, sVk, CPU_TIMING_PHYSICAL_DEVICE); addCategory(vulkanCPUTimingInstance, sVk, CPU_TIMING_INSTANCE); @@ -750,7 +740,6 @@ private void updateVulkan() { vulkanCPUTimingPhysicalDevice.setEnabled(enabled); vulkanCPUTimingDevice.setEnabled(enabled); vulkanCPUTimingQueue.setEnabled(enabled); - vulkanCPUTimingCommandBuffer.setEnabled(enabled); } if (vulkanMemoryTracking != null) { vulkanMemoryTracking.setEnabled(vkEnabled); From ae3925cc00cb1e7884b414feb6fdb845f2b78187 Mon Sep 17 00:00:00 2001 From: zakerinasab Date: Tue, 11 Feb 2020 14:56:21 -0500 Subject: [PATCH 0041/1218] Add Vulkan version annotation to the api files (#3774) * Add Vulkan version annotation to the api files This change adds Vulkan version annotation to the api files in gapis/api/vulkan/api. This allows to distinguish between Vulkan releases if a third party user had to use an older API version than GAPID. --- gapis/api/vulkan/api/buffer.api | 1 + gapis/api/vulkan/api/command_buffer_control.api | 1 + gapis/api/vulkan/api/descriptor.api | 1 + gapis/api/vulkan/api/image.api | 5 ++++- gapis/api/vulkan/api/physical_device.api | 2 +- .../api/properties_features_requirements.api | 14 ++++++++++++++ gapis/api/vulkan/api/query_pool.api | 2 +- gapis/api/vulkan/api/renderpass_framebuffer.api | 2 +- gapis/api/vulkan/api/synchronization.api | 3 +++ 9 files changed, 27 insertions(+), 4 deletions(-) diff --git a/gapis/api/vulkan/api/buffer.api b/gapis/api/vulkan/api/buffer.api index 8802587d4b..0ffc9c160e 100644 --- a/gapis/api/vulkan/api/buffer.api +++ b/gapis/api/vulkan/api/buffer.api @@ -333,6 +333,7 @@ sub void BindBufferMemory2( } } +@since("1.1") @indirect("VkDevice") cmd VkResult vkBindBufferMemory2( VkDevice device, diff --git a/gapis/api/vulkan/api/command_buffer_control.api b/gapis/api/vulkan/api/command_buffer_control.api index 94f6523904..815f762805 100644 --- a/gapis/api/vulkan/api/command_buffer_control.api +++ b/gapis/api/vulkan/api/command_buffer_control.api @@ -691,6 +691,7 @@ sub void TrimCommandPool( if !(commandPool in CommandPools) { vkErrorInvalidCommandPool(commandPool) } } +@since("1.1") @indirect("VkDevice") cmd void vkTrimCommandPool( VkDevice device, diff --git a/gapis/api/vulkan/api/descriptor.api b/gapis/api/vulkan/api/descriptor.api index 0d08ee5156..5ebfedecd5 100644 --- a/gapis/api/vulkan/api/descriptor.api +++ b/gapis/api/vulkan/api/descriptor.api @@ -963,6 +963,7 @@ sub void GetDescriptorSetLayoutSupport( } } +@since("1.1") @indirect("VkDevice") cmd void vkGetDescriptorSetLayoutSupport( VkDevice device, diff --git a/gapis/api/vulkan/api/image.api b/gapis/api/vulkan/api/image.api index a7cc0f02d0..d2b1f958de 100644 --- a/gapis/api/vulkan/api/image.api +++ b/gapis/api/vulkan/api/image.api @@ -885,6 +885,7 @@ sub void BindImageMemory2( } } +@since("1.1") @indirect("VkDevice") cmd VkResult vkBindImageMemory2( VkDevice device, @@ -941,6 +942,7 @@ sub void CreateSamplerYcbcrConversion( SamplerYcbcrConversions[handle] = object } +@since("1.1") @threadSafety("system") @indirect("VkDevice") cmd VkResult vkCreateSamplerYcbcrConversion( @@ -963,6 +965,7 @@ sub void DestroySamplerYcbcrConversion( } } +@since("1.1") @threadSafety("system") @indirect("VkDevice") cmd void vkDestroySamplerYcbcrConversion( @@ -1033,4 +1036,4 @@ sub ref!ImagePlaneMemoryInfo getImagePlaneMemoryInfo(ref!ImageObject img, VkImag default: img.PlaneMemoryInfo[as!VkImageAspectFlagBits(0)] } -} \ No newline at end of file +} diff --git a/gapis/api/vulkan/api/physical_device.api b/gapis/api/vulkan/api/physical_device.api index cb1c498b16..3f03a9a04f 100644 --- a/gapis/api/vulkan/api/physical_device.api +++ b/gapis/api/vulkan/api/physical_device.api @@ -133,4 +133,4 @@ cmd VkResult vkEnumeratePhysicalDevices( @internal class Maintenance3Properties { u32 MaxPerSetDescriptors VkDeviceSize MaxMemoryAllocationSize -} \ No newline at end of file +} diff --git a/gapis/api/vulkan/api/properties_features_requirements.api b/gapis/api/vulkan/api/properties_features_requirements.api index 35f0c9d7e5..24378487d6 100644 --- a/gapis/api/vulkan/api/properties_features_requirements.api +++ b/gapis/api/vulkan/api/properties_features_requirements.api @@ -317,6 +317,7 @@ cmd void vkGetImageSparseMemoryRequirements( // Instance // ////////////// +@since("1.1") @threadSafety("system") cmd VkResult vkEnumerateInstanceVersion( u32* pApiVersion) { @@ -444,6 +445,7 @@ sub void GetPhysicalDeviceFeatures2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceFeatures2( @@ -468,6 +470,7 @@ sub void GetPhysicalDeviceFormatProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceFormatProperties2( @@ -526,6 +529,7 @@ sub void GetPhysicalDeviceImageFormatProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd VkResult vkGetPhysicalDeviceImageFormatProperties2( @@ -674,6 +678,7 @@ sub void GetPhysicalDeviceProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceProperties2( @@ -700,6 +705,7 @@ sub void GetPhysicalDeviceMemoryProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceMemoryProperties2( @@ -745,6 +751,7 @@ sub void GetPhysicalDeviceSparseImageFormatProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceSparseImageFormatProperties2( @@ -783,6 +790,7 @@ sub void GetPhysicalDeviceQueueFamilyProperties2( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceQueueFamilyProperties2( @@ -833,6 +841,7 @@ sub void GetPhysicalDeviceExternalBufferProperties( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceExternalBufferProperties( @@ -883,6 +892,7 @@ sub void GetPhysicalDeviceExternalSemaphoreProperties( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceExternalSemaphoreProperties( @@ -933,6 +943,7 @@ sub void GetPhysicalDeviceExternalFenceProperties( } } +@since("1.1") @threadSafety("system") @indirect("VkPhysicalDevice", "VkInstance") cmd void vkGetPhysicalDeviceExternalFenceProperties( @@ -996,6 +1007,7 @@ sub void GetBufferMemoryRequirements2( } } +@since("1.1") @threadSafety("system") @indirect("VkDevice") cmd void vkGetBufferMemoryRequirements2( @@ -1073,6 +1085,7 @@ sub void GetImageMemoryRequirements2( } } +@since("1.1") @threadSafety("system") @indirect("VkDevice") cmd void vkGetImageMemoryRequirements2( @@ -1123,6 +1136,7 @@ sub void GetImageSparseMemoryRequirements2( } } +@since("1.1") @threadSafety("system") @indirect("VkDevice") cmd void vkGetImageSparseMemoryRequirements2( diff --git a/gapis/api/vulkan/api/query_pool.api b/gapis/api/vulkan/api/query_pool.api index bf7442afc2..6b2cea39b0 100644 --- a/gapis/api/vulkan/api/query_pool.api +++ b/gapis/api/vulkan/api/query_pool.api @@ -413,4 +413,4 @@ sub u32 getResultCount(ref!QueryPoolObject pool) { case VK_QUERY_TYPE_TIMESTAMP: as!u32(1) } -} \ No newline at end of file +} diff --git a/gapis/api/vulkan/api/renderpass_framebuffer.api b/gapis/api/vulkan/api/renderpass_framebuffer.api index 2261d2b132..4d3b161416 100644 --- a/gapis/api/vulkan/api/renderpass_framebuffer.api +++ b/gapis/api/vulkan/api/renderpass_framebuffer.api @@ -547,4 +547,4 @@ sub void useRenderPass() { @internal class InputAttachmentAspectInfo{ @unused dense_map!(u32, VkInputAttachmentAspectReference) AspectReferences -} \ No newline at end of file +} diff --git a/gapis/api/vulkan/api/synchronization.api b/gapis/api/vulkan/api/synchronization.api index 2bea46af7d..8badc4b64e 100644 --- a/gapis/api/vulkan/api/synchronization.api +++ b/gapis/api/vulkan/api/synchronization.api @@ -215,6 +215,7 @@ cmd void vkDestroySemaphore( } // Partial implementation +@since("1.2") @threadSafety("system") @indirect("VkDevice") cmd VkResult vkSignalSemaphore( @@ -224,6 +225,7 @@ cmd VkResult vkSignalSemaphore( } // Partial implementation +@since("1.2") @threadSafety("system") @indirect("VkDevice") cmd VkResult vkWaitSemaphores( @@ -234,6 +236,7 @@ cmd VkResult vkWaitSemaphores( } // Partial implementation +@since("1.2") @threadSafety("system") @indirect("VkDevice") cmd VkResult vkGetSemaphoreCounterValue( From 47923fb54567d89debf00e8943ccb49238dbd449 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 05:43:23 -0800 Subject: [PATCH 0042/1218] Remove the unused PerfettoConfig class. --- gapic/src/main/com/google/gapid/Main.java | 2 - .../google/gapid/perfetto/PerfettoConfig.java | 90 ------------------- 2 files changed, 92 deletions(-) delete mode 100644 gapic/src/main/com/google/gapid/perfetto/PerfettoConfig.java diff --git a/gapic/src/main/com/google/gapid/Main.java b/gapic/src/main/com/google/gapid/Main.java index 13f2fabb2c..f99603cd8e 100644 --- a/gapic/src/main/com/google/gapid/Main.java +++ b/gapic/src/main/com/google/gapid/Main.java @@ -26,7 +26,6 @@ import com.google.gapid.models.Follower; import com.google.gapid.models.Models; import com.google.gapid.models.Settings; -import com.google.gapid.perfetto.PerfettoConfig; import com.google.gapid.perfetto.canvas.PanelCanvas; import com.google.gapid.server.GapiPaths; import com.google.gapid.server.GapisProcess; @@ -209,7 +208,6 @@ private static interface ShellRunnable { Logging.logDir, Follower.logFollowRequests, Server.useCache, - PerfettoConfig.perfettoConfig, PanelCanvas.showRedraws, }; } diff --git a/gapic/src/main/com/google/gapid/perfetto/PerfettoConfig.java b/gapic/src/main/com/google/gapid/perfetto/PerfettoConfig.java deleted file mode 100644 index 18ad598527..0000000000 --- a/gapic/src/main/com/google/gapid/perfetto/PerfettoConfig.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.gapid.perfetto; - -import static java.util.logging.Level.WARNING; - -import com.google.common.collect.ImmutableList; -import com.google.gapid.server.GapiPaths; -import com.google.gapid.util.Flags; -import com.google.gapid.util.Flags.Flag; -import com.google.protobuf.TextFormat; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.function.Supplier; -import java.util.logging.Logger; - -public class PerfettoConfig { - public static final Flag perfettoConfig = Flags.value("perfetto", "", - "Path to a file containing a Perfetto config proto in text format. " + - "Specifying this flag will enable the System Profile UI features"); - - private static final Logger LOG = Logger.getLogger(PerfettoConfig.class.getName()); - private static final PerfettoConfig MISSING = new PerfettoConfig(null); - - private final perfetto.protos.PerfettoConfig.TraceConfig config; - - public PerfettoConfig(perfetto.protos.PerfettoConfig.TraceConfig config) { - this.config = config; - } - - // This call is expensive as it re-reads the perfetto config file, in order to enable perfetto - // configuration changes without having to restart GAPID. - public static synchronized PerfettoConfig get() { - return ImmutableList.>of( - () -> { - String path = perfettoConfig.get(); - return "".equals(path) ? null : new File(path); - }, - GapiPaths.get()::perfettoConfig - ).stream() - .map(dir -> checkForConfig(dir.get())) - .filter(PerfettoConfig::shouldUse) - .findFirst() - .orElse(MISSING); - } - - public boolean hasConfig() { - return config != null; - } - - public perfetto.protos.PerfettoConfig.TraceConfig getConfig() { - return config; - } - - private static boolean shouldUse(PerfettoConfig config) { - return config != null && config.hasConfig(); - } - - private static PerfettoConfig checkForConfig(File file) { - if (file == null || !file.isFile()) { - return null; - } - try (Reader in = new InputStreamReader(new FileInputStream(file))) { - perfetto.protos.PerfettoConfig.TraceConfig.Builder config = - perfetto.protos.PerfettoConfig.TraceConfig.newBuilder(); - TextFormat.merge(in, config); - return new PerfettoConfig(config.build()); - } catch (IOException e) { - LOG.log(WARNING, "Failed to read Perfetto config from " + file, e); - } - return null; - } -} From 81384c0d40c7d84da669e4c682f57e6ce7a5a59e Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Wed, 12 Feb 2020 19:00:32 +0000 Subject: [PATCH 0043/1218] Downgrade to gcc8 on Linux builds (#37) Building with gcc9 creates a runtime dependency on GLIBCXX_3.4.26, which is not yet widely available. Bug: none --- kokoro/linux-test/test.sh | 4 ++-- kokoro/linux/build.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kokoro/linux-test/test.sh b/kokoro/linux-test/test.sh index 0ecbf2f0fc..28173f80ce 100755 --- a/kokoro/linux-test/test.sh +++ b/kokoro/linux-test/test.sh @@ -29,8 +29,8 @@ bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel sudo rm /etc/apt/sources.list.d/cuda.list* sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get -q update -sudo apt-get -qy install gcc-9 g++-9 -export CC=/usr/bin/gcc-9 +sudo apt-get -qy install gcc-8 g++-8 +export CC=/usr/bin/gcc-8 cd $SRC BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index d7efc8492b..70b65d7e98 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -25,12 +25,12 @@ curl -L -k -O -s https://github.com/bazelbuild/bazel/releases/download/${BAZEL_V mkdir bazel bash bazel-${BAZEL_VERSION}-installer-linux-x86_64.sh --prefix=$PWD/bazel -# Get GCC 9 +# Get GCC 8 sudo rm /etc/apt/sources.list.d/cuda.list* sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get -q update -sudo apt-get -qy install gcc-9 g++-9 -export CC=/usr/bin/gcc-9 +sudo apt-get -qy install gcc-8 g++-8 +export CC=/usr/bin/gcc-8 # Get the Android NDK curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip From 709dc8b0bf1383d9ceec40954a5557c799f9d5a6 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Wed, 12 Feb 2020 11:02:30 -0800 Subject: [PATCH 0044/1218] Have the enum tooltips display in Pipeline View (#30) Last PR only formatted the text. Note: Might not work in Windows for now --- .../com/google/gapid/views/PipelineView.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index be60ca5513..bc2bebc83c 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -378,8 +378,9 @@ private Composite createStage(Composite parent, API.Stage currentStage) { withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> models.follower.onFollow(dv.link)), new GridData(SWT.LEFT, SWT.CENTER, true, true)); } else { - withLayoutData( createLabel(valueComposite, dv.displayValue), + Label valueLabel = withLayoutData( createLabel(valueComposite, dv.displayValue), new GridData(SWT.LEFT, SWT.CENTER, true, true)); + valueLabel.setToolTipText(dv.tooltipValue); } } @@ -428,14 +429,18 @@ private Composite createStage(Composite parent, API.Stage currentStage) { groupTable.setContentProvider(ArrayContentProvider.getInstance()); + ColumnViewerToolTipSupport.enableFor(groupTable); + for (int i = 0; i < dataGroup.getTable().getHeadersCount(); i++) { int col = i; TableViewerColumn tvc = createTableColumn(groupTable, dataGroup.getTable().getHeaders(i)); StyledCellLabelProvider cellLabelProvider = new StyledCellLabelProvider() { + DataValue dv; + @Override public void update(ViewerCell cell) { - DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); + dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); cell.setText(dv.displayValue); @@ -448,6 +453,15 @@ public void update(ViewerCell cell) { super.update(cell); } + + @Override + public String getToolTipText(Object element) { + if (dv != null) { + return dv.tooltipValue; + } else { + return null; + } + } }; tvc.setLabelProvider(cellLabelProvider); From 2c0ba5fd96d4dd2cd593d77a251824dee3295c50 Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Wed, 12 Feb 2020 15:13:58 -0800 Subject: [PATCH 0045/1218] Create transform to generate command links for slices (#19) --- gapis/api/cmd_id.go | 6 ++ gapis/api/vulkan/BUILD.bazel | 1 + gapis/api/vulkan/replay.go | 21 +++--- gapis/api/vulkan/slice_command_mapper.go | 71 ++++++++++++++++++++ gapis/service/service.proto | 4 +- gapis/trace/BUILD.bazel | 1 + gapis/trace/android/BUILD.bazel | 2 + gapis/trace/android/adreno/BUILD.bazel | 2 + gapis/trace/android/adreno/profiling_data.go | 57 ++++++++++++++-- gapis/trace/android/trace.go | 6 +- gapis/trace/desktop/BUILD.bazel | 2 + gapis/trace/desktop/trace.go | 4 +- gapis/trace/trace.go | 5 +- gapis/trace/tracer/BUILD.bazel | 2 + gapis/trace/tracer/tracer.go | 4 +- 15 files changed, 167 insertions(+), 21 deletions(-) create mode 100644 gapis/api/vulkan/slice_command_mapper.go diff --git a/gapis/api/cmd_id.go b/gapis/api/cmd_id.go index ea36372102..7be710eb8c 100644 --- a/gapis/api/cmd_id.go +++ b/gapis/api/cmd_id.go @@ -49,3 +49,9 @@ func (id CmdID) String() string { return fmt.Sprintf("%v", uint64(id)) } } + +// TODO(apbodnar) find a more appropriate place for this +type CommandSubmissionKey struct { + SubmissionOrder uint64 + CommandBuffer int64 +} diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel index 73209f925f..626eb3f9c5 100644 --- a/gapis/api/vulkan/BUILD.bazel +++ b/gapis/api/vulkan/BUILD.bazel @@ -93,6 +93,7 @@ go_library( "set_primitive_count_to_one.go", "simplify_fragment_shader.go", "simplify_sampling.go", + "slice_command_mapper.go", "state.go", "state_rebuilder.go", "vulkan.go", diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 12348c52df..118cf89e1b 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -828,11 +828,12 @@ func uniqueConfig() replay.Config { } type profileRequest struct { - overrides *path.OverrideConfig - traceOptions *service.TraceOptions - handler *replay.SignalHandler - buffer *bytes.Buffer - mappings *map[uint64][]service.VulkanHandleMappingItem + overrides *path.OverrideConfig + traceOptions *service.TraceOptions + handler *replay.SignalHandler + buffer *bytes.Buffer + handleMappings *map[uint64][]service.VulkanHandleMappingItem + submissionIds *map[api.CommandSubmissionKey][]uint64 } func (a API) GetInitialPayload(ctx context.Context, @@ -1065,9 +1066,10 @@ func (a API) Replay( profile.AddResult(rr.Result) makeReadable.imagesOnly = true optimize = false + transforms.Add(newSliceCommandMapper(req.submissionIds)) transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer)) transforms.Add(&profilingLayers{}) - transforms.Add(replay.NewMappingExporter(ctx, req.mappings)) + transforms.Add(replay.NewMappingExporter(ctx, req.handleMappings)) if req.overrides.GetViewportSize() { transforms.Add(minimizeViewport(ctx)) } @@ -1268,11 +1270,12 @@ func (a API) Profile( c := uniqueConfig() handler := replay.NewSignalHandler() var buffer bytes.Buffer - mappings := make(map[uint64][]service.VulkanHandleMappingItem) - r := profileRequest{overrides, traceOptions, handler, &buffer, &mappings} + handleMappings := make(map[uint64][]service.VulkanHandleMappingItem) + submissionIds := make(map[api.CommandSubmissionKey][]uint64) + r := profileRequest{overrides, traceOptions, handler, &buffer, &handleMappings, &submissionIds} _, err := mgr.Replay(ctx, intent, c, r, a, hints, true) handler.DoneSignal.Wait(ctx) - d, err := trace.ProcessProfilingData(ctx, intent.Device, &buffer, &mappings) + d, err := trace.ProcessProfilingData(ctx, intent.Device, intent.Capture, &buffer, &handleMappings, &submissionIds) return d, err } diff --git a/gapis/api/vulkan/slice_command_mapper.go b/gapis/api/vulkan/slice_command_mapper.go new file mode 100644 index 0000000000..0204191a5a --- /dev/null +++ b/gapis/api/vulkan/slice_command_mapper.go @@ -0,0 +1,71 @@ +// Copyright (C) 2020 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package vulkan + +import ( + "context" + + "github.com/google/gapid/core/log" + "github.com/google/gapid/gapis/api" + "github.com/google/gapid/gapis/api/transform" +) + +type sliceCommandMapper struct { + subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64 + submissionCount uint64 +} + +func (t *sliceCommandMapper) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { + ctx = log.Enter(ctx, "Slice Command Mapper") + s := out.State() + + switch cmd := cmd.(type) { + case *VkQueueSubmit: + if id.IsReal() { + submitInfoCount := cmd.SubmitCount() + submitInfos := cmd.pSubmits.Slice(0, uint64(submitInfoCount), s.MemoryLayout).MustRead(ctx, cmd, s, nil) + for i := uint32(0); i < submitInfoCount; i++ { + si := submitInfos[i] + cmdBufferCount := si.CommandBufferCount() + cmdBuffers := si.PCommandBuffers().Slice(0, uint64(cmdBufferCount), s.MemoryLayout).MustRead(ctx, cmd, s, nil) + for j := uint32(0); j < cmdBufferCount; j++ { + commandIndex := []uint64{uint64(id), uint64(i), uint64(j), 0} + key := api.CommandSubmissionKey{SubmissionOrder: t.submissionCount, CommandBuffer: int64(cmdBuffers[j])} + (*t.subCommandIndicesMap)[key] = commandIndex + } + } + t.submissionCount++ + } + return out.MutateAndWrite(ctx, id, cmd) + default: + return out.MutateAndWrite(ctx, id, cmd) + } + return nil +} + +func (t *sliceCommandMapper) PreLoop(ctx context.Context, out transform.Writer) { + out.NotifyPreLoop(ctx) +} +func (t *sliceCommandMapper) PostLoop(ctx context.Context, out transform.Writer) { + out.NotifyPostLoop(ctx) +} +func (t *sliceCommandMapper) Flush(ctx context.Context, out transform.Writer) error { return nil } +func (t *sliceCommandMapper) BuffersCommands() bool { + return false +} + +func newSliceCommandMapper(subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64) *sliceCommandMapper { + return &sliceCommandMapper{subCommandIndicesMap: subCommandIndicesMap, submissionCount: 0} +} diff --git a/gapis/service/service.proto b/gapis/service/service.proto index 9a62d03cf1..cc582a8bab 100644 --- a/gapis/service/service.proto +++ b/gapis/service/service.proto @@ -1310,7 +1310,7 @@ message ProfilingData { repeated Extra extras = 5; int32 trackId = 6; // references Track.id - int32 group = 7; // references Group.id + int32 groupId = 7; // references Group.id } message Track { @@ -1321,7 +1321,7 @@ message ProfilingData { message Group { int32 id = 1; int32 parent = 2; // references Group.id - path.Commands link = 3; + path.Command link = 3; } repeated Slice slices = 1; diff --git a/gapis/trace/BUILD.bazel b/gapis/trace/BUILD.bazel index 18382a5e80..35adb17332 100644 --- a/gapis/trace/BUILD.bazel +++ b/gapis/trace/BUILD.bazel @@ -33,6 +33,7 @@ go_library( "//core/os/device:go_default_library", "//core/os/device/bind:go_default_library", "//gapii/client:go_default_library", + "//gapis/api:go_default_library", "//gapis/config:go_default_library", "//gapis/service:go_default_library", "//gapis/service/path:go_default_library", diff --git a/gapis/trace/android/BUILD.bazel b/gapis/trace/android/BUILD.bazel index 0b0693f926..33ae2d03f7 100644 --- a/gapis/trace/android/BUILD.bazel +++ b/gapis/trace/android/BUILD.bazel @@ -33,9 +33,11 @@ go_library( "//gapidapk:go_default_library", "//gapidapk/pkginfo:go_default_library", "//gapii/client:go_default_library", + "//gapis/api:go_default_library", "//gapis/perfetto:go_default_library", "//gapis/perfetto/android:go_default_library", "//gapis/service:go_default_library", + "//gapis/service/path:go_default_library", "//gapis/trace/android/adreno:go_default_library", "//gapis/trace/android/validate:go_default_library", "//gapis/trace/tracer:go_default_library", diff --git a/gapis/trace/android/adreno/BUILD.bazel b/gapis/trace/android/adreno/BUILD.bazel index f0a12ddcbf..0c2ae7a287 100644 --- a/gapis/trace/android/adreno/BUILD.bazel +++ b/gapis/trace/android/adreno/BUILD.bazel @@ -11,9 +11,11 @@ go_library( deps = [ "//core/log:go_default_library", "//core/os/device:go_default_library", + "//gapis/api:go_default_library", "//gapis/perfetto:go_default_library", "//gapis/perfetto/service:go_default_library", "//gapis/service:go_default_library", + "//gapis/service/path:go_default_library", "//gapis/trace/android/validate:go_default_library", ], ) diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index 9baefbbc6c..8c93cf50d7 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -20,9 +20,11 @@ import ( "github.com/google/gapid/core/log" "github.com/google/gapid/core/os/device" + "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/perfetto" perfetto_service "github.com/google/gapid/gapis/perfetto/service" "github.com/google/gapid/gapis/service" + "github.com/google/gapid/gapis/service/path" ) var ( @@ -32,14 +34,16 @@ var ( "ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage'" argsQueryFmt = "" + "SELECT key, string_value FROM args WHERE args.arg_set_id = %d" + queueSubmitQuery = "" + + "SELECT submission_id FROM gpu_slice s JOIN track t ON s.track_id = t.id WHERE s.name = 'vkQueueSubmit' AND t.name = 'Vulkan Events' ORDER BY submission_id" counterTracksQuery = "" + "SELECT id, name, unit, description FROM gpu_counter_track ORDER BY id" countersQueryFmt = "" + "SELECT ts, value FROM counter c WHERE c.track_id = %d ORDER BY ts" ) -func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) { - slices, err := processGpuSlices(ctx, processor, handleMapping) +func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) { + slices, err := processGpuSlices(ctx, processor, capture, handleMapping, submissionIds) if err != nil { log.Err(ctx, err, "Failed to get GPU slices") } @@ -50,17 +54,31 @@ func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, de return &service.ProfilingData{Slices: slices, Counters: counters}, nil } -func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData_GpuSlices, error) { +func processGpuSlices(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData_GpuSlices, error) { slicesQueryResult, err := processor.Query(slicesQuery) if err != nil { return nil, log.Errf(ctx, err, "SQL query failed: %v", slicesQuery) } + queueSubmitQueryResult, err := processor.Query(queueSubmitQuery) + if err != nil { + return nil, log.Errf(ctx, err, "SQL query failed: %v", queueSubmitQuery) + } + queueSubmitColumns := queueSubmitQueryResult.GetColumns() + queueSubmitIds := queueSubmitColumns[0].GetLongValues() + submissionOrdering := make(map[int64]uint64) + + for i, v := range queueSubmitIds { + submissionOrdering[v] = uint64(i) + } + trackIdCache := make(map[int64]bool) argsQueryCache := make(map[int64]*perfetto_service.QueryResult) slicesColumns := slicesQueryResult.GetColumns() numSliceRows := slicesQueryResult.GetNumRecords() slices := make([]*service.ProfilingData_GpuSlices_Slice, numSliceRows) + groups := make([]*service.ProfilingData_GpuSlices_Group, 0) + groupIds := make([]int32, numSliceRows) var tracks []*service.ProfilingData_GpuSlices_Track // Grab all the column values. Depends on the order of columns selected in slicesQuery @@ -91,8 +109,37 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handle } } - frameIds := slicesColumns[2].GetLongValues() submissionIds := slicesColumns[3].GetLongValues() + currentSubId := int64(-1) + subCommandGroupMap := make(map[api.CommandSubmissionKey]bool) + for i, v := range submissionIds { + if v != currentSubId { + currentSubId = v + // We'll never need the previous keys again + subCommandGroupMap = make(map[api.CommandSubmissionKey]bool) + } + subOrder, ok := submissionOrdering[v] + if ok { + cb := commandBuffers[i] + key := api.CommandSubmissionKey{SubmissionOrder: subOrder, CommandBuffer: cb} + if _, ok := subCommandGroupMap[key]; !ok { + if indices, ok := (*subCommandIndicesMap)[key]; ok { + group := &service.ProfilingData_GpuSlices_Group{ + Id: int32(len(groups)), + Link: &path.Command{Capture: capture, Indices: indices}, + } + groups = append(groups, group) + subCommandGroupMap[key] = true + } + } + } else { + log.W(ctx, "Encountered submission ID mismatch %v", v) + } + + groupIds[i] = int32(len(groups)) - 1 + } + + frameIds := slicesColumns[2].GetLongValues() hwQueueIds := slicesColumns[4].GetLongValues() timestamps := slicesColumns[6].GetLongValues() durations := slicesColumns[7].GetLongValues() @@ -156,6 +203,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handle Depth: int32(depths[i]), Extras: extras, TrackId: int32(trackIds[i]), + GroupId: groupIds[i], } if _, ok := trackIdCache[trackIds[i]]; !ok { @@ -170,6 +218,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, handle return &service.ProfilingData_GpuSlices{ Slices: slices, Tracks: tracks, + Groups: groups, }, nil } diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go index a97c5c7a8c..a826c9e656 100644 --- a/gapis/trace/android/trace.go +++ b/gapis/trace/android/trace.go @@ -28,6 +28,8 @@ import ( "strings" "time" + "github.com/google/gapid/gapis/api" + "github.com/google/gapid/gapis/service/path" perfetto_pb "protos/perfetto/config" "github.com/golang/protobuf/proto" @@ -118,7 +120,7 @@ func (t *androidTracer) GetDevice() bind.Device { return t.b } -func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, handleMappings *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) { +func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMappings *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) { // Load Perfetto trace and create trace processor. rawData := make([]byte, buffer.Len()) _, err := buffer.Read(rawData) @@ -135,7 +137,7 @@ func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes. desc := conf.GetPerfettoCapability().GetGpuProfiling().GetGpuCounterDescriptor() gpuName := gpu.GetName() if strings.Contains(gpuName, "Adreno") { - return adreno.ProcessProfilingData(ctx, processor, desc, handleMappings) + return adreno.ProcessProfilingData(ctx, processor, capture, desc, handleMappings, submissionIds) } return nil, log.Errf(ctx, nil, "Failed to process Perfetto trace for device %v", gpuName) } diff --git a/gapis/trace/desktop/BUILD.bazel b/gapis/trace/desktop/BUILD.bazel index c4dcbd5c58..a74f8f9758 100644 --- a/gapis/trace/desktop/BUILD.bazel +++ b/gapis/trace/desktop/BUILD.bazel @@ -35,8 +35,10 @@ go_library( "//core/text:go_default_library", "//core/vulkan/loader:go_default_library", "//gapii/client:go_default_library", + "//gapis/api:go_default_library", "//gapis/perfetto/desktop:go_default_library", "//gapis/service:go_default_library", + "//gapis/service/path:go_default_library", "//gapis/trace/tracer:go_default_library", ], ) diff --git a/gapis/trace/desktop/trace.go b/gapis/trace/desktop/trace.go index f3e1e7bac6..4d09b85058 100644 --- a/gapis/trace/desktop/trace.go +++ b/gapis/trace/desktop/trace.go @@ -31,8 +31,10 @@ import ( "github.com/google/gapid/core/os/process" "github.com/google/gapid/core/vulkan/loader" gapii "github.com/google/gapid/gapii/client" + "github.com/google/gapid/gapis/api" perfetto "github.com/google/gapid/gapis/perfetto/desktop" "github.com/google/gapid/gapis/service" + gapis_path "github.com/google/gapid/gapis/service/path" "github.com/google/gapid/gapis/trace/tracer" ) @@ -48,7 +50,7 @@ func (t *DesktopTracer) GetDevice() bind.Device { return t.b } -func (t *DesktopTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) { +func (t *DesktopTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *gapis_path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) { return nil, log.Err(ctx, nil, "Desktop replay profiling is unsupported.") } diff --git a/gapis/trace/trace.go b/gapis/trace/trace.go index 4b985607e0..cc60b21405 100644 --- a/gapis/trace/trace.go +++ b/gapis/trace/trace.go @@ -26,6 +26,7 @@ import ( "github.com/google/gapid/core/event/task" "github.com/google/gapid/core/log" gapii "github.com/google/gapid/gapii/client" + "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/config" "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" @@ -106,12 +107,12 @@ func TraceConfiguration(ctx context.Context, device *path.Device) (*service.Devi return t.TraceConfiguration(ctx) } -func ProcessProfilingData(ctx context.Context, device *path.Device, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) { +func ProcessProfilingData(ctx context.Context, device *path.Device, capture *path.Capture, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) { t, err := GetTracer(ctx, device) if err != nil { return nil, err } - return t.ProcessProfilingData(ctx, buffer, handleMapping) + return t.ProcessProfilingData(ctx, buffer, capture, handleMapping, submissionIds) } func Validate(ctx context.Context, device *path.Device) error { diff --git a/gapis/trace/tracer/BUILD.bazel b/gapis/trace/tracer/BUILD.bazel index d1fc85c4e5..5b1ad5b31f 100644 --- a/gapis/trace/tracer/BUILD.bazel +++ b/gapis/trace/tracer/BUILD.bazel @@ -28,6 +28,8 @@ go_library( "//core/event/task:go_default_library", "//core/os/device/bind:go_default_library", "//gapii/client:go_default_library", + "//gapis/api:go_default_library", "//gapis/service:go_default_library", + "//gapis/service/path:go_default_library", ], ) diff --git a/gapis/trace/tracer/tracer.go b/gapis/trace/tracer/tracer.go index 89e579ffef..9b21930a1a 100644 --- a/gapis/trace/tracer/tracer.go +++ b/gapis/trace/tracer/tracer.go @@ -24,7 +24,9 @@ import ( "github.com/google/gapid/core/event/task" "github.com/google/gapid/core/os/device/bind" gapii "github.com/google/gapid/gapii/client" + "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/service" + "github.com/google/gapid/gapis/service/path" ) // TraceTargetTreeNode represents a node in the traceable application @@ -72,7 +74,7 @@ type Tracer interface { GetDevice() bind.Device // ProcessProfilingData takes a buffer for a Perfetto trace and translates it into // a ProfilingData - ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem) (*service.ProfilingData, error) + ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) // Validate validates the GPU profiling capabilities of the given device and returns // an error if validation failed or the GPU profiling data is invalid. Validate(ctx context.Context) error From fc50fe95dac2bf45c958da4945f8c65d2a7e99d2 Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Wed, 12 Feb 2020 19:25:02 -0800 Subject: [PATCH 0046/1218] Fix vulkan event linking issue when zoomed too out. (#20) - Query submission_id for quantized GPU Queue slices. - Related ticket: http://b/148952158. --- .../gapid/perfetto/models/SliceTrack.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java index 5fff22da8b..29c423da01 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java @@ -68,12 +68,36 @@ public static SliceTrack forGpuQueue(QueryEngine qe, GpuInfo.Queue queue) { return new WithQueryEngine(qe, "gpu_slice", queue.trackId) { // TODO(b/148540258): Remove the copy pasted SliceTrack code and clean up private final String GPU_COLUMNS = "render_target, render_target_name, render_pass, render_pass_name, command_buffer, command_buffer_name, submission_id"; + private final String GPU_SLICES_QUANT_SQL = + "select min(start_ts), max(end_ts), depth, label, max(cnt), " + + " first_value(submission_id) over (partition by depth, label, i) from (" + + " select quantum_ts, start_ts, end_ts, depth, label, count(1) cnt, " + + " quantum_ts-row_number() over (partition by depth, label order by quantum_ts) i, " + + " submission_id from (" + + " select quantum_ts, min(ts) over win1 start_ts, max(ts + dur) over win1 end_ts, depth, " + + " substr(group_concat(name) over win1, 0, 101) label, " + + " first_value(submission_id) over win1 submission_id" + + " from %s" + + " window win1 as (partition by quantum_ts, depth order by dur desc" + + " range between unbounded preceding and unbounded following))" + + " group by quantum_ts, depth)" + + "group by depth, label, i"; @Override protected String baseColumns() { return BASE_COLUMNS + ", " + GPU_COLUMNS; } + @Override + protected String slicesQuantSql() { + return format(GPU_SLICES_QUANT_SQL, tableName("span")); + } + + @Override + protected void appendForQuant(Data data, QueryEngine.Result res) { + data.putExtraLongs("submissionIds", res.stream().mapToLong(r -> r.getLong(5)).toArray()); + } + @Override protected ListenableFuture computeData(DataRequest req) { Window window = Window.compute(req, 5); @@ -510,6 +534,8 @@ protected String baseColumns() { return BASE_COLUMNS; } + protected void appendForQuant(Data data, QueryEngine.Result res) { /* Do nothing by default. */} + protected WithQueryEngine(QueryEngine qe, String table, long trackId) { super(trackId); this.qe = qe; @@ -555,11 +581,12 @@ protected ListenableFuture computeQuantSlices(DataRequest req) { } data.args[i] = ArgSet.EMPTY; }); + appendForQuant(data, res); return data; }); } - private String slicesQuantSql() { + protected String slicesQuantSql() { return format(SLICES_QUANT_SQL, tableName("span")); } From 72b067d054e96a26936c301775e57e61a65822a7 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Thu, 13 Feb 2020 09:54:18 +0000 Subject: [PATCH 0047/1218] Make release and dev-release update check the AGI repos (#36) Bug: none --- gapis/server/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gapis/server/server.go b/gapis/server/server.go index 9ed890abc1..b322f659dd 100644 --- a/gapis/server/server.go +++ b/gapis/server/server.go @@ -116,8 +116,8 @@ func (s *server) GetServerInfo(ctx context.Context) (*service.ServerInfo, error) func (s *server) CheckForUpdates(ctx context.Context, includeDevReleases bool) (*service.Release, error) { const ( githubOrg = "google" - githubRepo = "gapid" - devGithubRepo = "gapid-dev-releases" + githubRepo = "agi" + devGithubRepo = "agi-dev-releases" ) ctx = status.Start(ctx, "RPC CheckForUpdates") defer status.Finish(ctx) From 31565022b11fbfd9c180783b003f65d777b2eac5 Mon Sep 17 00:00:00 2001 From: Melih Yasin Yalcin Date: Thu, 13 Feb 2020 10:48:44 +0000 Subject: [PATCH 0048/1218] Package the symbol files to be able to upload them (#24) by the release tool b/139480214 --- kokoro/linux/package.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh index c9cde4f619..d20e8c3c24 100755 --- a/kokoro/linux/package.sh +++ b/kokoro/linux/package.sh @@ -88,5 +88,8 @@ echo "$(date): Done." # Copy the symbol file to the output. [ -f "$BIN/cmd/gapir/cc/gapir.sym" ] && cp "$BIN/cmd/gapir/cc/gapir.sym" gapir-$VERSION-linux.sym +[ -f "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" arm64-v8a_gapir-$VERSION-linux.sym +[ -f "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" armeabi-v7a_gapir-$VERSION-linux.sym +[ -f "$BIN/gapidapk/android/apk/x86_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/x86_gapir.sym" x86_gapir-$VERSION-linux.sym popd From 69e874bfe6b9dc3f74691ae9f921c573ab0fedb6 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 05:40:18 -0800 Subject: [PATCH 0049/1218] Limit the max number of frames/time for captures. --- gapic/src/main/com/google/gapid/Main.java | 3 ++ .../com/google/gapid/views/TracerDialog.java | 48 ++++++++----------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/gapic/src/main/com/google/gapid/Main.java b/gapic/src/main/com/google/gapid/Main.java index f99603cd8e..5bcb78c02f 100644 --- a/gapic/src/main/com/google/gapid/Main.java +++ b/gapic/src/main/com/google/gapid/Main.java @@ -36,6 +36,7 @@ import com.google.gapid.util.Logging; import com.google.gapid.util.Messages; import com.google.gapid.util.Scheduler; +import com.google.gapid.views.TracerDialog; import com.google.gapid.widgets.Theme; import com.google.gapid.widgets.Widgets; @@ -209,5 +210,7 @@ private static interface ShellRunnable { Follower.logFollowRequests, Server.useCache, PanelCanvas.showRedraws, + TracerDialog.maxFrames, + TracerDialog.maxPerfetto, }; } diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index aea828629b..45fc9bfa22 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -55,6 +55,8 @@ import com.google.gapid.server.Client; import com.google.gapid.server.Tracer; import com.google.gapid.server.Tracer.TraceRequest; +import com.google.gapid.util.Flags; +import com.google.gapid.util.Flags.Flag; import com.google.gapid.util.Messages; import com.google.gapid.util.OS; import com.google.gapid.util.Scheduler; @@ -109,6 +111,11 @@ public class TracerDialog { protected static final Logger LOG = Logger.getLogger(TracerDialog.class.getName()); + public static final Flag maxFrames = Flags.value( + "max-frames", 20, "The maximum number of frames to allow for graphics captures", true); + public static final Flag maxPerfetto = Flags.value( + "max-perfetto", 10 * 60, "The maximum amount of time to allow for profile captures", true); + private TracerDialog() { } @@ -258,10 +265,10 @@ private static class TraceInput extends Composite { private static final String TARGET_LABEL = "Application"; private static final String FRAMES_LABEL = "Stop After:"; private static final String DURATION_LABEL = "Duration:"; - private static final int DURATION_MAX = 999999; - private static final String FRAMES_UNIT = "Frames (0 for manual)"; - private static final String DURATION_UNIT = "Seconds (0 for manual)"; - private static final String DURATION_UNIT_NO_MANUAL = "Seconds"; + private static final int DURATION_FRAMES_MAX = maxFrames.get(); + private static final int DURATION_PERFETTO_MAX = maxPerfetto.get(); + private static final String DURATION_FRAMES_UNIT = "Frames"; + private static final String DURATION_PERFETTO_UNIT = "Seconds"; private static final String MEC_LABEL_WARNING = "NOTE: Mid-Execution capture for %s is experimental"; private static final String PERFETTO_LABEL = "Profile Config: "; @@ -391,9 +398,9 @@ protected String createAndShowDialog(String current) { mecWarningLabel = createLabel(durGroup, ""); durationLabel = createLabel(durGroup, FRAMES_LABEL); - duration = withLayoutData(createSpinner(durGroup, 7, 0, DURATION_MAX), + duration = withLayoutData(createSpinner(durGroup, 7, 1, DURATION_FRAMES_MAX), new GridData(SWT.FILL, SWT.TOP, false, false)); - durationUnit = createLabel(durGroup, FRAMES_UNIT); + durationUnit = createLabel(durGroup, DURATION_FRAMES_UNIT); Group optGroup = withLayoutData( createGroup(this, "Trace Options", new GridLayout(2, false)), @@ -466,8 +473,7 @@ protected void configureDialog(DirectoryDialog dialog) { device.getCombo().addListener(SWT.Selection, e -> updateOnDeviceChange(models.settings, getSelectedDevice())); - api.getCombo().addListener(SWT.Selection, - e -> updateOnApiChange(trace, getSelectedDevice(), getSelectedApi())); + api.getCombo().addListener(SWT.Selection, e -> updateOnApiChange(trace, getSelectedApi())); Listener gpuProfilingCapabilityListener = e -> { // Skip if the device is not Android device, or trace type is not Perfetto. @@ -596,7 +602,7 @@ private void updateOnDeviceChange(Settings settings, DeviceCaptureInfo dev) { } private void updateOnApiChange( - SettingsProto.TraceOrBuilder trace, DeviceCaptureInfo dev, TraceTypeCapabilities config) { + SettingsProto.TraceOrBuilder trace, TraceTypeCapabilities config) { boolean pcs = config != null && config.getCanDisablePcs(); disablePcs.setEnabled(pcs); disablePcs.setSelection(pcs && trace.getDisablePcs()); @@ -641,7 +647,10 @@ private void updateOnApiChange( duration.setSelection(dur.getDuration()); durationLabel.setText(isPerfetto ? DURATION_LABEL : FRAMES_LABEL); - updateDurationSpinner(dev, config, dur.getType()); + duration.setMaximum(isPerfetto ? DURATION_PERFETTO_MAX : DURATION_FRAMES_MAX); + durationUnit.setText(isPerfetto ? DURATION_PERFETTO_UNIT : DURATION_FRAMES_UNIT); + durationUnit.requestLayout(); + perfettoConfig.setVisible(isPerfetto); if (!userHasChangedOutputFile) { @@ -650,25 +659,6 @@ private void updateOnApiChange( } } - private void updateDurationSpinner( - DeviceCaptureInfo dev, TraceTypeCapabilities capabilities, - SettingsProto.Trace.Duration.Type type) { - boolean isStadia = dev != null && dev.isStadia(); - boolean isPerfetto = isPerfetto(capabilities); - if (isStadia && isPerfetto) { - // On Stadia, force limit Perfetto traces to 10 seconds. - duration.setMinimum(1); - duration.setMaximum(10); - durationUnit.setText(DURATION_UNIT_NO_MANUAL); - } else { - duration.setMinimum(0); - duration.setMaximum(DURATION_MAX); - durationUnit.setText((isPerfetto || type == SettingsProto.Trace.Duration.Type.TIME) ? - DURATION_UNIT : FRAMES_UNIT); - } - durationUnit.requestLayout(); - } - private void updateDevicesDropDown(SettingsProto.TraceOrBuilder trace) { if (device != null && devices != null) { deviceLoader.stopLoading(); From 70c0a43aa4215a20afa94b25eb3757614de53fbe Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 08:28:31 -0800 Subject: [PATCH 0050/1218] Utility factory methods for create TableViewers. --- .../com/google/gapid/widgets/Widgets.java | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/gapic/src/main/com/google/gapid/widgets/Widgets.java b/gapic/src/main/com/google/gapid/widgets/Widgets.java index 99b799e7ca..e3e756d1ed 100644 --- a/gapic/src/main/com/google/gapid/widgets/Widgets.java +++ b/gapic/src/main/com/google/gapid/widgets/Widgets.java @@ -28,6 +28,7 @@ import com.google.gapid.views.CommandEditor; import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ComboViewer; @@ -432,14 +433,40 @@ public static Link createLink(Composite parent, String text, Listener listener) return link; } - public static TableViewer createTableViewer(Composite parent, int style) { - TableViewer table = new VisibilityTrackingTableViewer(new Table(parent, style)); - table.getTable().setHeaderVisible(true); - table.getTable().setLinesVisible(true); - table.setUseHashlookup(true); + /** + * Use this to create a {@link Table} that you will later wrap in a {@link TableViewer} using + * {@link #createTableViewer(Table)}. + * If using the table for {@link #createCheckboxTableViewer(Table)}, style needs to contain + * {@code SWT.CHECK}. + */ + public static Table createTableForViewer(Composite parent, int style) { + Table table = new Table(parent, style); + table.setHeaderVisible(true); + table.setLinesVisible(true); return table; } + public static TableViewer createTableViewer(Composite parent, int style) { + return createTableViewer(createTableForViewer(parent, style)); + } + + public static TableViewer createTableViewer(Table table) { + return initTableViewer(new TableViewer(table)); + } + + public static CheckboxTableViewer createCheckboxTableViewer(Composite parent, int style) { + return createCheckboxTableViewer(createTableForViewer(parent, style | SWT.CHECK)); + } + + public static CheckboxTableViewer createCheckboxTableViewer(Table table) { + return initTableViewer(new CheckboxTableViewer(table)); + } + + private static T initTableViewer(T viewer) { + viewer.setUseHashlookup(true); + return viewer; + } + public static TableViewerColumn createTableColumn(TableViewer viewer, String title) { TableViewerColumn result = new TableViewerColumn(viewer, SWT.NONE); TableColumn column = result.getColumn(); From d9cfc60534b86b7c8daf9d169467e67317cf0ee9 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 08:51:34 -0800 Subject: [PATCH 0051/1218] Use a TableViewer in the counter selection dialog. --- .../perfetto/views/TraceConfigDialog.java | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 20cff6b33e..33d35abbb9 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -22,6 +22,7 @@ import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.MemoryTracking.MEMORY_TRACKING_DEVICE; import static com.google.gapid.proto.SettingsProto.Perfetto.Vulkan.MemoryTracking.MEMORY_TRACKING_DRIVER; import static com.google.gapid.widgets.Widgets.createCheckbox; +import static com.google.gapid.widgets.Widgets.createCheckboxTableViewer; import static com.google.gapid.widgets.Widgets.createComposite; import static com.google.gapid.widgets.Widgets.createLabel; import static com.google.gapid.widgets.Widgets.createLink; @@ -53,6 +54,8 @@ import com.google.protobuf.TextFormat.ParseException; import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; @@ -65,9 +68,6 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Spinner; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import java.util.Arrays; @@ -769,7 +769,7 @@ private static class GpuCountersDialog extends DialogBase { private final Device.PerfettoCapability caps; private final Set currentIds; - private Table table; + private CheckboxTableViewer table; private List selectedIds; public GpuCountersDialog( @@ -791,27 +791,23 @@ public String getTitle() { @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite)super.createDialogArea(parent); - table = withLayoutData(new Table(area, SWT.CHECK), new GridData(GridData.FILL_BOTH)); - table.setHeaderVisible(true); - table.setLinesVisible(true); - new TableColumn(table, SWT.NONE).setText("Name"); - new TableColumn(table, SWT.NONE).setText("Description"); - for (GpuProfiling.GpuCounterDescriptor.GpuCounterSpec counter : - caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList()) { - TableItem item = new TableItem(table, SWT.NONE); - item.setText(new String[] { counter.getName(), counter.getDescription() }); - item.setData(counter); - if (currentIds.contains(counter.getCounterId())) { - item.setChecked(true); - } - } - table.getColumn(0).pack(); - table.getColumn(1).pack(); + table = createCheckboxTableViewer(area, SWT.NONE); + table.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + Widgets.createTableColumn( + table, "Name", counter -> counter.getName()); + Widgets.createTableColumn( + table, "Description", counter -> counter.getDescription()); + table.setContentProvider(new ArrayContentProvider()); + table.setInput(caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList()); + table.setCheckedElements( + caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList().stream() + .filter(counter -> currentIds.contains(counter.getCounterId())) + .toArray(GpuProfiling.GpuCounterDescriptor.GpuCounterSpec[]::new)); + table.getTable().getColumn(0).pack(); + table.getTable().getColumn(1).pack(); + createLink(area, "Select none | all", e -> { - boolean checked = "all".equals(e.text); - for (TableItem item : table.getItems()) { - item.setChecked(checked); - } + table.setAllChecked("all".equals(e.text)); }); return area; } @@ -823,9 +819,8 @@ protected Point getInitialSize() { @Override protected void okPressed() { - selectedIds = Arrays.stream(table.getItems()) - .filter(item -> item.getChecked()) - .map(item -> (GpuProfiling.GpuCounterDescriptor.GpuCounterSpec)item.getData()) + selectedIds = Arrays.stream(table.getCheckedElements()) + .map(item -> (GpuProfiling.GpuCounterDescriptor.GpuCounterSpec)item) .mapToInt(GpuProfiling.GpuCounterDescriptor.GpuCounterSpec::getCounterId) .boxed() .collect(toList()); From cec05d23d5fad21390df9d0f23ee008d8e940dd6 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 08:59:50 -0800 Subject: [PATCH 0052/1218] Respect the "select by default" counter setting. When no counter has been selected, it defaults to selecting the default counters. Also adds a link to allow the user to change the current selection back to the default selection. --- .../perfetto/views/TraceConfigDialog.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 33d35abbb9..9f2e95a518 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -37,6 +37,7 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -766,6 +767,9 @@ private void updateBat() { } private static class GpuCountersDialog extends DialogBase { + private static final Predicate + SELECT_DEFAULT = GpuProfiling.GpuCounterDescriptor.GpuCounterSpec::getSelectByDefault; + private final Device.PerfettoCapability caps; private final Set currentIds; @@ -801,13 +805,27 @@ protected Control createDialogArea(Composite parent) { table.setInput(caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList()); table.setCheckedElements( caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList().stream() - .filter(counter -> currentIds.contains(counter.getCounterId())) + .filter(currentIds.isEmpty() ? + SELECT_DEFAULT : c -> currentIds.contains(c.getCounterId())) .toArray(GpuProfiling.GpuCounterDescriptor.GpuCounterSpec[]::new)); table.getTable().getColumn(0).pack(); table.getTable().getColumn(1).pack(); - createLink(area, "Select none | all", e -> { - table.setAllChecked("all".equals(e.text)); + createLink(area, "Select none | default | all", e -> { + switch (e.text) { + case "none": + table.setAllChecked(false); + break; + case "default": + table.setCheckedElements( + caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList().stream() + .filter(SELECT_DEFAULT) + .toArray(GpuProfiling.GpuCounterDescriptor.GpuCounterSpec[]::new)); + break; + case "all": + table.setAllChecked(true); + break; + } }); return area; } From af4cda4998ada916097d4d821acb549aa9acaec4 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 12 Feb 2020 09:14:38 -0800 Subject: [PATCH 0053/1218] Add a searchbox to the GPU counter selection. --- .../perfetto/views/TraceConfigDialog.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java index 9f2e95a518..0c09ebdab0 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java @@ -57,6 +57,8 @@ import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; @@ -795,6 +797,9 @@ public String getTitle() { @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite)super.createDialogArea(parent); + Text search = new Text(area, SWT.SINGLE | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL); + search.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + table = createCheckboxTableViewer(area, SWT.NONE); table.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Widgets.createTableColumn( @@ -827,6 +832,23 @@ protected Control createDialogArea(Composite parent) { break; } }); + + search.addListener(SWT.Modify, e -> { + String query = search.getText().trim().toLowerCase(); + if (query.isEmpty()) { + table.resetFilters(); + return; + } + table.setFilters(new ViewerFilter() { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + return ((GpuProfiling.GpuCounterDescriptor.GpuCounterSpec)element) + .getName() + .toLowerCase() + .contains(query); + } + }); + }); return area; } From d3f44eed4df5872a133eaafdba769d528b0357f1 Mon Sep 17 00:00:00 2001 From: rschiu Date: Thu, 13 Feb 2020 08:29:34 -0800 Subject: [PATCH 0054/1218] Fix vkEnumerateDeviceExtensionProperties in CPUTiming layer (#41) The layer added new extension and increased the pPropertyCount by 2. pPropertyCount is expected to be reduced back to the original value when vkEnumerateDeviceExtensionProperties is called. Therefore, it needs to increased back to the requested value. Bug: b/149116549 --- core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl index 229150d92a..3923c1bab4 100644 --- a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl +++ b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl @@ -205,7 +205,6 @@ VkResult vkSetDebugUtilsObjectNameEXT( return debug_utils_ext_supported ? next(device, pNameInfo) : VK_SUCCESS; } - VkResult vkDebugMarkerSetObjectNameEXT( PFN_vkDebugMarkerSetObjectNameEXT next, VkDevice device, @@ -238,9 +237,9 @@ VkResult vkEnumerateDeviceExtensionProperties(PFN_vkEnumerateDeviceExtensionProp return res; } if (*pPropertyCount > 0) { + uint32_t requestedCount = *pPropertyCount; VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties); if (res == VK_SUCCESS) { - uint32_t count = std::min(NUM_EXTENSIONS, *pPropertyCount); for (uint32_t i = 0; i < *pPropertyCount; ++i) { if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, pProperties[i].extensionName)) { debug_utils_ext_supported = true; @@ -249,6 +248,9 @@ VkResult vkEnumerateDeviceExtensionProperties(PFN_vkEnumerateDeviceExtensionProp debug_marker_ext_supported = true; } } + // *pPropertyCount is expected to be requestedCount - NUM_EXTENSIONS. + *pPropertyCount = std::min(*pPropertyCount + NUM_EXTENSIONS, requestedCount); + uint32_t count = std::min(NUM_EXTENSIONS, *pPropertyCount); memcpy( &pProperties[*pPropertyCount - count], new_device_extensions, From a3a8f859ccf63a3da27b130e223bd3894089a3ca Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Thu, 13 Feb 2020 16:30:37 +0000 Subject: [PATCH 0055/1218] Update Kokoro config to include android symbols as artifacts (#45) --- kokoro/linux/common.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index 7b3896c142..a3db974c96 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -17,7 +17,7 @@ action { define_artifacts { regex: "out/dist/agi*.deb" regex: "out/dist/agi*.zip" - regex: "out/dist/gapir*.sym" + regex: "out/dist/*gapir*.sym" strip_prefix: "out/dist" } } From ba706fc8f603b2a4e6b5e190b61f014b751cd229 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 14 Feb 2020 08:45:31 +1300 Subject: [PATCH 0056/1218] Pipeline view: Fix label of index count for DrawIndexed (#43) Bug: b/149446083 --- gapis/api/vulkan/resources.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go index e4495ab137..cbfcb952a7 100644 --- a/gapis/api/vulkan/resources.go +++ b/gapis/api/vulkan/resources.go @@ -1230,7 +1230,7 @@ func (p GraphicsPipelineObjectʳ) inputAssembly(cmd *path.Command, drawCallInfo drawCallList = drawCallList.AppendKeyValuePair("First Instance", api.CreatePoDDataValue("u32", callArgs.FirstInstance()), false) } else if !drawCallInfo.DrawIndexed().IsNil() { callArgs := drawCallInfo.DrawIndexed() - drawCallList = drawCallList.AppendKeyValuePair("Instance Count", api.CreatePoDDataValue("u32", callArgs.IndexCount()), false) + drawCallList = drawCallList.AppendKeyValuePair("Index Count", api.CreatePoDDataValue("u32", callArgs.IndexCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Instance Count", api.CreatePoDDataValue("u32", callArgs.InstanceCount()), false) drawCallList = drawCallList.AppendKeyValuePair("First Index", api.CreatePoDDataValue("u32", callArgs.FirstIndex()), false) drawCallList = drawCallList.AppendKeyValuePair("Vertex Offset", api.CreatePoDDataValue("u32", callArgs.VertexOffset()), false) From 4392748b4bc0bedd42d0621063cdd51cf6a62ef8 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Thu, 13 Feb 2020 11:51:29 -0800 Subject: [PATCH 0057/1218] Fix error where last row tooltip in PV tables were showing (#44) --- gapic/src/main/com/google/gapid/views/PipelineView.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index bc2bebc83c..347b13a016 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -436,11 +436,9 @@ private Composite createStage(Composite parent, API.Stage currentStage) { TableViewerColumn tvc = createTableColumn(groupTable, dataGroup.getTable().getHeaders(i)); StyledCellLabelProvider cellLabelProvider = new StyledCellLabelProvider() { - DataValue dv; - @Override public void update(ViewerCell cell) { - dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); + DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); cell.setText(dv.displayValue); @@ -456,6 +454,7 @@ public void update(ViewerCell cell) { @Override public String getToolTipText(Object element) { + DataValue dv = convertDataValue(((API.Row)element).getRowValues(col)); if (dv != null) { return dv.tooltipValue; } else { From 9f2ff5d48b2a795bc8dc8bd8f6061c2a645d69e2 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 13 Dec 2019 17:30:46 -0800 Subject: [PATCH 0058/1218] Basic profiling data model. --- .../main/com/google/gapid/models/Models.java | 8 +- .../main/com/google/gapid/models/Profile.java | 149 ++++++++++++++++++ .../main/com/google/gapid/server/Client.java | 11 ++ .../com/google/gapid/server/GapidClient.java | 3 +- .../google/gapid/server/GapidClientGrpc.java | 14 +- 5 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 gapic/src/main/com/google/gapid/models/Profile.java diff --git a/gapic/src/main/com/google/gapid/models/Models.java b/gapic/src/main/com/google/gapid/models/Models.java index 87f34ceeea..e9d67351e9 100644 --- a/gapic/src/main/com/google/gapid/models/Models.java +++ b/gapic/src/main/com/google/gapid/models/Models.java @@ -39,13 +39,14 @@ public class Models { public final Memory memory; public final MemoryTypes types; public final Perfetto perfetto; + public final Profile profile; public final StatusBar status; // The "model" part of this "widget". public Models(Settings settings, Analytics analytics, Follower follower, Capture capture, Devices devices, CommandStream commands, ApiContext contexts, Timeline timeline, Resources resources, ApiState state, Reports reports, ImagesModel images, ConstantSets constants, Geometries geos, Memory memory, MemoryTypes types, Perfetto perfetto, - StatusBar status) { + Profile profile, StatusBar status) { this.settings = settings; this.analytics = analytics; this.follower = follower; @@ -63,6 +64,7 @@ public Models(Settings settings, Analytics analytics, Follower follower, Capture this.memory = memory; this.types = types; this.perfetto = perfetto; + this.profile = profile; this.status = status; } @@ -86,8 +88,10 @@ public static Models create( Memory memory = new Memory(shell, analytics, client, devices, commands); MemoryTypes types = new MemoryTypes(client, devices, constants); Perfetto perfetto = new Perfetto(shell, analytics, client, capture, status); + Profile profile = new Profile(shell, analytics, client, capture, devices); return new Models(settings, analytics, follower, capture, devices, commands, contexts, timeline, - resources, state, reports, images, constants, geometries, memory, types, perfetto, status); + resources, state, reports, images, constants, geometries, memory, types, perfetto, profile, + status); } public void dispose() { diff --git a/gapic/src/main/com/google/gapid/models/Profile.java b/gapic/src/main/com/google/gapid/models/Profile.java new file mode 100644 index 0000000000..2b99fa7316 --- /dev/null +++ b/gapic/src/main/com/google/gapid/models/Profile.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gapid.models; +import static com.google.gapid.rpc.UiErrorCallback.error; +import static com.google.gapid.rpc.UiErrorCallback.success; +import static com.google.gapid.util.Logging.throttleLogRpcError; +import static com.google.gapid.util.MoreFutures.transform; +import static java.util.logging.Level.WARNING; + +import com.google.common.base.Objects; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gapid.proto.service.Service; +import com.google.gapid.proto.service.path.Path; +import com.google.gapid.rpc.Rpc; +import com.google.gapid.rpc.RpcException; +import com.google.gapid.rpc.UiErrorCallback.ResultOrError; +import com.google.gapid.server.Client; +import com.google.gapid.util.Events; +import com.google.gapid.util.Loadable; + +import org.eclipse.swt.widgets.Shell; + +import java.util.concurrent.ExecutionException; +import java.util.logging.Logger; + +public class Profile + extends CaptureDependentModel { + private static final Logger LOG = Logger.getLogger(Profile.class.getName()); + + private final Capture capture; + + public Profile( + Shell shell, Analytics analytics, Client client, Capture capture, Devices devices) { + super(LOG, shell, analytics, client, Listener.class, capture, devices); + this.capture = capture; + } + + @Override + protected Source getSource(Capture.Data data) { + return new Source(data.path); + } + + @Override + protected boolean shouldLoad(Capture.Data data) { + return data.isGraphics(); + } + + @Override + protected ListenableFuture doLoad(Source source, Path.Device device) { + return transform(client.profile(capture.getData().path, device), r -> new Data(device, r)); + } + + @Override + protected ResultOrError processResult(Rpc.Result result) { + try { + return success(result.get()); + } catch (RpcException e) { + LOG.log(WARNING, "Failed to load the GPU profile", e); + return error(Loadable.Message.error(e)); + } catch (ExecutionException e) { + if (!shell.isDisposed()) { + throttleLogRpcError(LOG, "Failed to load the GPU profile", e); + } + return error(Loadable.Message.error("Failed to load the GPU profile")); + } + } + + @Override + protected void updateError(Loadable.Message error) { + listeners.fire().onProfileLoaded(error); + } + + @Override + protected void fireLoadStartEvent() { + listeners.fire().onProfileLoadingStart(); + } + + @Override + protected void fireLoadedEvent() { + listeners.fire().onProfileLoaded(null); + } + + public static class Source { + public final Path.Capture capture; + + public Source(Path.Capture capture) { + this.capture = capture; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (!(obj instanceof Source)) { + return false; + } + return Objects.equal(capture, ((Source)obj).capture); + } + + @Override + public int hashCode() { + return (capture == null) ? 0 : capture.hashCode(); + } + } + + public static class Data extends DeviceDependentModel.Data { + public final Service.ProfilingData profile; + + public Data(Path.Device device, Service.ProfilingData profile) { + super(device); + this.profile = profile; + } + + public boolean hasSlices() { + return profile.getSlices().getSlicesCount() > 0; + } + + public Service.ProfilingData.GpuSlices getSlices() { + return profile.getSlices(); + } + } + + public static interface Listener extends Events.Listener { + /** + * Event indicating that profiling data is being loaded. + */ + public default void onProfileLoadingStart() { /* empty */ } + + /** + * Event indicating that the profiling data has finished loading. + * + * @param error the loading error or {@code null} if loading was successful. + */ + public default void onProfileLoaded(Loadable.Message error) { /* empty */ } + } +} diff --git a/gapic/src/main/com/google/gapid/server/Client.java b/gapic/src/main/com/google/gapid/server/Client.java index 9e0c71359d..2803843676 100644 --- a/gapic/src/main/com/google/gapid/server/Client.java +++ b/gapic/src/main/com/google/gapid/server/Client.java @@ -257,6 +257,17 @@ public ListenableFuture perfettoQuery(Path.Capture capture in -> immediateFuture(throwIfError(in.getResult(), in.getError(), stack)))); } + public ListenableFuture profile(Path.Capture capture, Path.Device device) { + return call(() -> String.format( + "RPC->profile(%s, %s)", shortDebugString(capture), shortDebugString(device)), + stack -> MoreFutures.transformAsync( + client.profile(Service.GpuProfileRequest.newBuilder() + .setCapture(capture) + .setDevice(device) + .build()), + in -> immediateFuture(throwIfError(in.getProfilingData(), in.getError(), stack)))); + } + public ListenableFuture streamLog(Consumer onLogMessage) { LOG.log(FINE, "RPC->getLogStream()"); return client.streamLog(onLogMessage); diff --git a/gapic/src/main/com/google/gapid/server/GapidClient.java b/gapic/src/main/com/google/gapid/server/GapidClient.java index 7a83271128..8dfb6d2c0e 100644 --- a/gapic/src/main/com/google/gapid/server/GapidClient.java +++ b/gapic/src/main/com/google/gapid/server/GapidClient.java @@ -33,8 +33,6 @@ public ListenableFuture checkForUpdates( public ListenableFuture get(Service.GetRequest request); public ListenableFuture set(Service.SetRequest request); public ListenableFuture follow(Service.FollowRequest request); - public StreamSender profile( - StreamConsumer response); public ListenableFuture getPerformanceCounters( Service.GetPerformanceCountersRequest request); public ListenableFuture getProfile(Service.GetProfileRequest request); @@ -61,6 +59,7 @@ public ListenableFuture updateSettings( Service.UpdateSettingsRequest request); public ListenableFuture perfettoQuery( Service.PerfettoQueryRequest request); + public ListenableFuture profile(Service.GpuProfileRequest request); public ListenableFuture streamLog(Consumer onLogMessage); public ListenableFuture streamStatus( diff --git a/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java b/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java index 8809a3aaca..be1cfd8beb 100644 --- a/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java +++ b/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java @@ -24,6 +24,8 @@ import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.Service.ClientEventRequest; import com.google.gapid.proto.service.Service.ClientEventResponse; +import com.google.gapid.proto.service.Service.GpuProfileRequest; +import com.google.gapid.proto.service.Service.GpuProfileResponse; import com.google.gapid.proto.service.Service.PerfettoQueryRequest; import com.google.gapid.proto.service.Service.PerfettoQueryResponse; import com.google.gapid.proto.service.Service.PingRequest; @@ -81,13 +83,6 @@ public ListenableFuture follow(Service.FollowRequest req return client.follow(request); } - @Override - public GapidClient.StreamSender profile( - StreamConsumer response) { - StreamHandler handler = StreamHandler.wrap(response); - return Sender.wrap(handler.future, stub.profile(handler)); - } - @Override public ListenableFuture getPerformanceCounters( Service.GetPerformanceCountersRequest request) { @@ -169,6 +164,11 @@ public ListenableFuture perfettoQuery(PerfettoQueryReques return client.perfettoQuery(request); } + @Override + public ListenableFuture profile(GpuProfileRequest request) { + return client.gpuProfile(request); + } + @Override public ListenableFuture streamLog(Consumer onLogMessage) { StreamHandler handler = StreamHandler.wrap(onLogMessage); From d51afd435d1f40257b94e1384faf68ab89649b30 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 21 Jan 2020 12:49:16 -0800 Subject: [PATCH 0059/1218] Adds a new Profile tab to show the profiling data. --- .../com/google/gapid/GraphicsTraceView.java | 2 + .../com/google/gapid/models/Analytics.java | 4 +- .../main/com/google/gapid/util/Messages.java | 1 + .../com/google/gapid/views/ProfileView.java | 177 ++++++++++++++++++ 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 gapic/src/main/com/google/gapid/views/ProfileView.java diff --git a/gapic/src/main/com/google/gapid/GraphicsTraceView.java b/gapic/src/main/com/google/gapid/GraphicsTraceView.java index 18bd27db3a..a56eca6f20 100644 --- a/gapic/src/main/com/google/gapid/GraphicsTraceView.java +++ b/gapic/src/main/com/google/gapid/GraphicsTraceView.java @@ -34,6 +34,7 @@ import com.google.gapid.views.LogView; import com.google.gapid.views.MemoryView; import com.google.gapid.views.PipelineView; +import com.google.gapid.views.ProfileView; import com.google.gapid.views.ReportView; import com.google.gapid.views.ShaderView; import com.google.gapid.views.StateView; @@ -357,6 +358,7 @@ private static List getTabs( */ public static enum Type { Filmstrip(View.FilmStrip, "Filmstrip", true, ThumbnailScrubber::new), + Profile(View.Profile, "Profile", true, ProfileView::new), ApiCalls(View.Commands, "Commands", false, CommandTree::new), diff --git a/gapic/src/main/com/google/gapid/models/Analytics.java b/gapic/src/main/com/google/gapid/models/Analytics.java index a7f6ceec64..ab4b232c9a 100644 --- a/gapic/src/main/com/google/gapid/models/Analytics.java +++ b/gapic/src/main/com/google/gapid/models/Analytics.java @@ -31,10 +31,10 @@ public class Analytics implements ExceptionHandler { private static final Logger LOG = Logger.getLogger(Analytics.class.getName()); public static enum View { - Main, FilmStrip, LeftTabs, RightTabs, + Main, LeftTabs, RightTabs, About, Help, GotoCommand, GotoMemory, Licenses, Settings, Trace, Welcome, // See MainWindow.MainTab.Type - Commands, Framebuffer, Pipeline, Textures, Geometry, Shaders, Report, Log, State, Memory, + FilmStrip, Profile, Commands, Framebuffer, Pipeline, Textures, Geometry, Shaders, Report, Log, State, Memory, ContextSelector, ReplayDeviceSelector; } diff --git a/gapic/src/main/com/google/gapid/util/Messages.java b/gapic/src/main/com/google/gapid/util/Messages.java index a5cc9dba12..ba221e2bd0 100644 --- a/gapic/src/main/com/google/gapid/util/Messages.java +++ b/gapic/src/main/com/google/gapid/util/Messages.java @@ -20,6 +20,7 @@ public interface Messages { public static final String WINDOW_TITLE = "Android GPU Inspector"; public static final String LOADING_CAPTURE = "Loading capture..."; + public static final String LOADING_PROFILE = "Profiling replay..."; public static final String CAPTURE_LOAD_FAILURE = "Failed to load capture."; public static final String NO_FRAMES_IN_CONTEXT = "No frames in selected context."; public static final String SELECT_COMMAND = "Select a frame or command."; diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java new file mode 100644 index 0000000000..609c4ddccb --- /dev/null +++ b/gapic/src/main/com/google/gapid/views/ProfileView.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gapid.views; + +import static com.google.gapid.util.Loadable.MessageType.Error; +import static com.google.gapid.util.Loadable.MessageType.Loading; + +import com.google.common.collect.Lists; +import com.google.gapid.models.Capture; +import com.google.gapid.models.Models; +import com.google.gapid.models.Profile; +import com.google.gapid.models.Settings; +import com.google.gapid.perfetto.canvas.Panel; +import com.google.gapid.perfetto.canvas.RenderContext; +import com.google.gapid.perfetto.models.CpuInfo; +import com.google.gapid.perfetto.models.ProcessInfo; +import com.google.gapid.perfetto.models.ThreadInfo; +import com.google.gapid.perfetto.views.RootPanel; +import com.google.gapid.perfetto.views.State; +import com.google.gapid.perfetto.views.TraceComposite; +import com.google.gapid.util.Loadable; +import com.google.gapid.util.Messages; +import com.google.gapid.widgets.LoadablePanel; +import com.google.gapid.widgets.Theme; +import com.google.gapid.widgets.Widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +import java.util.List; + +public class ProfileView extends Composite implements Tab, Capture.Listener, Profile.Listener { + private final Models models; + + private final LoadablePanel loading; + private final TraceUi traceUi; + + public ProfileView(Composite parent, Models models, Widgets widgets) { + super(parent, SWT.NONE); + this.models = models; + + setLayout(new FillLayout(SWT.VERTICAL)); + + loading = new LoadablePanel(this, widgets, p -> new TraceUi(p, models, widgets.theme) { + @Override + protected Settings settings() { + return models.settings; + } + }); + traceUi = loading.getContents(); + + models.capture.addListener(this); + models.profile.addListener(this); + addListener(SWT.Dispose, e -> { + models.capture.removeListener(this); + models.profile.removeListener(this); + }); + } + + @Override + public Control getControl() { + return this; + } + + @Override + public void reinitialize() { + if (models.profile.isLoaded()) { + updateProfile(models.profile.getData()); + } else { + loading.showMessage( + Loading, models.capture.isLoaded() ? Messages.LOADING_CAPTURE : Messages.LOADING_PROFILE); + } + } + + @Override + public void onCaptureLoadingStart(boolean maintainState) { + loading.showMessage(Loading, Messages.LOADING_CAPTURE); + } + + @Override + public void onCaptureLoaded(Loadable.Message error) { + if (error != null) { + loading.showMessage(Error, Messages.CAPTURE_LOAD_FAILURE); + } + } + + @Override + public void onProfileLoadingStart() { + loading.showMessage(Loading, Messages.LOADING_PROFILE); + } + + @Override + public void onProfileLoaded(Loadable.Message error) { + if (error != null) { + loading.showMessage(error); + } else { + loading.stopLoading(); + updateProfile(models.profile.getData()); + } + } + + private void updateProfile(Profile.Data data) { + traceUi.update(data); + } + + private abstract static class TraceUi extends TraceComposite { + protected final List panels = Lists.newArrayList(); + + public TraceUi(Composite parent, Models models, Theme theme) { + super(parent, models.analytics, theme); + } + + public void update(Profile.Data data) { + panels.clear(); + } + + @Override + protected State createState() { + return new State(this) { + @Override + public CpuInfo getCpuInfo() { + return CpuInfo.NONE; + } + + @Override + public ProcessInfo getProcessInfo(long id) { + return null; + } + + @Override + public ThreadInfo getThreadInfo(long id) { + return null; + } + }; + } + + @Override + protected RootPanel createRootPanel() { + return new RootPanel(state, settings()) { + @Override + protected void createUi() { + top.add(timeline); + for (Panel panel : panels) { + bottom.add(panel); + } + } + + @Override + protected void preTopUiRender(RenderContext ctx, Repainter repainter) { + // Do nothing. + } + + @Override + protected void preMainUiRender(RenderContext ctx, Repainter repainter) { + // Do nothing. + } + }; + } + + protected abstract Settings settings(); + } +} From e584ecfc3b52d88618b704c2914623c8198352f5 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 21 Jan 2020 12:50:05 -0800 Subject: [PATCH 0060/1218] Show the GPU slices in the profile view. --- .../main/com/google/gapid/models/Profile.java | 17 +- .../com/google/gapid/perfetto/TimeSpan.java | 6 +- .../main/com/google/gapid/util/Messages.java | 2 + .../com/google/gapid/views/ProfileView.java | 164 ++++++++++++++++++ 4 files changed, 187 insertions(+), 2 deletions(-) diff --git a/gapic/src/main/com/google/gapid/models/Profile.java b/gapic/src/main/com/google/gapid/models/Profile.java index 2b99fa7316..a11bd3b714 100644 --- a/gapic/src/main/com/google/gapid/models/Profile.java +++ b/gapic/src/main/com/google/gapid/models/Profile.java @@ -22,6 +22,7 @@ import com.google.common.base.Objects; import com.google.common.util.concurrent.ListenableFuture; +import com.google.gapid.perfetto.TimeSpan; import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.path.Path; import com.google.gapid.rpc.Rpc; @@ -125,12 +126,26 @@ public Data(Path.Device device, Service.ProfilingData profile) { } public boolean hasSlices() { - return profile.getSlices().getSlicesCount() > 0; + return profile.getSlices().getSlicesCount() > 0 && + profile.getSlices().getTracksCount() > 0; } public Service.ProfilingData.GpuSlices getSlices() { return profile.getSlices(); } + + public TimeSpan getSlicesTimeSpan() { + if (!hasSlices()) { + return TimeSpan.ZERO; + } + + long start = Long.MAX_VALUE, end = 0; + for (Service.ProfilingData.GpuSlices.Slice slice : profile.getSlices().getSlicesList()) { + start = Math.min(slice.getTs(), start); + end = Math.max(slice.getTs() + slice.getDur(), end); + } + return new TimeSpan(start, end); + } } public static interface Listener extends Events.Listener { diff --git a/gapic/src/main/com/google/gapid/perfetto/TimeSpan.java b/gapic/src/main/com/google/gapid/perfetto/TimeSpan.java index 7acc92e6d1..7f9ac3d607 100644 --- a/gapic/src/main/com/google/gapid/perfetto/TimeSpan.java +++ b/gapic/src/main/com/google/gapid/perfetto/TimeSpan.java @@ -50,7 +50,7 @@ public TimeSpan expand(TimeSpan other) { public final long end; public TimeSpan(long startNs, long endNs) { - checkArgument(startNs <= endNs, "%d > %d", startNs, endNs); + checkArgument(startNs <= endNs, "%s > %s", startNs, endNs); this.start = startNs; this.end = endNs; } @@ -77,6 +77,10 @@ public boolean contains(TimeSpan other) { return start <= other.start && end >= other.end; } + public boolean overlaps(long oStart, long oEnd) { + return start < oEnd && oStart < end; + } + public TimeSpan expand(long deltaNs) { return expand(deltaNs, deltaNs); } diff --git a/gapic/src/main/com/google/gapid/util/Messages.java b/gapic/src/main/com/google/gapid/util/Messages.java index ba221e2bd0..c9712adbd9 100644 --- a/gapic/src/main/com/google/gapid/util/Messages.java +++ b/gapic/src/main/com/google/gapid/util/Messages.java @@ -85,4 +85,6 @@ public interface Messages { public static final String GEO_SEMANTICS_HINT = "Manually configure the vertex stream semantics:"; public static final String QUERY_VIEW_WINDOW_TITLE = "AGI - Query Shell"; public static final String KEYBOARD_MOUSE_HELP_TITLE = "Keyboard/Mouse Shortcut Help"; + public static final String PROFILE_NO_SLICES = + "GPU Profiling is not supported on this device or for this capture"; } diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java index 609c4ddccb..8cc380e454 100644 --- a/gapic/src/main/com/google/gapid/views/ProfileView.java +++ b/gapic/src/main/com/google/gapid/views/ProfileView.java @@ -15,24 +15,41 @@ */ package com.google.gapid.views; +import static com.google.gapid.perfetto.views.StyleConstants.LABEL_MARGIN; +import static com.google.gapid.perfetto.views.StyleConstants.LABEL_WIDTH; +import static com.google.gapid.perfetto.views.StyleConstants.TITLE_HEIGHT; +import static com.google.gapid.perfetto.views.StyleConstants.colors; import static com.google.gapid.util.Loadable.MessageType.Error; import static com.google.gapid.util.Loadable.MessageType.Loading; +import static java.util.stream.Collectors.toList; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.models.Capture; import com.google.gapid.models.Models; import com.google.gapid.models.Profile; import com.google.gapid.models.Settings; +import com.google.gapid.perfetto.TimeSpan; +import com.google.gapid.perfetto.canvas.Area; +import com.google.gapid.perfetto.canvas.Fonts; import com.google.gapid.perfetto.canvas.Panel; import com.google.gapid.perfetto.canvas.RenderContext; +import com.google.gapid.perfetto.models.ArgSet; import com.google.gapid.perfetto.models.CpuInfo; +import com.google.gapid.perfetto.models.GpuInfo; import com.google.gapid.perfetto.models.ProcessInfo; +import com.google.gapid.perfetto.models.SliceTrack; import com.google.gapid.perfetto.models.ThreadInfo; +import com.google.gapid.perfetto.views.GpuQueuePanel; import com.google.gapid.perfetto.views.RootPanel; import com.google.gapid.perfetto.views.State; import com.google.gapid.perfetto.views.TraceComposite; +import com.google.gapid.perfetto.views.TrackPanel; +import com.google.gapid.proto.service.Service; import com.google.gapid.util.Loadable; import com.google.gapid.util.Messages; +import com.google.gapid.util.Scheduler; import com.google.gapid.widgets.LoadablePanel; import com.google.gapid.widgets.Theme; import com.google.gapid.widgets.Widgets; @@ -115,6 +132,11 @@ public void onProfileLoaded(Loadable.Message error) { } private void updateProfile(Profile.Data data) { + if (!data.hasSlices()) { + loading.showMessage(Error, Messages.PROFILE_NO_SLICES); + return; + } + traceUi.update(data); } @@ -127,6 +149,23 @@ public TraceUi(Composite parent, Models models, Theme theme) { public void update(Profile.Data data) { panels.clear(); + + Service.ProfilingData.GpuSlices slices = data.getSlices(); + for (Service.ProfilingData.GpuSlices.Track track : slices.getTracksList()) { + List matched = Lists.newArrayList(); + int maxDepth = 0; + for (Service.ProfilingData.GpuSlices.Slice slice : slices.getSlicesList()) { + if (slice.getTrackId() == track.getId()) { + matched.add(slice); + maxDepth = Math.max(maxDepth, slice.getDepth()); + } + } + panels.add(new Container(new GpuQueuePanel(state, + new GpuInfo.Queue(track.getId(), track.getId(), maxDepth + 1), + new GpuSliceTrack(track.getId(), matched)))); + } + + state.update(data.getSlicesTimeSpan()); } @Override @@ -173,5 +212,130 @@ protected void preMainUiRender(RenderContext ctx, Repainter repainter) { } protected abstract Settings settings(); + + // TODO: dedupe with code in TrackContainer. + private static class Container extends Panel.Base { + private final TrackPanel track; + + public Container(TrackPanel panel) { + this.track = panel; + } + + @Override + public double getPreferredHeight() { + return track.getPreferredHeight(); + } + + @Override + public void setSize(double w, double h) { + super.setSize(w, h); + track.setSize(w, h); + } + + @Override + public void render(RenderContext ctx, Repainter repainter) { + ctx.withClip(0, 0, LABEL_WIDTH, height, () -> { + ctx.setForegroundColor(colors().textMain); + ctx.drawTextLeftTruncate(Fonts.Style.Normal, track.getTitle(), LABEL_MARGIN, 0, + LABEL_WIDTH - 2 * LABEL_MARGIN, TITLE_HEIGHT); + }); + + ctx.setForegroundColor(colors().panelBorder); + ctx.drawLine(LABEL_WIDTH - 1, 0, LABEL_WIDTH - 1, height); + ctx.drawLine(0, height - 1, width, height - 1); + track.render(ctx, repainter); + } + + @Override + public void visit(Visitor v, Area area) { + super.visit(v, area); + track.visit(v, area); + } + + @Override + public Dragger onDragStart(double x, double y, int mods) { + return track.onDragStart(x, y, mods); + } + + @Override + public Hover onMouseMove(Fonts.TextMeasurer m, double x, double y, int mods) { + return (x < LABEL_WIDTH) ? Hover.NONE : track.onMouseMove(m, x, y, mods); + } + } + + private static class GpuSliceTrack extends SliceTrack { + private final List slices; + + protected GpuSliceTrack(long trackId, List slices) { + super(trackId); + this.slices = slices; + } + + @Override + public ListenableFuture getSlice(long id) { + return Futures.immediateFuture(toSlice(slices.get((int)id))); + } + + @Override + public ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth) { + return Scheduler.EXECUTOR.submit(() -> slices.stream() + .filter(s -> ts.overlaps(s.getTs(), s.getTs() + s.getDur())) + .filter(s -> s.getDepth() >= minDepth && s.getDepth() <= maxDepth) + .map(this::toSlice) + .collect(toList())); + } + + @Override + protected ListenableFuture initialize() { + return Futures.immediateFuture(null); + } + + @Override + protected ListenableFuture computeData(DataRequest req) { + return Scheduler.EXECUTOR.submit(() -> { + List matched = Lists.newArrayList(); + for (int i = 0; i < slices.size(); i++) { + Service.ProfilingData.GpuSlices.Slice slice = slices.get(i); + if (req.range.overlaps(slice.getTs(), slice.getTs() + slice.getDur())) { + matched.add(new SliceAndId(slice, i)); + } + } + + int n = matched.size(); + Data data = new Data(req, new long[n], new long[n], new long[n], new int[n], new String[n], + new String[n], new ArgSet[n]); + for (int i = 0; i < n; i++) { + SliceAndId s = matched.get(i); + data.ids[i] = s.id; + data.starts[i] = s.slice.getTs(); + data.ends[i] = s.slice.getTs() + s.slice.getDur(); + data.depths[i] = s.slice.getDepth(); + data.titles[i] = s.slice.getLabel(); + data.categories[i] = ""; + data.args[i] = ArgSet.EMPTY; + } + return data; + }); + } + + private Slice toSlice(Service.ProfilingData.GpuSlices.Slice s) { + return new Slice(s.getTs(), s.getDur(), "", s.getLabel(), s.getDepth(), -1, -1, ArgSet.EMPTY) { + @Override + public String getTitle() { + return "GPU Render Stages"; + } + }; + } + + private static class SliceAndId { + public final Service.ProfilingData.GpuSlices.Slice slice; + public final int id; + + public SliceAndId(Service.ProfilingData.GpuSlices.Slice slice, int id) { + this.slice = slice; + this.id = id; + } + } + } } } From 356cce1758d50da496458a8f26a8dedf38788033 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 5 Feb 2020 16:30:56 +1300 Subject: [PATCH 0061/1218] Fix subsequent showing of profile view There were two issues here: * There is a transient state where the width is zero, before everything has been sized properly. This caused the visible exception * If the profile model was already available at the point the panel is created, then we would never hide the 'loading' overlay widgets, so they would obscure the actual profile view forever --- gapic/src/main/com/google/gapid/perfetto/views/State.java | 2 +- gapic/src/main/com/google/gapid/views/ProfileView.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/State.java b/gapic/src/main/com/google/gapid/perfetto/views/State.java index c71a042c56..a349ba0859 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/State.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/State.java @@ -323,7 +323,7 @@ public ListenableFuture onUiThread(Runnable run) { private void update() { nanosPerPx = visibleTime.getDuration() / width; - if (nanosPerPx <= 0) { + if (width <= 0 || nanosPerPx <= 0) { nanosPerPx = 0; resolution = 0; } else { diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java index 8cc380e454..9887e2f0cf 100644 --- a/gapic/src/main/com/google/gapid/views/ProfileView.java +++ b/gapic/src/main/com/google/gapid/views/ProfileView.java @@ -97,6 +97,7 @@ public Control getControl() { @Override public void reinitialize() { if (models.profile.isLoaded()) { + loading.stopLoading(); updateProfile(models.profile.getData()); } else { loading.showMessage( From 7ee4b228b7cf52f57c1a367bc41f0fe051ef74e9 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 11 Feb 2020 09:04:33 +1300 Subject: [PATCH 0062/1218] Name replay profiler 'Surface' slices according to their matched command id --- gapis/trace/android/adreno/profiling_data.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index 8c93cf50d7..fc8112b3e7 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -196,6 +196,10 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])}, }) + if names[i] == "Surface" { + names[i] = fmt.Sprintf("%v", groups[groupIds[i]].Link.Indices) + } + slices[i] = &service.ProfilingData_GpuSlices_Slice{ Ts: uint64(timestamps[i]), Dur: uint64(durations[i]), From 68c90efd7275ec13721611e8200752e4ab39301b Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Fri, 14 Feb 2020 11:32:23 +0000 Subject: [PATCH 0063/1218] Fix the issue of first command of the trace has CmdNoID (#47) --- gapis/api/transform/transforms.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/transform/transforms.go b/gapis/api/transform/transforms.go index 0cabe59904..bd0ba4821d 100644 --- a/gapis/api/transform/transforms.go +++ b/gapis/api/transform/transforms.go @@ -44,7 +44,7 @@ func (l Transforms) TransformAll(ctx context.Context, cmds []api.Cmd, numberOfIn } err := api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { captureCmdID := api.CmdNoID - if uint64(id) > numberOfInitialCommands { + if uint64(id) >= numberOfInitialCommands { captureCmdID = id - api.CmdID(numberOfInitialCommands) } From 51d4ec79bed045258806462443d6a726cd14c077 Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Fri, 14 Feb 2020 13:59:09 +0000 Subject: [PATCH 0064/1218] Remove the numInitialCmds from transforms (#48) as it is not needed now --- gapis/api/sync/sync.go | 2 +- gapis/api/transform/early_terminator.go | 2 +- gapis/api/transform/early_terminator_test.go | 6 +++--- gapis/api/transform/terminator.go | 2 +- gapis/api/vulkan/overdraw.go | 4 ++-- gapis/api/vulkan/replay.go | 17 ++++++----------- gapis/api/vulkan/vulkan_terminator.go | 2 +- 7 files changed, 15 insertions(+), 20 deletions(-) diff --git a/gapis/api/sync/sync.go b/gapis/api/sync/sync.go index 0b76ac22ba..9c00459c2a 100644 --- a/gapis/api/sync/sync.go +++ b/gapis/api/sync/sync.go @@ -143,7 +143,7 @@ func MutationCmdsFor(ctx context.Context, c *path.Capture, data *Data, cmds []ap terminators = append(terminators, transform.NewEarlyTerminator(api.ID())) } for _, t := range terminators { - if err := t.Add(ctx, 0, id, subindex); err != nil { + if err := t.Add(ctx, id, subindex); err != nil { return nil, err } transforms.Add(t) diff --git a/gapis/api/transform/early_terminator.go b/gapis/api/transform/early_terminator.go index a2d6faf5e5..7367c1bf58 100644 --- a/gapis/api/transform/early_terminator.go +++ b/gapis/api/transform/early_terminator.go @@ -32,7 +32,7 @@ func NewEarlyTerminator(api api.ID) Terminator { return &earlyTerminator{api: api} } -func (t *earlyTerminator) Add(ctx context.Context, extraCommands int, id api.CmdID, idx api.SubCmdIdx) error { +func (t *earlyTerminator) Add(ctx context.Context, id api.CmdID, idx api.SubCmdIdx) error { if id > t.lastID { t.lastID = id } diff --git a/gapis/api/transform/early_terminator_test.go b/gapis/api/transform/early_terminator_test.go index 0101e33c43..cd5d51777f 100644 --- a/gapis/api/transform/early_terminator_test.go +++ b/gapis/api/transform/early_terminator_test.go @@ -53,9 +53,9 @@ func TestEarlyTerminator(t *testing.T) { ) et := transform.NewEarlyTerminator(test.API{}.ID()) - et.Add(ctx, 0, 20, []uint64{0}) - et.Add(ctx, 0, 50, []uint64{}) - et.Add(ctx, 0, 70, []uint64{1}) + et.Add(ctx, 20, []uint64{0}) + et.Add(ctx, 50, []uint64{}) + et.Add(ctx, 70, []uint64{1}) CheckTransform(ctx, t, et, inputs, expected) } diff --git a/gapis/api/transform/terminator.go b/gapis/api/transform/terminator.go index 9d6b1fd1e6..14d4df4c2f 100644 --- a/gapis/api/transform/terminator.go +++ b/gapis/api/transform/terminator.go @@ -27,5 +27,5 @@ type Terminator interface { // Add relaxes the termination limit to pass-through all commands before and // including the command or subcommand. - Add(context.Context, int, api.CmdID, api.SubCmdIdx) error + Add(context.Context, api.CmdID, api.SubCmdIdx) error } diff --git a/gapis/api/vulkan/overdraw.go b/gapis/api/vulkan/overdraw.go index 10455a45f5..f487c2d054 100644 --- a/gapis/api/vulkan/overdraw.go +++ b/gapis/api/vulkan/overdraw.go @@ -51,7 +51,7 @@ func newStencilOverdraw() *stencilOverdraw { } } -func (s *stencilOverdraw) add(ctx context.Context, extraCommands uint64, after []uint64, capt *path.Capture, res replay.Result) { +func (s *stencilOverdraw) add(ctx context.Context, after []uint64, capt *path.Capture, res replay.Result) { c, err := capture.ResolveGraphicsFromPath(ctx, capt) if err != nil { res(nil, err) @@ -60,7 +60,7 @@ func (s *stencilOverdraw) add(ctx context.Context, extraCommands uint64, after [ for lastSubmit := int64(after[0]); lastSubmit >= 0; lastSubmit-- { switch (c.Commands[lastSubmit]).(type) { case *VkQueueSubmit: - id := api.CmdID(uint64(lastSubmit) + extraCommands) + id := api.CmdID(lastSubmit) s.rewrite[id] = res s.lastSubIdx[id] = api.SubCmdIdx(after[1:]) log.D(ctx, "Overdraw marked for submit id %v", lastSubmit) diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 118cf89e1b..553d0b977f 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -1000,21 +1000,17 @@ func (a API) Replay( timestamps.AddResult(rr.Result) optimize = false case framebufferRequest: - cfg := cfg.(drawConfig) if cfg.disableReplayOptimization { optimize = false } - extraCommands, err := expandCommands(optimize) - if err != nil { - return err - } - cmdid := req.after[0] + uint64(extraCommands) + + cmdID := req.after[0] if optimize { // Should have been built in expandCommands() if dceBuilder != nil { - dceBuilder.Request(ctx, api.SubCmdIdx{cmdid}) + dceBuilder.Request(ctx, api.SubCmdIdx{cmdID}) } else { optimize = false } @@ -1022,21 +1018,20 @@ func (a API) Replay( if cfg.drawMode == service.DrawMode_OVERDRAW { // TODO(subcommands): Add subcommand support here - if err := earlyTerminator.Add(ctx, extraCommands, api.CmdID(cmdid), req.after[1:]); err != nil { + if err := earlyTerminator.Add(ctx, api.CmdID(cmdID), req.after[1:]); err != nil { return err } if overdraw == nil { overdraw = newStencilOverdraw() } - overdraw.add(ctx, uint64(extraCommands), req.after, intent.Capture, rr.Result) + overdraw.add(ctx, req.after, intent.Capture, rr.Result) break } - if err := earlyTerminator.Add(ctx, extraCommands, api.CmdID(cmdid), api.SubCmdIdx{}); err != nil { + if err := earlyTerminator.Add(ctx, api.CmdID(cmdID), api.SubCmdIdx{}); err != nil { return err } subIdx := append(api.SubCmdIdx{}, req.after...) - subIdx[0] = subIdx[0] + uint64(extraCommands) splitter.Split(ctx, subIdx) switch cfg.drawMode { case service.DrawMode_WIREFRAME_ALL: diff --git a/gapis/api/vulkan/vulkan_terminator.go b/gapis/api/vulkan/vulkan_terminator.go index cadbd8b2a0..5e66cc77d1 100644 --- a/gapis/api/vulkan/vulkan_terminator.go +++ b/gapis/api/vulkan/vulkan_terminator.go @@ -58,7 +58,7 @@ func NewVulkanTerminator(ctx context.Context, capture *path.Capture) (*VulkanTer // Add adds the command with identifier id to the set of commands that must be // seen before the VulkanTerminator will consume all commands (excluding the EOS // command). -func (t *VulkanTerminator) Add(ctx context.Context, extraCommands int, id api.CmdID, subcommand api.SubCmdIdx) error { +func (t *VulkanTerminator) Add(ctx context.Context, id api.CmdID, subcommand api.SubCmdIdx) error { if len(t.requestSubIndex) != 0 { return log.Errf(ctx, nil, "Cannot handle multiple requests when requesting a subcommand") } From 704ed707f523045b46aeaf33009859fdbb560a04 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 14 Feb 2020 10:20:19 -0800 Subject: [PATCH 0065/1218] Update DEVDOC with one extra instruction. (#51) It's often unclear that one should specify the bazel output directory if AGI is built debuggable, update the DEVDOC with this instruction. Bug: N/A --- DEVDOC.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DEVDOC.md b/DEVDOC.md index 50a112b5f8..1ef2654a24 100644 --- a/DEVDOC.md +++ b/DEVDOC.md @@ -18,6 +18,9 @@ mkdir /agi-gofuse # Run gofuse with the previous directory as a target bazel run //cmd/gofuse -- -dir +# If you build with bazel build -c dbg pkg, the is `k8-dbg` on Linux. +bazel run //cmd/gofuse -- -dir -bazelout + # Add agi-gofuse directory to your GOPATH environment variable. # On Linux, with a bash shell, you can add the following to your ~/.bashrc file: export GOPATH="${GOPATH:+${GOPATH}:}" From d721661de794b2ecc14ed7a441f3319e269ad79e Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com> Date: Fri, 14 Feb 2020 11:02:38 -0800 Subject: [PATCH 0066/1218] Device validation ui (#39) Device validation UI Added device validation to the capture trace dialog. This prevents the user from starting a trace until the validation completes. Bug: 141712515 --- core/os/android/adb/commands.go | 13 ++ core/os/android/adb/device.go | 4 + core/os/device/device.proto | 2 + gapic/src/main/BUILD.bazel | 1 + gapic/src/main/com/google/gapid/Main.java | 2 + .../main/com/google/gapid/models/Devices.java | 108 +++++++++++++++- .../main/com/google/gapid/models/Models.java | 2 +- .../com/google/gapid/models/Settings.java | 4 + .../main/com/google/gapid/server/Client.java | 10 ++ .../com/google/gapid/server/GapidClient.java | 2 + .../google/gapid/server/GapidClientGrpc.java | 7 + .../src/main/com/google/gapid/settings.proto | 23 ++++ .../src/main/com/google/gapid/util/URLs.java | 3 + .../com/google/gapid/views/TracerDialog.java | 120 ++++++++++++++---- .../gapid/widgets/LoadingIndicator.java | 39 ++++-- 15 files changed, 298 insertions(+), 42 deletions(-) diff --git a/core/os/android/adb/commands.go b/core/os/android/adb/commands.go index 70586a84ce..2ab9269c88 100644 --- a/core/os/android/adb/commands.go +++ b/core/os/android/adb/commands.go @@ -414,6 +414,19 @@ func (b *binding) PrereleaseGraphicsDriver(ctx context.Context) (Driver, error) return b.resolveDriverPath(ctx, driver) } +// Returns the package version code of the graphics driver +func (b *binding) DriverVersionCode(ctx context.Context) (int, error) { + driver, err := b.SystemProperty(ctx, driverProperty) + if err != nil { + return 0, err + } + ip, err := b.InstalledPackage(ctx, driver) + if err != nil { + return 0, err + } + return ip.VersionCode, err +} + // DriverPackage queries and returns the package of the preview graphics driver. func (b *binding) GraphicsDriver(ctx context.Context) (Driver, error) { // Check if there is an override setup. diff --git a/core/os/android/adb/device.go b/core/os/android/adb/device.go index f2b4f1e9ab..701c67e1f6 100644 --- a/core/os/android/adb/device.go +++ b/core/os/android/adb/device.go @@ -241,6 +241,10 @@ func newDevice(ctx context.Context, serial string, status bind.Status) (*binding i.GenID() } + if version, err := d.DriverVersionCode(ctx); err == nil { + d.To.Configuration.Drivers.Vulkan.Version = strconv.Itoa(version) + } + return d, nil } diff --git a/core/os/device/device.proto b/core/os/device/device.proto index ac6b7e11fb..ba0dd871e8 100644 --- a/core/os/device/device.proto +++ b/core/os/device/device.proto @@ -245,6 +245,8 @@ message VulkanDriver { repeated string icd_and_implicit_layer_extensions = 2; // Physical devices that have Vulkan support. repeated VulkanPhysicalDevice physical_devices = 3; + // Driver package version + string version = 4; } // VulkanLayer describes the layers currently installed on the device, diff --git a/gapic/src/main/BUILD.bazel b/gapic/src/main/BUILD.bazel index 3ed9f1fb04..6f16bccb2a 100644 --- a/gapic/src/main/BUILD.bazel +++ b/gapic/src/main/BUILD.bazel @@ -77,6 +77,7 @@ proto_library( name = "settings_proto", srcs = ["com/google/gapid/settings.proto"], deps = [ + "//core/os/device:device_proto", "@perfetto//:protos_perfetto_config_merged_config_protos", ], ) diff --git a/gapic/src/main/com/google/gapid/Main.java b/gapic/src/main/com/google/gapid/Main.java index 5bcb78c02f..e179051f25 100644 --- a/gapic/src/main/com/google/gapid/Main.java +++ b/gapic/src/main/com/google/gapid/Main.java @@ -23,6 +23,7 @@ import com.google.common.base.Throwables; import com.google.gapid.Server.GapisInitException; import com.google.gapid.models.Analytics; +import com.google.gapid.models.Devices; import com.google.gapid.models.Follower; import com.google.gapid.models.Models; import com.google.gapid.models.Settings; @@ -196,6 +197,7 @@ private static interface ShellRunnable { Flags.help, Flags.fullHelp, Flags.version, + Devices.skipDeviceValidation, GapiPaths.gapidPath, GapiPaths.adbPath, GapisProcess.disableGapisTimeout, diff --git a/gapic/src/main/com/google/gapid/models/Devices.java b/gapic/src/main/com/google/gapid/models/Devices.java index 21fe458bec..a297fa7885 100644 --- a/gapic/src/main/com/google/gapid/models/Devices.java +++ b/gapic/src/main/com/google/gapid/models/Devices.java @@ -15,12 +15,14 @@ */ package com.google.gapid.models; +import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.gapid.util.Logging.throttleLogRpcError; import static java.util.stream.Collectors.toList; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.gapid.proto.SettingsProto.DeviceValidation; import com.google.gapid.proto.device.Device; import com.google.gapid.proto.device.Device.Instance; import com.google.gapid.proto.service.Service; @@ -33,6 +35,8 @@ import com.google.gapid.rpc.UiErrorCallback; import com.google.gapid.server.Client; import com.google.gapid.util.Events; +import com.google.gapid.util.Flags; +import com.google.gapid.util.Flags.Flag; import com.google.gapid.util.Loadable; import com.google.gapid.util.MoreFutures; import com.google.gapid.util.Paths; @@ -57,11 +61,17 @@ public class Devices { private List replayDevices; private Device.Instance selectedReplayDevice; private List devices; + private DeviceValidationInfo deviceValidationInfo; - public Devices(Shell shell, Analytics analytics, Client client, Capture capture) { + public static final Flag skipDeviceValidation = Flags.value("skip-device-validation", false, + "Skips the device validation process. " + + "Device validation verifies that the GPU events emitted are within the acceptable threshold.", true); + + public Devices(Shell shell, Analytics analytics, Client client, Capture capture, Settings settings) { this.shell = shell; this.analytics = analytics; this.client = client; + deviceValidationInfo = new DeviceValidationInfo(client, settings); capture.addListener(new Capture.Listener() { @Override @@ -142,6 +152,14 @@ public void selectReplayDevice(Device.Instance dev) { listeners.fire().onReplayDeviceChanged(dev); } + public ListenableFuture validateDevice(DeviceCaptureInfo device) { + return deviceValidationInfo.doValidation(device); + } + + public DeviceValidationResult getValidationStatus(DeviceCaptureInfo device) { + return deviceValidationInfo.getValidationStatus(device); + } + public void loadDevices() { rpcController.start().listen(MoreFutures.transformAsync(client.getDevices(), paths -> { List> results = Lists.newArrayList(); @@ -295,4 +313,92 @@ public boolean isStadia() { return device.getConfiguration().getOS().getKind() == Device.OSKind.Stadia; } } + + /* + * Class that handles the gapis communication for device validation and the load/store + * of the validation cache. + */ + private static class DeviceValidationInfo { + private final Client client; + private DeviceValidation.Builder deviceValidation; + + public DeviceValidationInfo(Client client, Settings settings) { + this.client = client; + deviceValidation = settings.writeDeviceValidation(); + } + + private static DeviceValidation.ValidationEntry buildValidationEntry(DeviceCaptureInfo device) { + return DeviceValidation.ValidationEntry.newBuilder() + .setDevice(DeviceValidation.Device.newBuilder() + .setSerial(device.device.getSerial()) + .setOs(device.device.getConfiguration().getOS()) + .setVersion(device.device.getConfiguration().getDrivers().getVulkan().getVersion())) + .setResult(DeviceValidation.Result.newBuilder() + .setPassed(true)) + .build(); + } + + // TODO(b/149406313): Move to UI thread to avoid synchronization + public synchronized DeviceValidationResult getValidationStatus(DeviceCaptureInfo device) { + if (skipDeviceValidation.get()) { + return DeviceValidationResult.getSkippedResult(); + } + DeviceValidation.ValidationEntry entry = buildValidationEntry(device); + if (deviceValidation.getValidationEntriesList().contains(entry)) { + return DeviceValidationResult.getPassedResult(); + } + return DeviceValidationResult.getFailedResult(); + } + + // TODO(b/149406313): Move to UI thread to avoid synchronization + public synchronized ListenableFuture doValidation(DeviceCaptureInfo device) { + if (device == null) { + return immediateFuture(DeviceValidationResult.getFailedResult()); + } + DeviceValidation.ValidationEntry currentEntry = buildValidationEntry(device); + if (deviceValidation.getValidationEntriesList().contains(currentEntry)) { + return immediateFuture(DeviceValidationResult.getPassedResult()); + } + + return MoreFutures.transform(client.validateDevice(device.path), e -> { + updateValidationStatus(currentEntry, e); + return new DeviceValidationResult(e.getError(), !e.hasError(), false); + }); + } + + // TODO(b/149406313): Move to UI thread to avoid synchronization + protected synchronized void updateValidationStatus(DeviceValidation.ValidationEntry entry, Service.ValidateDeviceResponse response) { + if (response == null || response.hasError()) { + return; + } + deviceValidation.addValidationEntries(entry); + } + } + + public static class DeviceValidationResult { + private static DeviceValidationResult passedResult = new DeviceValidationResult(null, true, false); + private static DeviceValidationResult failedResult = new DeviceValidationResult(null, false, false); + private static DeviceValidationResult skippedResult = new DeviceValidationResult(null, true, true); + public Service.Error error; + public boolean passed; + public boolean skipped; + + public DeviceValidationResult(Service.Error error, boolean passed, boolean skipped) { + this.error = error; + this.passed = passed; + this.skipped = skipped; + } + + public static DeviceValidationResult getPassedResult() { + return passedResult; + } + + public static DeviceValidationResult getSkippedResult() { + return skippedResult; + } + + public static DeviceValidationResult getFailedResult() { + return failedResult; + } + } } diff --git a/gapic/src/main/com/google/gapid/models/Models.java b/gapic/src/main/com/google/gapid/models/Models.java index e9d67351e9..9fbd401012 100644 --- a/gapic/src/main/com/google/gapid/models/Models.java +++ b/gapic/src/main/com/google/gapid/models/Models.java @@ -73,7 +73,7 @@ public static Models create( Analytics analytics = new Analytics(client, settings, handler); Follower follower = new Follower(shell, client); Capture capture = new Capture(shell, analytics, client, settings); - Devices devices = new Devices(shell, analytics, client, capture); + Devices devices = new Devices(shell, analytics, client, capture, settings); ConstantSets constants = new ConstantSets(client, devices); ApiContext contexts = new ApiContext(shell, analytics, client, capture, devices); Timeline timeline = new Timeline(shell, analytics, client, capture, devices, contexts); diff --git a/gapic/src/main/com/google/gapid/models/Settings.java b/gapic/src/main/com/google/gapid/models/Settings.java index 3888b3e845..10c12f9fe6 100644 --- a/gapic/src/main/com/google/gapid/models/Settings.java +++ b/gapic/src/main/com/google/gapid/models/Settings.java @@ -220,6 +220,10 @@ public SettingsProto.Perfetto.Builder writePerfetto() { return proto.getPerfettoBuilder(); } + public SettingsProto.DeviceValidation.Builder writeDeviceValidation() { + return proto.getDeviceValidationBuilder(); + } + public int[] getSplitterWeights(SplitterWeights type) { return type.get(ui()); } diff --git a/gapic/src/main/com/google/gapid/server/Client.java b/gapic/src/main/com/google/gapid/server/Client.java index 2803843676..b7cd88cbc1 100644 --- a/gapic/src/main/com/google/gapid/server/Client.java +++ b/gapic/src/main/com/google/gapid/server/Client.java @@ -257,6 +257,7 @@ public ListenableFuture perfettoQuery(Path.Capture capture in -> immediateFuture(throwIfError(in.getResult(), in.getError(), stack)))); } + public ListenableFuture profile(Path.Capture capture, Path.Device device) { return call(() -> String.format( "RPC->profile(%s, %s)", shortDebugString(capture), shortDebugString(device)), @@ -268,6 +269,15 @@ public ListenableFuture profile(Path.Capture capture, Pat in -> immediateFuture(throwIfError(in.getProfilingData(), in.getError(), stack)))); } + public ListenableFuture validateDevice(Path.Device device) { + return call(() -> String.format("RPC->validateDevice(%s)", shortDebugString(device)), + stack -> MoreFutures.transformAsync( + client.validateDevice(Service.ValidateDeviceRequest.newBuilder() + .setDevice(device) + .build()), + in -> immediateFuture(in))); + } + public ListenableFuture streamLog(Consumer onLogMessage) { LOG.log(FINE, "RPC->getLogStream()"); return client.streamLog(onLogMessage); diff --git a/gapic/src/main/com/google/gapid/server/GapidClient.java b/gapic/src/main/com/google/gapid/server/GapidClient.java index 8dfb6d2c0e..1e5b378f7b 100644 --- a/gapic/src/main/com/google/gapid/server/GapidClient.java +++ b/gapic/src/main/com/google/gapid/server/GapidClient.java @@ -60,6 +60,8 @@ public ListenableFuture updateSettings( public ListenableFuture perfettoQuery( Service.PerfettoQueryRequest request); public ListenableFuture profile(Service.GpuProfileRequest request); + public ListenableFuture validateDevice( + Service.ValidateDeviceRequest request); public ListenableFuture streamLog(Consumer onLogMessage); public ListenableFuture streamStatus( diff --git a/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java b/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java index be1cfd8beb..f815886420 100644 --- a/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java +++ b/gapic/src/main/com/google/gapid/server/GapidClientGrpc.java @@ -33,6 +33,8 @@ import com.google.gapid.proto.service.Service.TraceTargetTreeNodeResponse; import com.google.gapid.proto.service.Service.UpdateSettingsRequest; import com.google.gapid.proto.service.Service.UpdateSettingsResponse; +import com.google.gapid.proto.service.Service.ValidateDeviceRequest; +import com.google.gapid.proto.service.Service.ValidateDeviceResponse; import com.google.gapid.util.MoreFutures; import java.util.function.Consumer; @@ -169,6 +171,11 @@ public ListenableFuture profile(GpuProfileRequest request) { return client.gpuProfile(request); } + @Override + public ListenableFuture validateDevice(ValidateDeviceRequest request) { + return client.validateDevice(request); + } + @Override public ListenableFuture streamLog(Consumer onLogMessage) { StreamHandler handler = StreamHandler.wrap(onLogMessage); diff --git a/gapic/src/main/com/google/gapid/settings.proto b/gapic/src/main/com/google/gapid/settings.proto index 183e3aba81..c86a5fc5cf 100644 --- a/gapic/src/main/com/google/gapid/settings.proto +++ b/gapic/src/main/com/google/gapid/settings.proto @@ -19,6 +19,8 @@ import "protos/perfetto/config/perfetto_config.proto"; option java_package = "com.google.gapid.proto"; option java_outer_classname = "SettingsProto"; +import "core/os/device/device.proto"; + message Point { int32 x = 1; int32 y = 2; @@ -169,4 +171,25 @@ message Settings { UI ui = 6; Trace trace = 7; Perfetto perfetto = 8; + DeviceValidation device_validation = 9; +} + +// DeviceValidation contains the list of validated devices. +message DeviceValidation { + message Device { + string serial = 1; + device.OS os = 2; + // The pre-release driver APK version code + string version = 3; + } + + message Result { + bool passed = 1; + } + + message ValidationEntry { + Device device = 1; + Result result = 2; + } + repeated ValidationEntry validation_entries = 1; } diff --git a/gapic/src/main/com/google/gapid/util/URLs.java b/gapic/src/main/com/google/gapid/util/URLs.java index 52d73b9eff..2237f2afe4 100644 --- a/gapic/src/main/com/google/gapid/util/URLs.java +++ b/gapic/src/main/com/google/gapid/util/URLs.java @@ -18,4 +18,7 @@ public interface URLs { public static final String FILE_BUG_URL = "https://github.com/google/gapid/issues/new?template=standard-bug-report-for-gapid.md"; + // TODO(b/148700785): Create the device compatibility doc and update here + public static final String DEVICE_COMPATIBILITY_URL = + "https://github.com/google/agi"; } \ No newline at end of file diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index 45fc9bfa22..68235ba46c 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -18,6 +18,7 @@ import static com.google.gapid.perfetto.views.TraceConfigDialog.getConfig; import static com.google.gapid.perfetto.views.TraceConfigDialog.getConfigSummary; import static com.google.gapid.perfetto.views.TraceConfigDialog.showPerfettoConfigDialog; +import static com.google.gapid.util.Logging.throttleLogRpcError; import static com.google.gapid.util.MoreFutures.logFailure; import static com.google.gapid.widgets.Widgets.createBoldLabel; import static com.google.gapid.widgets.Widgets.createCheckbox; @@ -35,12 +36,14 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; +import static java.util.logging.Level.WARNING; import com.google.common.collect.Lists; import com.google.gapid.models.Analytics; import com.google.gapid.models.Analytics.View; import com.google.gapid.models.Devices; import com.google.gapid.models.Devices.DeviceCaptureInfo; +import com.google.gapid.models.Devices.DeviceValidationResult; import com.google.gapid.models.Models; import com.google.gapid.models.Settings; import com.google.gapid.models.TraceTargets; @@ -52,6 +55,10 @@ import com.google.gapid.proto.service.Service.StatusResponse; import com.google.gapid.proto.service.Service.TraceType; import com.google.gapid.proto.service.Service.TraceTypeCapabilities; +import com.google.gapid.rpc.Rpc; +import com.google.gapid.rpc.RpcException; +import com.google.gapid.rpc.SingleInFlight; +import com.google.gapid.rpc.UiErrorCallback; import com.google.gapid.server.Client; import com.google.gapid.server.Tracer; import com.google.gapid.server.Tracer.TraceRequest; @@ -60,6 +67,7 @@ import com.google.gapid.util.Messages; import com.google.gapid.util.OS; import com.google.gapid.util.Scheduler; +import com.google.gapid.util.URLs; import com.google.gapid.widgets.ActionTextbox; import com.google.gapid.widgets.DialogBase; import com.google.gapid.widgets.FileTextbox; @@ -78,6 +86,7 @@ import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.program.Program; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; @@ -101,6 +110,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -272,19 +282,23 @@ private static class TraceInput extends Composite { private static final String MEC_LABEL_WARNING = "NOTE: Mid-Execution capture for %s is experimental"; private static final String PERFETTO_LABEL = "Profile Config: "; - private static final String NO_GPU_PROFILING_CAPABILITY = "Warning: Selected device has no GPU profiling capability."; private static final String EMPTY_APP_WITH_RENDER_STAGE = "Warning: Application needs to be specified for GPU profiling data."; + private static final String VALIDATION_FAILED_LANDING_PAGE = "Learn about device compatibility"; private final String date = TRACE_DATE_FORMAT.format(new Date()); private List devices; + private final SingleInFlight rpcController = new SingleInFlight(); + private final Models models; private final ComboViewer device; private final Label deviceLabel; private final LoadingIndicator.Widget deviceLoader; private final ComboViewer api; private final Label apiLabel; + private final LoadingIndicator.Widget validationStatusLoader; + private final Link validationStatusText; private final ActionTextbox traceTarget; private final Label targetLabel; private final Text arguments; @@ -308,15 +322,17 @@ private static class TraceInput extends Composite { private final Label fileLabel; private final Label pcsWarning; private final Label requiredFieldMessage; - private final Label gpuProfilingCapabilityWarning; private final Label emptyAppWarning; protected String friendlyName = ""; protected boolean userHasChangedOutputFile = false; protected boolean userHasChangedTarget = false; + public boolean validationStatus; + public TraceInput(Composite parent, Models models, Widgets widgets, Runnable refreshDevices) { super(parent, SWT.NONE); + this.models = models; SettingsProto.TraceOrBuilder trace = models.settings.trace(); this.friendlyName = trace.getFriendlyName(); @@ -343,6 +359,17 @@ public TraceInput(Composite parent, Models models, Widgets widgets, Runnable ref apiLabel = createLabel(mainGroup, "Type*:"); api = createApiDropDown(mainGroup); api.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + // dummy label to fill the 3rd column + createLabel(mainGroup, ""); + + validationStatusLoader = widgets.loading.createWidgetWithImage(mainGroup, widgets.theme.smile(), widgets.theme.error()); + validationStatusLoader.setLayoutData( + withIndents(new GridData(SWT.LEFT, SWT.BOTTOM, false, false), 0, 0)); + validationStatusText = createLink(mainGroup, "", e-> { + Program.launch(URLs.DEVICE_COMPATIBILITY_URL); + }); + validationStatusText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + validationStatus = false; Group appGroup = withLayoutData( createGroup(this, "Application", new GridLayout(2, false)), @@ -457,12 +484,6 @@ protected void configureDialog(DirectoryDialog dialog) { requiredFieldMessage.setForeground(getDisplay().getSystemColor(SWT.COLOR_RED)); requiredFieldMessage.setVisible(false); - gpuProfilingCapabilityWarning = withLayoutData( - createLabel(this, NO_GPU_PROFILING_CAPABILITY), - new GridData(SWT.FILL, SWT.FILL, true, false)); - gpuProfilingCapabilityWarning.setForeground(getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW)); - gpuProfilingCapabilityWarning.setVisible(false); - Link adbWarning = withLayoutData( createLink(this, "Path to adb invalid/missing. " + "To trace on Android, please fix it in the preferences.", @@ -471,26 +492,14 @@ protected void configureDialog(DirectoryDialog dialog) { adbWarning.setForeground(getDisplay().getSystemColor(SWT.COLOR_DARK_RED)); adbWarning.setVisible(!models.settings.isAdbValid()); - device.getCombo().addListener(SWT.Selection, - e -> updateOnDeviceChange(models.settings, getSelectedDevice())); - api.getCombo().addListener(SWT.Selection, e -> updateOnApiChange(trace, getSelectedApi())); - Listener gpuProfilingCapabilityListener = e -> { - // Skip if the device is not Android device, or trace type is not Perfetto. - if (getSelectedDevice() == null || !getSelectedDevice().isAndroid() || - getSelectedApi() == null || getSelectedApi().getType() != TraceType.Perfetto) { - gpuProfilingCapabilityWarning.setVisible(false); - return; - } - Device.GPUProfiling gpuCaps = getPerfettoCaps().getGpuProfiling(); - if (gpuCaps.getHasRenderStage() && gpuCaps.getGpuCounterDescriptor().getSpecsCount() > 0) { - gpuProfilingCapabilityWarning.setVisible(false); - return; - } - gpuProfilingCapabilityWarning.setVisible(true); - }; - device.getCombo().addListener(SWT.Selection, gpuProfilingCapabilityListener); - api.getCombo().addListener(SWT.Selection, gpuProfilingCapabilityListener); + device.getCombo().addListener(SWT.Selection, e -> { + updateOnDeviceChange(models.settings, getSelectedDevice()); + runValidationCheck(getSelectedDevice()); + }); + api.getCombo().addListener(SWT.Selection, e -> { + updateOnApiChange(trace, getSelectedApi()); + }); emptyAppWarning = withLayoutData( createLabel(this, EMPTY_APP_WITH_RENDER_STAGE), @@ -545,7 +554,7 @@ private void colorFilledInput(Theme theme) { return; } - requiredFieldMessage.setVisible(!this.isReady()); + requiredFieldMessage.setVisible(!this.isInputReady()); deviceLabel.setForeground(getSelectedDevice() == null ? theme.missingInput() : theme.filledInput()); directoryLabel.setForeground(directory.getText().isEmpty() ? theme.missingInput() : theme.filledInput()); fileLabel.setForeground(file.getText().isEmpty() ? theme.missingInput() : theme.filledInput()); @@ -601,6 +610,56 @@ private void updateOnDeviceChange(Settings settings, DeviceCaptureInfo dev) { updatePerfettoConfigLabel(settings); } + private void runValidationCheck(DeviceCaptureInfo dev) { + if (dev == null) { + return; + } + setValidationStatus(models.devices.getValidationStatus(dev)); + if (!models.devices.getValidationStatus(dev).passed) { + validationStatusLoader.startLoading(); + validationStatusText.setText("Device is being validated"); + rpcController.start().listen(models.devices.validateDevice(dev), + new UiErrorCallback(validationStatusLoader, LOG) { + @Override + protected ResultOrError + onRpcThread(Rpc.Result response) throws RpcException, ExecutionException { + try { + return success(response.get()); + } catch (RpcException | ExecutionException e) { + throttleLogRpcError(LOG, "LoadData error", e); + return error(null); + } + } + + @Override + protected void onUiThreadSuccess(DeviceValidationResult result) { + setValidationStatus(result); + } + + @Override + protected void onUiThreadError(DeviceValidationResult result) { + LOG.log(WARNING, "UI thread error while validating device"); + setValidationStatus(result); + } + }); + } + } + + protected void setValidationStatus(DeviceValidationResult result) { + if (result.skipped) { + validationStatusLoader.updateStatus(true); + validationStatusLoader.stopLoading(); + validationStatusText.setText("Validation skipped."); + validationStatus = true; + } else { + validationStatusLoader.updateStatus(result.passed); + validationStatusText.setText("Validation " + (result.passed ? "Passed." : "Failed. " + VALIDATION_FAILED_LANDING_PAGE)); + validationStatusLoader.stopLoading(); + validationStatus = result.passed; + } + notifyListeners(SWT.Modify, new Event()); + } + private void updateOnApiChange( SettingsProto.TraceOrBuilder trace, TraceTypeCapabilities config) { boolean pcs = config != null && config.getCanDisablePcs(); @@ -801,6 +860,10 @@ protected String formatTraceName(String name) { } public boolean isReady() { + return isInputReady() && validationStatus; + } + + public boolean isInputReady() { TraceTypeCapabilities config = getSelectedApi(); return getSelectedDevice() != null && config != null && (!config.getRequiresApplication() || !traceTarget.getText().isEmpty()) && @@ -813,6 +876,7 @@ public void addModifyListener(Listener listener) { traceTarget.addBoxListener(SWT.Modify, listener); directory.addBoxListener(SWT.Modify, listener); file.addListener(SWT.Modify, listener); + this.addListener(SWT.Modify, listener); } public void setDevices(Settings settings, List devices) { diff --git a/gapic/src/main/com/google/gapid/widgets/LoadingIndicator.java b/gapic/src/main/com/google/gapid/widgets/LoadingIndicator.java index e83841d5ce..8f4516be33 100644 --- a/gapic/src/main/com/google/gapid/widgets/LoadingIndicator.java +++ b/gapic/src/main/com/google/gapid/widgets/LoadingIndicator.java @@ -75,12 +75,8 @@ public void paint(GC g, int x, int y, int w, int h, String text) { } } - public void paintRefresh(GC g, int x, int y, Point size) { - paintRefresh(g, x, y, size.x, size.y); - } - - public void paintRefresh(GC g, int x, int y, int w, int h) { - paint(refresh, g, x, y, w, h); + public void paint(Image image, GC g, int x, int y, Point size) { + paint(image, g, x, y, size.x, size.y); } private static int paint(Image image, GC g, int x, int y, int w, int h) { @@ -129,11 +125,15 @@ private void redrawAll() { } public Widget createWidget(Composite parent) { - return new Widget(parent, false); + return new Widget(parent, null, null); } public Widget createWidgetWithRefresh(Composite parent) { - return new Widget(parent, true); + return new Widget(parent, refresh, refresh); + } + + public Widget createWidgetWithImage(Composite parent, Image success, Image failure) { + return new Widget(parent, success, failure); } /** @@ -148,22 +148,37 @@ public interface Repaintable { /** * Widget that shows the loading indicator while loading and is blank once done. + * Can optionally show an image when done. */ public class Widget extends Canvas implements Loadable, Repaintable { - private boolean loading = false; + private final Image successImage; + private final Image failureImage; - public Widget(Composite parent, boolean showRefresh) { + protected boolean loading = false; + protected boolean status = false; + + public Widget(Composite parent, Image success, Image failure) { super(parent, SWT.DOUBLE_BUFFERED); + successImage = success; + failureImage = failure; addListener(SWT.Paint, e -> { if (loading) { paint(e.gc, 0, 0, getSize(), ""); scheduleForRedraw(this); - } else if (showRefresh) { - paintRefresh(e.gc, 0, 0, getSize()); + } else { + Image image = status ? successImage : failureImage; + if (image != null) { + paint(image, e.gc, 0, 0, getSize()); + } } }); } + public void updateStatus(boolean status) { + this.status = status; + scheduleForRedraw(this); + } + @Override public void startLoading() { loading = true; From 42241e51f4414b3684fd33824cfc338a71537b8a Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Fri, 14 Feb 2020 11:09:43 -0800 Subject: [PATCH 0067/1218] Print links in GAPIT (#53) --- cmd/gapit/dump_pipeline.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/gapit/dump_pipeline.go b/cmd/gapit/dump_pipeline.go index a3fa95e6e4..19f77a60bb 100644 --- a/cmd/gapit/dump_pipeline.go +++ b/cmd/gapit/dump_pipeline.go @@ -126,6 +126,9 @@ func toString(dataval *api.DataValue) string { case *api.DataValue_Bitfield: return strings.Join(x.Bitfield.SetBitnames, " | ") + + case *api.DataValue_Link: + return toString(x.Link.DisplayVal) } return "" From 2f25b7248cc5e8f403251d51254040ecb7c48638 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 14 Feb 2020 13:01:31 -0800 Subject: [PATCH 0068/1218] Add perfetto protos to gofuse. (#50) gofuse commnad has output all generated protobuf go files of the project to gofuse directory, however, Perfetto protos are in the third_party directory which is not scanned at all. This patch adds Perfetto directory in the mapping path so that all Perfetto protos are output to gofuse directory and indexable by IDE. Bug: N/A Test: bazel run //cmd/gofuse -- -dir GOFUSE_OUTPUT_DIR --- cmd/gofuse/main.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cmd/gofuse/main.go b/cmd/gofuse/main.go index 0ccf991f71..b9cdbbf6ea 100644 --- a/cmd/gofuse/main.go +++ b/cmd/gofuse/main.go @@ -208,8 +208,17 @@ func run() error { extMapping = append(extMapping, m...) } + thirdPartiesOut := filepath.Join(projectRoot, "bazel-out", *bazelOutDirectory, "bin", "tools", "build", "third_party") + fmt.Println("Collecting generated .go from:", thirdPartiesOut) + perfettoProtosMappingOut := collect(thirdPartiesOut, always).ifTrue(and( + isFile, + contains(filepath.Join("protos", "perfetto")), + hasSuffix(".go")), + ).mapping(func(path string) string { + return filepath.Join(fusedRoot, "src", trimUpTo(rel(projectRoot, path), "protos")) + }) // Every mapping we're going to deal with. - allMappings := join(srcMapping, genfilesMappingOut, binMappingOut, templateGenedGofiles, templateGenedCppfiles, extMapping) + allMappings := join(srcMapping, genfilesMappingOut, binMappingOut, templateGenedGofiles, templateGenedCppfiles, extMapping, perfettoProtosMappingOut) // Remove all existing symlinks in the fused directory that are not part of the // mappings. This may never happen if the OS automatically deletes deleted From 8b3d064be18b013c12ce9faa4d1a637032040d60 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 14 Feb 2020 15:38:59 +1300 Subject: [PATCH 0069/1218] Remove global what-if experiments These are not used by the current replay profiler implementation. We will reintroduce replay experiments at some point, but when we do, they will be local experiments targeting a particular command. If we need to refer to the old code it's available in the git history Bug: b/149528237 --- gapis/api/gles/replay.go | 7 +- gapis/api/vulkan/BUILD.bazel | 6 - gapis/api/vulkan/minimize_textures.go | 191 ------------------ gapis/api/vulkan/minimize_viewport.go | 184 ----------------- gapis/api/vulkan/replay.go | 21 +- .../api/vulkan/set_primitive_count_to_one.go | 150 -------------- gapis/api/vulkan/simplify_fragment_shader.go | 161 --------------- gapis/api/vulkan/simplify_sampling.go | 61 ------ gapis/replay/gpu_profile.go | 2 +- gapis/replay/interfaces.go | 4 +- gapis/service/path/path.proto | 8 - 11 files changed, 6 insertions(+), 789 deletions(-) delete mode 100644 gapis/api/vulkan/minimize_textures.go delete mode 100644 gapis/api/vulkan/minimize_viewport.go delete mode 100644 gapis/api/vulkan/set_primitive_count_to_one.go delete mode 100644 gapis/api/vulkan/simplify_fragment_shader.go delete mode 100644 gapis/api/vulkan/simplify_sampling.go diff --git a/gapis/api/gles/replay.go b/gapis/api/gles/replay.go index 155acdaacf..592c6c902a 100644 --- a/gapis/api/gles/replay.go +++ b/gapis/api/gles/replay.go @@ -30,7 +30,6 @@ import ( "github.com/google/gapid/gapis/replay" "github.com/google/gapid/gapis/resolve/dependencygraph" "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" ) var ( @@ -73,7 +72,6 @@ type framebufferRequest struct { } type profileRequest struct { - overrides *path.OverrideConfig } // GetReplayPriority returns a uint32 representing the preference for @@ -361,11 +359,10 @@ func (a API) Profile( intent replay.Intent, mgr replay.Manager, hints *service.UsageHints, - traceOptions *service.TraceOptions, - overrides *path.OverrideConfig) (*service.ProfilingData, error) { + traceOptions *service.TraceOptions) (*service.ProfilingData, error) { c := uniqueConfig() - r := profileRequest{overrides} + r := profileRequest{} _, err := mgr.Replay(ctx, intent, c, r, a, hints, true) return nil, err diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel index 626eb3f9c5..1636731e83 100644 --- a/gapis/api/vulkan/BUILD.bazel +++ b/gapis/api/vulkan/BUILD.bazel @@ -79,8 +79,6 @@ go_library( "links.go", "mem_binding_list.go", "memory_breakdown.go", - "minimize_textures.go", - "minimize_viewport.go", "overdraw.go", "primeable_image_data.go", "profiling_layers.go", @@ -90,9 +88,6 @@ go_library( "replay.go", "resources.go", "scratch_resources.go", - "set_primitive_count_to_one.go", - "simplify_fragment_shader.go", - "simplify_sampling.go", "slice_command_mapper.go", "state.go", "state_rebuilder.go", @@ -120,7 +115,6 @@ go_library( "//core/image/astc:go_default_library", "//core/log:go_default_library", "//core/math/interval:go_default_library", - "//core/math/u32:go_default_library", "//core/memory/arena:go_default_library", # keep "//core/os/device:go_default_library", "//core/stream:go_default_library", diff --git a/gapis/api/vulkan/minimize_textures.go b/gapis/api/vulkan/minimize_textures.go deleted file mode 100644 index 95836af7ab..0000000000 --- a/gapis/api/vulkan/minimize_textures.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package vulkan - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" -) - -// minimizeTextures returns a transform that sets the size of textures to 1x1 -func minimizeTextures(ctx context.Context) transform.Transformer { - ctx = log.Enter(ctx, "Minimize textures") - return transform.Transform("Minimize textures", func(ctx context.Context, - id api.CmdID, cmd api.Cmd, out transform.Writer) error { - - const newTexWidth = 1 - const newTexHeight = 1 - - s := out.State() - a := s.Arena - l := s.MemoryLayout - cb := CommandBuilder{Thread: cmd.Thread(), Arena: a} - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - switch cmd := cmd.(type) { - - case *VkCreateImage: - imageCreateInfo := cmd.PCreateInfo().MustRead(ctx, cmd, s, nil) - if 0 != (imageCreateInfo.Usage() & VkImageUsageFlags(VkImageUsageFlagBits_VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { - return out.MutateAndWrite(ctx, id, cmd) - } - - imageCreateInfo.SetExtent(NewVkExtent3D(a, newTexWidth, newTexHeight, imageCreateInfo.Extent().Depth())) - imageCreateInfo.SetMipLevels(1) - - imageCreateInfoData := s.AllocDataOrPanic(ctx, imageCreateInfo) - defer imageCreateInfoData.Free() - - newCmd := cb.VkCreateImage( - cmd.Device(), - imageCreateInfoData.Ptr(), - cmd.PAllocator(), - cmd.PImage(), - VkResult_VK_SUCCESS, - ).AddRead(imageCreateInfoData.Data()) - - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - return out.MutateAndWrite(ctx, id, newCmd) - - case *VkCmdCopyBufferToImage: - bufferImageCopy := cmd.PRegions().Slice(0, 1, l).MustRead(ctx, cmd, s, nil)[0] - imageSubresource := bufferImageCopy.ImageSubresource() - imageSubresource.SetMipLevel(0) - bufferImageCopy.SetImageSubresource(imageSubresource) - bufferImageCopy.SetImageExtent(NewVkExtent3D(a, newTexWidth, newTexHeight, bufferImageCopy.ImageExtent().Depth())) - bufferImageCopy.SetImageOffset(NewVkOffset3D(a, 0, 0, bufferImageCopy.ImageOffset().Z())) - - bufferImageCopyData := s.AllocDataOrPanic(ctx, bufferImageCopy) - defer bufferImageCopyData.Free() - - newCmd := cb.VkCmdCopyBufferToImage( - cmd.commandBuffer, - cmd.srcBuffer, - cmd.dstImage, - cmd.dstImageLayout, - 1, // regionCount - bufferImageCopyData.Ptr(), - ).AddRead(bufferImageCopyData.Data()) - - return out.MutateAndWrite(ctx, id, newCmd) - - case *VkCmdCopyImageToBuffer: - bufferImageCopy := cmd.PRegions().Slice(0, 1, l).MustRead(ctx, cmd, s, nil)[0] - imageSubresource := bufferImageCopy.ImageSubresource() - imageSubresource.SetMipLevel(0) - bufferImageCopy.SetImageSubresource(imageSubresource) - bufferImageCopy.SetImageExtent(NewVkExtent3D(a, newTexWidth, newTexHeight, bufferImageCopy.ImageExtent().Depth())) - bufferImageCopy.SetImageOffset(NewVkOffset3D(a, 0, 0, bufferImageCopy.ImageOffset().Z())) - - bufferImageCopyData := s.AllocDataOrPanic(ctx, bufferImageCopy) - defer bufferImageCopyData.Free() - - newCmd := cb.VkCmdCopyImageToBuffer( - cmd.commandBuffer, - cmd.srcImage, - cmd.srcImageLayout, - cmd.dstBuffer, - 1, // regionCount - bufferImageCopyData.Ptr(), - ).AddRead(bufferImageCopyData.Data()) - - return out.MutateAndWrite(ctx, id, newCmd) - - case *VkCmdBlitImage: - oldImageBlit := cmd.PRegions().MustRead(ctx, cmd, s, nil) - srcSubresource := oldImageBlit.SrcSubresource() - srcSubresource.SetMipLevel(0) - dstSubresource := oldImageBlit.DstSubresource() - dstSubresource.SetMipLevel(0) - - newImageBlit := NewVkImageBlit(a, - srcSubresource, - NewVkOffset3Dː2ᵃ(a, // srcOffsets (Bounds) - NewVkOffset3D(a, 0, 0, oldImageBlit.SrcOffsets().Get(0).Z()), - NewVkOffset3D(a, newTexWidth, newTexHeight, oldImageBlit.SrcOffsets().Get(1).Z()), - ), - dstSubresource, - NewVkOffset3Dː2ᵃ(a, // dstOffsets (Bounds) - NewVkOffset3D(a, 0, 0, oldImageBlit.DstOffsets().Get(0).Z()), - NewVkOffset3D(a, newTexWidth, newTexHeight, oldImageBlit.DstOffsets().Get(1).Z()), - ), - ) - imageBlitData := s.AllocDataOrPanic(ctx, newImageBlit) - defer imageBlitData.Free() - - newCmd := cb.VkCmdBlitImage( - cmd.commandBuffer, - cmd.srcImage, - cmd.srcImageLayout, - cmd.dstImage, - cmd.dstImageLayout, - 1, // regionCount - imageBlitData.Ptr(), - cmd.filter, - ).AddRead(imageBlitData.Data()) - - return out.MutateAndWrite(ctx, id, newCmd) - - case *VkCreateImageView: - imageViewCreateInfo := cmd.PCreateInfo().MustRead(ctx, cmd, s, nil) - subresourceRange := imageViewCreateInfo.SubresourceRange() - subresourceRange.SetBaseMipLevel(0) - subresourceRange.SetLevelCount(1) - - imageViewCreateInfo.SetSubresourceRange(subresourceRange) - imageViewCreateInfoData := s.AllocDataOrPanic(ctx, imageViewCreateInfo) - defer imageViewCreateInfoData.Free() - - newCmd := cb.VkCreateImageView( - cmd.device, - imageViewCreateInfoData.Ptr(), - cmd.PAllocator(), - cmd.PView(), - VkResult_VK_SUCCESS, - ).AddRead(imageViewCreateInfoData.Data()) - - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - - return out.MutateAndWrite(ctx, id, newCmd) - - case *VkCmdClearColorImage: - subresourceRanges := cmd.PRanges().MustRead(ctx, cmd, s, nil) - subresourceRanges.SetBaseMipLevel(0) - subresourceRanges.SetLevelCount(1) - subresourceRangesData := s.AllocDataOrPanic(ctx, subresourceRanges) - defer subresourceRangesData.Free() - - newCmd := cb.VkCmdClearColorImage( - cmd.commandBuffer, - cmd.image, - cmd.imageLayout, - cmd.pColor, - 1, // rangeCount - subresourceRangesData.Ptr(), - ).AddRead(subresourceRangesData.Data()) - - return out.MutateAndWrite(ctx, id, newCmd) - - default: - return out.MutateAndWrite(ctx, id, cmd) - } - }) -} diff --git a/gapis/api/vulkan/minimize_viewport.go b/gapis/api/vulkan/minimize_viewport.go deleted file mode 100644 index 18cef2065e..0000000000 --- a/gapis/api/vulkan/minimize_viewport.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package vulkan - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" -) - -// minimizeViewport returns a transform that sets viewport sizes to 1x1 -func minimizeViewport(ctx context.Context) transform.Transformer { - ctx = log.Enter(ctx, "Minimize viewport") - return transform.Transform("Minimize viewport", func(ctx context.Context, - id api.CmdID, cmd api.Cmd, out transform.Writer) error { - - const width = 1 - const height = 1 - - s := out.State() - l := s.MemoryLayout - a := s.Arena - cb := CommandBuilder{Thread: cmd.Thread(), Arena: a} - - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - switch cmd := cmd.(type) { - case *VkCreateGraphicsPipelines: - createInfoCount := uint64(cmd.CreateInfoCount()) - createInfos := cmd.PCreateInfos().Slice(0, createInfoCount, l).MustRead(ctx, cmd, s, nil) - viewportStateCreateInfosData := make([]api.AllocResult, createInfoCount) - viewportDatas := make([]api.AllocResult, 0) - scissorDatas := make([]api.AllocResult, 0) - - for i := uint64(0); i < createInfoCount; i++ { - viewportStateCreateInfo := createInfos[i].PViewportState().MustRead(ctx, cmd, s, nil) - - viewportCount := uint64(viewportStateCreateInfo.ViewportCount()) - oldViewports := viewportStateCreateInfo.PViewports().Slice(0, viewportCount, l) - newViewports := make([]VkViewport, viewportCount) - for j := uint64(0); j < viewportCount; j++ { - viewport := oldViewports.Index(j).MustRead(ctx, cmd, s, nil)[0] - viewport.SetWidth(width) - viewport.SetHeight(height) - newViewports[j] = viewport - } - - viewportDatas := append(viewportDatas, s.AllocDataOrPanic(ctx, newViewports)) - defer viewportDatas[i].Free() - - scissorCount := uint64(viewportStateCreateInfo.ScissorCount()) - oldScissors := viewportStateCreateInfo.PScissors().Slice(0, scissorCount, l) - newScissors := make([]VkRect2D, scissorCount) - for j := uint64(0); j < scissorCount; j++ { - scissor := oldScissors.Index(j).MustRead(ctx, cmd, s, nil)[0] - scissor.SetOffset(NewVkOffset2D(a, 0, 0)) - scissor.SetExtent(NewVkExtent2D(a, width, height)) - newScissors[j] = scissor - } - - scissorDatas := append(scissorDatas, s.AllocDataOrPanic(ctx, newScissors)) - defer scissorDatas[i].Free() - - viewportStateCreateInfo.SetPViewports(NewVkViewportᶜᵖ(viewportDatas[i].Ptr())) - viewportStateCreateInfo.SetPScissors(NewVkRect2Dᶜᵖ(scissorDatas[i].Ptr())) - viewportStateCreateInfosData[i] = s.AllocDataOrPanic(ctx, viewportStateCreateInfo) - defer viewportStateCreateInfosData[i].Free() - - createInfos[i].SetPViewportState(NewVkPipelineViewportStateCreateInfoᶜᵖ(viewportStateCreateInfosData[i].Ptr())) - } - - createInfosData := s.AllocDataOrPanic(ctx, createInfos) - defer createInfosData.Free() - - newCmd := cb.VkCreateGraphicsPipelines( - cmd.Device(), - cmd.PipelineCache(), - cmd.CreateInfoCount(), - createInfosData.Ptr(), - cmd.PAllocator(), - cmd.PPipelines(), - cmd.Result(), - ).AddRead( - createInfosData.Data(), - ) - - for _, vd := range viewportDatas { - newCmd.AddRead(vd.Data()) - } - for _, sd := range scissorDatas { - newCmd.AddRead(sd.Data()) - } - for _, vps := range viewportStateCreateInfosData { - newCmd.AddRead(vps.Data()) - } - for _, r := range cmd.Extras().Observations().Reads { - newCmd.AddRead(r.Range, r.ID) - } - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - - out.MutateAndWrite(ctx, id, newCmd) - case *VkCmdBeginRenderPass: - beginInfo := cmd.PRenderPassBegin().MustRead(ctx, cmd, s, nil) - - beginInfo.SetRenderArea(NewVkRect2D(a, - NewVkOffset2D(a, 0, 0), - NewVkExtent2D(a, width, height), - )) - - beginInfoData := s.AllocDataOrPanic(ctx, beginInfo) - defer beginInfoData.Free() - - newCmd := cb.VkCmdBeginRenderPass(cmd.commandBuffer, - beginInfoData.Ptr(), - cmd.Contents(), - ).AddRead(beginInfoData.Data()) - - out.MutateAndWrite(ctx, id, newCmd) - case *VkCmdSetViewport: - viewportCount := uint64(cmd.viewportCount) - oldViewports := cmd.PViewports().Slice(0, viewportCount, l) - newViewports := make([]VkViewport, viewportCount) - - for i := uint64(0); i < viewportCount; i++ { - viewport := oldViewports.Index(i).MustRead(ctx, cmd, s, nil)[0] - viewport.SetWidth(width) - viewport.SetHeight(height) - newViewports[i] = viewport - } - - newViewportDatas := s.AllocDataOrPanic(ctx, newViewports) - defer newViewportDatas.Free() - - newCmd := cb.VkCmdSetViewport(cmd.commandBuffer, - cmd.FirstViewport(), - uint32(viewportCount), - newViewportDatas.Ptr()).AddRead(newViewportDatas.Data()) - - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - out.MutateAndWrite(ctx, id, newCmd) - case *VkCmdSetScissor: - scissorCount := uint64(cmd.scissorCount) - newScissors := make([]VkRect2D, scissorCount) - - for i := uint64(0); i < scissorCount; i++ { - newScissors[i] = NewVkRect2D(a, - NewVkOffset2D(a, 0, 0), - NewVkExtent2D(a, width, height), - ) - } - - newScissorsData := s.AllocDataOrPanic(ctx, newScissors) - defer newScissorsData.Free() - - newCmd := cb.VkCmdSetScissor(cmd.commandBuffer, - cmd.FirstScissor(), - uint32(scissorCount), - newScissorsData.Ptr(), - ).AddRead(newScissorsData.Data()) - - out.MutateAndWrite(ctx, id, newCmd) - default: - out.MutateAndWrite(ctx, id, cmd) - } - return nil - }) -} diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 553d0b977f..b318e91b38 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -828,7 +828,6 @@ func uniqueConfig() replay.Config { } type profileRequest struct { - overrides *path.OverrideConfig traceOptions *service.TraceOptions handler *replay.SignalHandler buffer *bytes.Buffer @@ -1065,21 +1064,6 @@ func (a API) Replay( transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer)) transforms.Add(&profilingLayers{}) transforms.Add(replay.NewMappingExporter(ctx, req.handleMappings)) - if req.overrides.GetViewportSize() { - transforms.Add(minimizeViewport(ctx)) - } - if req.overrides.GetTextureSize() { - transforms.Add(minimizeTextures(ctx)) - } - if req.overrides.GetSampling() { - transforms.Add(simplifySampling(ctx)) - } - if req.overrides.GetFragmentShader() { - transforms.Add(simplifyFragmentShader(ctx)) - } - if req.overrides.GetVertexCount() { - transforms.Add(setPrimitiveCountToOne(ctx)) - } } } @@ -1259,15 +1243,14 @@ func (a API) Profile( intent replay.Intent, mgr replay.Manager, hints *service.UsageHints, - traceOptions *service.TraceOptions, - overrides *path.OverrideConfig) (*service.ProfilingData, error) { + traceOptions *service.TraceOptions) (*service.ProfilingData, error) { c := uniqueConfig() handler := replay.NewSignalHandler() var buffer bytes.Buffer handleMappings := make(map[uint64][]service.VulkanHandleMappingItem) submissionIds := make(map[api.CommandSubmissionKey][]uint64) - r := profileRequest{overrides, traceOptions, handler, &buffer, &handleMappings, &submissionIds} + r := profileRequest{traceOptions, handler, &buffer, &handleMappings, &submissionIds} _, err := mgr.Replay(ctx, intent, c, r, a, hints, true) handler.DoneSignal.Wait(ctx) diff --git a/gapis/api/vulkan/set_primitive_count_to_one.go b/gapis/api/vulkan/set_primitive_count_to_one.go deleted file mode 100644 index b7773142d8..0000000000 --- a/gapis/api/vulkan/set_primitive_count_to_one.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package vulkan - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/math/u32" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" -) - -func getMinimumVertexCountForPrimitive(ctx context.Context, primitive VkPrimitiveTopology) uint32 { - switch primitive { - case VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_POINT_LIST: - return 1 - case VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: - return 2 - case VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: - return 3 - case VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: - return 4 - case VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: - return 6 - default: // VkPrimitiveTopology_VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, - log.W(ctx, "getMinimumVertexCountForPrimitive() not implemented for %v", primitive) - return 0 - } -} - -// setPrimitiveCountToOne returns a transform that sets the maximum -// number of primtives per draw call to 1 -func setPrimitiveCountToOne(ctx context.Context) transform.Transformer { - ctx = log.Enter(ctx, "setPrimitiveCountToOne") - - const instanceCount uint32 = 1 - - perPipelineVertexCount := make(map[VkPipeline]uint32) - cmdPipelineBindings := make(map[VkCommandBuffer]VkPipeline) - - return transform.Transform("setPrimitiveCountToOne", func(ctx context.Context, - id api.CmdID, cmd api.Cmd, out transform.Writer) error { - - s := out.State() - l := s.MemoryLayout - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - - isIndirectDraw := false - var cmdBuf VkCommandBuffer - cmdInstanceCount := instanceCount - - switch cmd := cmd.(type) { - case *VkCreateGraphicsPipelines: - if err := out.MutateAndWrite(ctx, id, cmd); err != nil { - return err - } - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - - createInfoCount := uint64(cmd.CreateInfoCount()) - createInfos := cmd.PCreateInfos().Slice(0, createInfoCount, l).MustRead(ctx, cmd, s, nil) - pipelineHandles := cmd.PPipelines().Slice(0, createInfoCount, l).MustRead(ctx, cmd, s, nil) - - for i := uint64(0); i < createInfoCount; i++ { - primitive := createInfos[i].PInputAssemblyState().MustRead(ctx, cmd, s, nil).Topology() - perPipelineVertexCount[pipelineHandles[i]] = getMinimumVertexCountForPrimitive(ctx, primitive) - } - case *VkCmdBindPipeline: - if err := out.MutateAndWrite(ctx, id, cmd); err != nil { - return err - } - if cmd.PipelineBindPoint() == VkPipelineBindPoint_VK_PIPELINE_BIND_POINT_GRAPHICS { - cmdPipelineBindings[cmd.commandBuffer] = cmd.Pipeline() - } - case *VkCmdDraw: - vertexCount := perPipelineVertexCount[cmdPipelineBindings[cmd.commandBuffer]] - newCmd := cb.VkCmdDraw( - cmd.commandBuffer, - u32.Min(vertexCount, cmd.VertexCount()), - u32.Min(instanceCount, cmd.InstanceCount()), - cmd.FirstVertex(), - cmd.FirstInstance(), - ) - if err := out.MutateAndWrite(ctx, id, newCmd); err != nil { - return err - } - case *VkCmdDrawIndexed: - vertexCount := perPipelineVertexCount[cmdPipelineBindings[cmd.commandBuffer]] - newCmd := cb.VkCmdDrawIndexed( - cmd.commandBuffer, - u32.Min(vertexCount, cmd.IndexCount()), - u32.Min(instanceCount, cmd.InstanceCount()), - cmd.FirstIndex(), - cmd.VertexOffset(), - cmd.FirstInstance(), - ) - if err := out.MutateAndWrite(ctx, id, newCmd); err != nil { - return err - } - case *VkCmdDrawIndirect: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - cmdInstanceCount = cmd.DrawCount() - case *VkCmdDrawIndexedIndirect: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - cmdInstanceCount = cmd.DrawCount() - case *VkCmdDrawIndirectCountKHR: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - case *VkCmdDrawIndexedIndirectCountKHR: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - case *VkCmdDrawIndirectCountAMD: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - case *VkCmdDrawIndexedIndirectCountAMD: - isIndirectDraw = true - cmdBuf = cmd.commandBuffer - default: - return out.MutateAndWrite(ctx, id, cmd) - } - - // Replace indirect draw calls with direct ones. - // TODO: Replace with appropriate indirect calls instead. - if isIndirectDraw { - newCmd := cb.VkCmdDraw( - cmdBuf, - 0, // vertex count - u32.Min(instanceCount, cmdInstanceCount), - 0, // first vertex - 0, // first instance - ) - return out.MutateAndWrite(ctx, id, newCmd) - } - return nil - }) -} diff --git a/gapis/api/vulkan/simplify_fragment_shader.go b/gapis/api/vulkan/simplify_fragment_shader.go deleted file mode 100644 index d0287c3cb7..0000000000 --- a/gapis/api/vulkan/simplify_fragment_shader.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package vulkan - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/shadertools" -) - -const constantColorShader string = ` -#version 330 -layout (location = 0) out vec4 fragColor; -void main() { - fragColor = vec4(0, 0, 1, 1); -}` - -const nameStr = "main" - -func createSimpleFragmentShaderModule(ctx context.Context, - cb CommandBuilder, - device VkDevice, - out transform.Writer, -) VkShaderModule { - s := out.State() - - shaderSource, _ := shadertools.CompileGlsl( - constantColorShader, - shadertools.CompileOptions{ - ShaderType: shadertools.TypeFragment, - ClientType: shadertools.Vulkan, - }, - ) - shaderData := s.AllocDataOrPanic(ctx, shaderSource) - defer shaderData.Free() - - createInfo := NewVkShaderModuleCreateInfo(s.Arena, - VkStructureType_VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, // sType - NewVoidᶜᵖ(memory.Nullptr), // pNext - 0, // flags - memory.Size(len(shaderSource)*4), // codeSize - NewU32ᶜᵖ(shaderData.Ptr()), // pCode - ) - createInfoData := s.AllocDataOrPanic(ctx, createInfo) - defer createInfoData.Free() - - shaderModuleHandle := VkShaderModule(newUnusedID(false, func(id uint64) bool { - return GetState(s).ShaderModules().Contains(VkShaderModule(id)) - })) - shaderModuleData := s.AllocDataOrPanic(ctx, shaderModuleHandle) - defer shaderModuleData.Free() - - createShaderModuleCmd := cb.VkCreateShaderModule( - device, - createInfoData.Ptr(), - memory.Nullptr, - shaderModuleData.Ptr(), - VkResult_VK_SUCCESS, - ).AddRead( - createInfoData.Data(), - ).AddRead( - shaderData.Data(), - ).AddWrite( - shaderModuleData.Data(), - ) - - out.MutateAndWrite(ctx, api.CmdNoID, createShaderModuleCmd) - - return shaderModuleHandle -} - -// simplifyFragmentShader returns a transform that replaces all -// fragment shaders with a constant color shader -func simplifyFragmentShader(ctx context.Context) transform.Transformer { - ctx = log.Enter(ctx, "simplifyFragmentShader") - - return transform.Transform("simplifyFragmentShader", func(ctx context.Context, - id api.CmdID, cmd api.Cmd, out transform.Writer) error { - - s := out.State() - l := s.MemoryLayout - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - - switch cmd := cmd.(type) { - case *VkCreateGraphicsPipelines: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - - shaderModuleHandle := createSimpleFragmentShaderModule(ctx, cb, cmd.Device(), out) - nameData := s.AllocDataOrPanic(ctx, nameStr) - - createInfoCount := uint64(cmd.CreateInfoCount()) - createInfos := cmd.PCreateInfos().Slice(0, createInfoCount, l).MustRead(ctx, cmd, s, nil) - shaderStageStateCreateInfosData := make([]api.AllocResult, createInfoCount) - - for i := uint64(0); i < createInfoCount; i++ { - stageCount := uint64(createInfos[i].StageCount()) - shaderStageStateCreateInfos := createInfos[i].PStages().Slice(0, stageCount, l).MustRead(ctx, cmd, s, nil) - for j := uint64(0); j < stageCount; j++ { - if shaderStageStateCreateInfos[j].Stage() == VkShaderStageFlagBits_VK_SHADER_STAGE_FRAGMENT_BIT { - shaderStageStateCreateInfos[j].SetPNext(NewVoidᶜᵖ(memory.Nullptr)) - shaderStageStateCreateInfos[j].SetModule(shaderModuleHandle) - shaderStageStateCreateInfos[j].SetPName(NewCharᶜᵖ(nameData.Ptr())) - shaderStageStateCreateInfos[j].SetPSpecializationInfo(NewVkSpecializationInfoᶜᵖ(memory.Nullptr)) - } - } - - shaderStageStateCreateInfosData[i] = s.AllocDataOrPanic(ctx, shaderStageStateCreateInfos) - defer shaderStageStateCreateInfosData[i].Free() - - createInfos[i].SetPStages(NewVkPipelineShaderStageCreateInfoᶜᵖ(shaderStageStateCreateInfosData[i].Ptr())) - } - - createInfosData := s.AllocDataOrPanic(ctx, createInfos) - defer createInfosData.Free() - - newCmd := cb.VkCreateGraphicsPipelines( - cmd.Device(), - cmd.PipelineCache(), - cmd.CreateInfoCount(), - createInfosData.Ptr(), - cmd.PAllocator(), - cmd.PPipelines(), - cmd.Result(), - ).AddRead( - createInfosData.Data(), - ) - - for _, r := range cmd.Extras().Observations().Reads { - newCmd.AddRead(r.Range, r.ID) - } - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - - for _, ss := range shaderStageStateCreateInfosData { - newCmd.AddRead(ss.Data()) - } - newCmd.AddRead(nameData.Data()) - - return out.MutateAndWrite(ctx, id, newCmd) - default: - return out.MutateAndWrite(ctx, id, cmd) - } - }) -} diff --git a/gapis/api/vulkan/simplify_sampling.go b/gapis/api/vulkan/simplify_sampling.go deleted file mode 100644 index 254983031d..0000000000 --- a/gapis/api/vulkan/simplify_sampling.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package vulkan - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" -) - -// simplifySampling returns a transform that turns off anisotropic filtering -// and sets filtering modes to nearest neighbor -func simplifySampling(ctx context.Context) transform.Transformer { - ctx = log.Enter(ctx, "Simplify sampling") - return transform.Transform("Simplify sampling", func(ctx context.Context, - id api.CmdID, cmd api.Cmd, out transform.Writer) error { - - s := out.State() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - switch cmd := cmd.(type) { - case *VkCreateSampler: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - - samplerCreateInfo := cmd.PCreateInfo().MustRead(ctx, cmd, s, nil) - samplerCreateInfo.SetAnisotropyEnable(VkBool32(0)) - samplerCreateInfo.SetMinFilter(VkFilter_VK_FILTER_NEAREST) - samplerCreateInfo.SetMagFilter(VkFilter_VK_FILTER_NEAREST) - - samplerCreateInfoData := s.AllocDataOrPanic(ctx, samplerCreateInfo) - defer samplerCreateInfoData.Free() - - newCmd := cb.VkCreateSampler(cmd.Device(), - samplerCreateInfoData.Ptr(), - cmd.PAllocator(), - cmd.PSampler(), - VkResult_VK_SUCCESS, - ).AddRead(samplerCreateInfoData.Data()) - - for _, w := range cmd.Extras().Observations().Writes { - newCmd.AddWrite(w.Range, w.ID) - } - return out.MutateAndWrite(ctx, id, newCmd) - default: - return out.MutateAndWrite(ctx, id, cmd) - } - }) -} diff --git a/gapis/replay/gpu_profile.go b/gapis/replay/gpu_profile.go index 94fef77e5d..44e45fe0d2 100644 --- a/gapis/replay/gpu_profile.go +++ b/gapis/replay/gpu_profile.go @@ -101,7 +101,7 @@ func GpuProfile(ctx context.Context, capturePath *path.Capture, device *path.Dev hints := &service.UsageHints{Background: true} for _, a := range c.APIs { if pf, ok := a.(Profiler); ok { - data, err := pf.Profile(ctx, intent, mgr, hints, opts, nil) + data, err := pf.Profile(ctx, intent, mgr, hints, opts) if err != nil { log.E(ctx, "Replay profiling failed.") continue diff --git a/gapis/replay/interfaces.go b/gapis/replay/interfaces.go index 51ed31f882..766e33c1d8 100644 --- a/gapis/replay/interfaces.go +++ b/gapis/replay/interfaces.go @@ -22,7 +22,6 @@ import ( "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/capture" "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" ) // Support is the optional interface implemented by APIs that can describe @@ -89,8 +88,7 @@ type Profiler interface { intent Intent, mgr Manager, hints *service.UsageHints, - traceOptions *service.TraceOptions, - overrides *path.OverrideConfig) (*service.ProfilingData, error) + traceOptions *service.TraceOptions) (*service.ProfilingData, error) } // Issue represents a single replay issue reported by QueryIssues. diff --git a/gapis/service/path/path.proto b/gapis/service/path/path.proto index 4b79e37013..2127c8ea86 100644 --- a/gapis/service/path/path.proto +++ b/gapis/service/path/path.proto @@ -528,14 +528,6 @@ message Thumbnail { bool disable_optimization = 7; } -message OverrideConfig { - bool viewport_size = 1; - bool fragment_shader = 2; - bool vertex_count = 3; - bool sampling = 4; - bool texture_size = 5; -} - message ResolveConfig { // The device to use for any replays when resolving paths. path.Device replay_device = 1; From ca386ff2eb30ecefe3f5138ebfec7e63ef1d7710 Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Mon, 17 Feb 2020 16:54:46 +0000 Subject: [PATCH 0070/1218] Fix the framelooping bug after the command id changes (#46) --- gapis/api/vulkan/find_issues.go | 2 +- gapis/api/vulkan/query_timestamps.go | 2 +- gapis/api/vulkan/replay.go | 20 ++++---------------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/gapis/api/vulkan/find_issues.go b/gapis/api/vulkan/find_issues.go index 70ee321fd1..2157c71d90 100644 --- a/gapis/api/vulkan/find_issues.go +++ b/gapis/api/vulkan/find_issues.go @@ -67,7 +67,7 @@ type findIssues struct { reportCallbacks map[VkInstance]VkDebugReportCallbackEXT } -func newFindIssues(ctx context.Context, c *capture.GraphicsCapture, numInitialCmds int) *findIssues { +func newFindIssues(ctx context.Context, c *capture.GraphicsCapture) *findIssues { t := &findIssues{ state: c.NewState(ctx), reportCallbacks: map[VkInstance]VkDebugReportCallbackEXT{}, diff --git a/gapis/api/vulkan/query_timestamps.go b/gapis/api/vulkan/query_timestamps.go index 854757d450..64685a06bb 100644 --- a/gapis/api/vulkan/query_timestamps.go +++ b/gapis/api/vulkan/query_timestamps.go @@ -74,7 +74,7 @@ type queryTimestamps struct { results map[uint64]queryResults } -func newQueryTimestamps(ctx context.Context, c *capture.GraphicsCapture, numInitialCmds int, Cmds []api.Cmd, willLoop bool, handler service.TimeStampsHandler) *queryTimestamps { +func newQueryTimestamps(ctx context.Context, c *capture.GraphicsCapture, Cmds []api.Cmd, willLoop bool, handler service.TimeStampsHandler) *queryTimestamps { transform := &queryTimestamps{ cmds: Cmds, commandPools: make(map[commandPoolKey]VkCommandPool), diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index b318e91b38..52955b226f 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -963,14 +963,8 @@ func (a API) Replay( for _, rr := range rrs { switch req := rr.Request.(type) { case issuesRequest: - var numInitialCommands int - var err error if issues == nil { - numInitialCommands, err = expandCommands(false) - if err != nil { - return err - } - issues = newFindIssues(ctx, c, numInitialCommands) + issues = newFindIssues(ctx, c) } issues.AddResult(rr.Result) optimize = false @@ -979,22 +973,16 @@ func (a API) Replay( } willLoop := req.loopCount > 1 if willLoop { - frameloop = newFrameLoop(ctx, c, api.CmdID(numInitialCommands), frameLoopEndCmdID(cmds), req.loopCount) + frameloop = newFrameLoop(ctx, c, api.CmdID(0), frameLoopEndCmdID(cmds), req.loopCount) } case timestampsRequest: - var numInitialCommands int - var err error if timestamps == nil { - numInitialCommands, err = expandCommands(false) - if err != nil { - return err - } willLoop := req.loopCount > 1 if willLoop { - frameloop = newFrameLoop(ctx, c, api.CmdID(numInitialCommands), frameLoopEndCmdID(cmds), req.loopCount) + frameloop = newFrameLoop(ctx, c, api.CmdID(0), frameLoopEndCmdID(cmds), req.loopCount) } - timestamps = newQueryTimestamps(ctx, c, numInitialCommands, cmds, willLoop, req.handler) + timestamps = newQueryTimestamps(ctx, c, cmds, willLoop, req.handler) } timestamps.AddResult(rr.Result) optimize = false From 701bf1fbf4e1b0362d109ddd612466dd830eafcc Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 18 Feb 2020 13:50:29 +0000 Subject: [PATCH 0071/1218] Revert "Name replay profiler 'Surface' slices according to their matched command id" (#62) This reverts commit 7ee4b228b7cf52f57c1a367bc41f0fe051ef74e9. This commit leads to crashes: panic: runtime error: index out of range gapis/trace/android/adreno/profiling_data.go:200 Bug: b/149693499 --- gapis/trace/android/adreno/profiling_data.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index fc8112b3e7..8c93cf50d7 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -196,10 +196,6 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])}, }) - if names[i] == "Surface" { - names[i] = fmt.Sprintf("%v", groups[groupIds[i]].Link.Indices) - } - slices[i] = &service.ProfilingData_GpuSlices_Slice{ Ts: uint64(timestamps[i]), Dur: uint64(durations[i]), From 51741199947cc114447a82145882071d2ebfb9a7 Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Tue, 18 Feb 2020 17:31:52 +0000 Subject: [PATCH 0072/1218] Fix the boundary issues in Commands() (#58) b/149010824 --- gapis/resolve/commands.go | 14 +++++++------- gapis/resolve/delete_test.go | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/gapis/resolve/commands.go b/gapis/resolve/commands.go index c691b65294..c5db380116 100644 --- a/gapis/resolve/commands.go +++ b/gapis/resolve/commands.go @@ -34,22 +34,22 @@ func Commands(ctx context.Context, p *path.Commands, r *path.ResolveConfig) (*se if err != nil { return nil, err } + count := uint64(len(c.Commands)) + if count == 0 { + return &service.Commands{List: []*path.Command{}}, nil + } cmdIdxFrom, cmdIdxTo := p.From[0], p.To[0] if len(p.From) > 1 || len(p.To) > 1 { return nil, fmt.Errorf("Subcommands currently not supported for Commands") // TODO: Subcommands } - count := uint64(len(c.Commands)) - if count == 0 { - return nil, fmt.Errorf("No commands in capture") - } cmdIdxFrom = u64.Min(cmdIdxFrom, count-1) cmdIdxTo = u64.Min(cmdIdxTo, count-1) if cmdIdxFrom > cmdIdxTo { - cmdIdxFrom, cmdIdxTo = cmdIdxTo, cmdIdxFrom + return nil, fmt.Errorf("Invalid command boundaries") } - count = cmdIdxTo - cmdIdxFrom + count = cmdIdxTo - cmdIdxFrom + 1 paths := make([]*path.Command, count) - for i := uint64(0); i < count; i++ { + for i := cmdIdxFrom; i <= cmdIdxTo; i++ { paths[i] = p.Capture.Command(i) } return &service.Commands{List: paths}, nil diff --git a/gapis/resolve/delete_test.go b/gapis/resolve/delete_test.go index a1424d1e76..bc8bc95b79 100644 --- a/gapis/resolve/delete_test.go +++ b/gapis/resolve/delete_test.go @@ -37,7 +37,6 @@ func createSingleCommandTrace(ctx context.Context) *path.Capture { cb := test.CommandBuilder{Arena: a} cmds := []api.Cmd{ cb.CmdTypeMix(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, true, test.Voidᵖ(0x12345678), 2), - cb.PrimeState(test.U8ᵖ(0x89abcdef)), } p, err := capture.NewGraphicsCapture(ctx, a, "test", h, nil, cmds) if err != nil { @@ -58,7 +57,6 @@ func createMultipleCommandTrace(ctx context.Context) *path.Capture { cb.CmdTypeMix(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, true, test.Voidᵖ(0x12345678), 2), cb.CmdTypeMix(1, 15, 25, 35, 45, 55, 65, 75, 85, 95, 105, false, test.Voidᵖ(0x87654321), 3), cb.CmdTypeMix(2, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, true, test.Voidᵖ(0xdeadfeed), 3), - cb.PrimeState(test.U8ᵖ(0x89abcdef)), } p, err := capture.NewGraphicsCapture(ctx, a, "test", h, nil, cmds) if err != nil { From 59030deda74b0611c9a7b3a5272740900783bbff Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Tue, 18 Feb 2020 11:43:22 -0800 Subject: [PATCH 0073/1218] Fix tooltips and links in Pipeline View tables on Windows (#55) --- gapic/src/main/com/google/gapid/views/PipelineView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index 347b13a016..d57e86794a 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -424,7 +424,7 @@ private Composite createStage(Composite parent, API.Stage currentStage) { dataGroupComposite.setText(dataGroup.getGroupName() + " (table was set dynamically)"); } - TableViewer groupTable = createTableViewer(dataGroupComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + TableViewer groupTable = createTableViewer(dataGroupComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); List rows = dataGroup.getTable().getRowsList(); groupTable.setContentProvider(ArrayContentProvider.getInstance()); From 0367e85069390cf65885cf630cac6b04dbf0bf9c Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 18 Feb 2020 08:54:33 -0800 Subject: [PATCH 0074/1218] Revert "Revert "Name replay profiler 'Surface' slices according to their matched command id" (#62)" This reverts commit 701bf1fbf4e1b0362d109ddd612466dd830eafcc. --- gapis/trace/android/adreno/profiling_data.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index 8c93cf50d7..fc8112b3e7 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -196,6 +196,10 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])}, }) + if names[i] == "Surface" { + names[i] = fmt.Sprintf("%v", groups[groupIds[i]].Link.Indices) + } + slices[i] = &service.ProfilingData_GpuSlices_Slice{ Ts: uint64(timestamps[i]), Dur: uint64(durations[i]), From d29edf41cd8044bc06b7fff7d6c063732cbb6835 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 18 Feb 2020 08:55:52 -0800 Subject: [PATCH 0075/1218] Replay profiler: Adjust slice renaming to be robust to missing mappings It's possible (most likely with a misconfigured device running out of date producers) to end up with Surface slices for which we could not determine the correct command mapping. This problem should ideally be caught by device validation before we get this far, but we also shouldn't crash here. Bug: b/149693499 --- gapis/trace/android/adreno/profiling_data.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index fc8112b3e7..0e66b9e33f 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -196,7 +196,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])}, }) - if names[i] == "Surface" { + if names[i] == "Surface" && groupIds[i] != -1 { names[i] = fmt.Sprintf("%v", groups[groupIds[i]].Link.Indices) } From f691a2ccdbac930a9822ede572f6d1ae2fcc7fad Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Tue, 18 Feb 2020 13:30:25 -0800 Subject: [PATCH 0076/1218] Enable/Disable KVPs in Pipeline View that depend on another value (#31) Also adds a tooltip for affected KVPs --- .../com/google/gapid/views/PipelineView.java | 45 ++++- gapis/api/data_group.go | 16 ++ gapis/api/service.proto | 4 + gapis/api/vulkan/resources.go | 176 +++++++++--------- 4 files changed, 149 insertions(+), 92 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index d57e86794a..03f3651f4e 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -364,6 +364,15 @@ private Composite createStage(Composite parent, API.Stage currentStage) { Label keyLabel = withLayoutData( createBoldLabel(keyComposite, kvp.getName() + (kvp.getDynamic() ? "*:" : ":")), new GridData(SWT.RIGHT, SWT.CENTER, true, true)); + + if (!kvp.getDependee().equals("")) { + if (kvp.getActive()) { + keyLabel.setToolTipText("Activated by " + kvp.getDependee()); + } else { + keyComposite.setToolTipText("Deactivated by " + kvp.getDependee()); + keyLabel.setEnabled(false); + } + } if (!dynamicExists && kvp.getDynamic()) { dataGroupComposite.setText(dataGroup.getGroupName() + " (* value set dynamically)"); @@ -378,9 +387,15 @@ private Composite createStage(Composite parent, API.Stage currentStage) { withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> models.follower.onFollow(dv.link)), new GridData(SWT.LEFT, SWT.CENTER, true, true)); } else { - Label valueLabel = withLayoutData( createLabel(valueComposite, dv.displayValue), + Label valueLabel = withLayoutData( createLabel(valueComposite, dv.displayValue), new GridData(SWT.LEFT, SWT.CENTER, true, true)); - valueLabel.setToolTipText(dv.tooltipValue); + + if (kvp.getActive()) { + valueLabel.setToolTipText(kvp.getDependee().equals("") ? dv.tooltipValue : "Activated by " + kvp.getDependee()); + } else { + valueComposite.setToolTipText("Deactivated by " + kvp.getDependee()); + valueLabel.setEnabled(false); + } } } @@ -420,20 +435,21 @@ private Composite createStage(Composite parent, API.Stage currentStage) { break; case TABLE: - if (dataGroup.getTable().getDynamic()) { + API.Table dataTable = dataGroup.getTable(); + if (dataTable.getDynamic()) { dataGroupComposite.setText(dataGroup.getGroupName() + " (table was set dynamically)"); } TableViewer groupTable = createTableViewer(dataGroupComposite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION); - List rows = dataGroup.getTable().getRowsList(); + List rows = dataTable.getRowsList(); groupTable.setContentProvider(ArrayContentProvider.getInstance()); ColumnViewerToolTipSupport.enableFor(groupTable); - for (int i = 0; i < dataGroup.getTable().getHeadersCount(); i++) { + for (int i = 0; i < dataTable.getHeadersCount(); i++) { int col = i; - TableViewerColumn tvc = createTableColumn(groupTable, dataGroup.getTable().getHeaders(i)); + TableViewerColumn tvc = createTableColumn(groupTable, dataTable.getHeaders(i)); StyledCellLabelProvider cellLabelProvider = new StyledCellLabelProvider() { @Override @@ -441,6 +457,9 @@ public void update(ViewerCell cell) { DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(col)); cell.setText(dv.displayValue); + if (!dataTable.getActive()) { + cell.setForeground(getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY)); + } if (dv.link != null) { StyleRange style = new StyleRange(); @@ -456,10 +475,18 @@ public void update(ViewerCell cell) { public String getToolTipText(Object element) { DataValue dv = convertDataValue(((API.Row)element).getRowValues(col)); if (dv != null) { - return dv.tooltipValue; - } else { - return null; + if (!dataTable.getDependee().equals("")) { + if (dataTable.getActive()) { + return (dv.tooltipValue != null ? dv.tooltipValue : "Activated by " + dataTable.getDependee()); + } else { + return "Deactivated by " + dataTable.getDependee(); + } + } else { + return dv.tooltipValue; + } } + + return null; } }; diff --git a/gapis/api/data_group.go b/gapis/api/data_group.go index 4455250419..64f6a16beb 100644 --- a/gapis/api/data_group.go +++ b/gapis/api/data_group.go @@ -29,6 +29,22 @@ func (list *KeyValuePairList) AppendKeyValuePair(name string, value *DataValue, Name: name, Value: value, Dynamic: dynamic, + Active: true, + }) + + return &KeyValuePairList{ + KeyValues: values, + } +} + +func (list *KeyValuePairList) AppendDependentKeyValuePair(name string, value *DataValue, dynamic bool, dependee string, active bool) *KeyValuePairList { + values := append(list.KeyValues, + &KeyValuePair{ + Name: name, + Value: value, + Dynamic: dynamic, + Dependee: dependee, + Active: active, }) return &KeyValuePairList{ diff --git a/gapis/api/service.proto b/gapis/api/service.proto index 0a7bbb221d..2ce9b06e39 100644 --- a/gapis/api/service.proto +++ b/gapis/api/service.proto @@ -307,12 +307,16 @@ message KeyValuePair { string name = 1; DataValue value = 2; bool dynamic = 3; + string dependee = 4; + bool active = 5; } message Table { repeated string headers = 1; repeated Row rows = 2; bool dynamic = 3; + string dependee = 4; + bool active = 5; } message Row { diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go index cbfcb952a7..409cd756fe 100644 --- a/gapis/api/vulkan/resources.go +++ b/gapis/api/vulkan/resources.go @@ -1152,6 +1152,7 @@ func commonShaderDataGroups(ctx context.Context, Headers: []string{"Set", "Binding", "Array Index", "Type", "Handle", "View", "Layout", "Offset", "Range"}, Rows: dsetRows, Dynamic: false, + Active: true, } return []*api.DataGroup{ @@ -1191,6 +1192,7 @@ func (p GraphicsPipelineObjectʳ) inputAssembly(cmd *path.Command, drawCallInfo Headers: []string{"Binding", "Stride", "Vertex Input Rate"}, Rows: bindingRows, Dynamic: false, + Active: true, } attributes := p.VertexInputState().AttributeDescriptions() @@ -1213,6 +1215,7 @@ func (p GraphicsPipelineObjectʳ) inputAssembly(cmd *path.Command, drawCallInfo Headers: []string{"Location", "Binding", "Format", "Offset"}, Rows: attributeRows, Dynamic: false, + Active: true, } assemblyList := &api.KeyValuePairList{} @@ -1428,14 +1431,14 @@ func (p GraphicsPipelineObjectʳ) rasterizer(s *api.GlobalState, dynamicStates m ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) if ok2 { - rasterList = rasterList.AppendKeyValuePair("Depth Bias Constant Factor", api.CreatePoDDataValue("f32", ldps.DepthBiasConstantFactor()), true) - rasterList = rasterList.AppendKeyValuePair("Depth Bias Clamp", api.CreatePoDDataValue("f32", ldps.DepthBiasClamp()), true) - rasterList = rasterList.AppendKeyValuePair("Depth Bias Slope Factor", api.CreatePoDDataValue("f32", ldps.DepthBiasSlopeFactor()), true) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Constant Factor", api.CreatePoDDataValue("f32", ldps.DepthBiasConstantFactor()), true, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Clamp", api.CreatePoDDataValue("f32", ldps.DepthBiasClamp()), true, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Slope Factor", api.CreatePoDDataValue("f32", ldps.DepthBiasSlopeFactor()), true, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) } } else { - rasterList = rasterList.AppendKeyValuePair("Depth Bias Constant Factor", api.CreatePoDDataValue("f32", rasterState.DepthBiasConstantFactor()), false) - rasterList = rasterList.AppendKeyValuePair("Depth Bias Clamp", api.CreatePoDDataValue("f32", rasterState.DepthBiasClamp()), false) - rasterList = rasterList.AppendKeyValuePair("Depth Bias Slope Factor", api.CreatePoDDataValue("f32", rasterState.DepthBiasSlopeFactor()), false) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Constant Factor", api.CreatePoDDataValue("f32", rasterState.DepthBiasConstantFactor()), false, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Clamp", api.CreatePoDDataValue("f32", rasterState.DepthBiasClamp()), false, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) + rasterList = rasterList.AppendDependentKeyValuePair("Depth Bias Slope Factor", api.CreatePoDDataValue("f32", rasterState.DepthBiasSlopeFactor()), false, "Depth Bias Enabled", rasterState.DepthBiasEnable() != 0) } if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_LINE_WIDTH]; ok { @@ -1462,7 +1465,7 @@ func (p GraphicsPipelineObjectʳ) rasterizer(s *api.GlobalState, dynamicStates m multiList = multiList.AppendKeyValuePair("Sample Mask", api.CreatePoDDataValue("VkSampleMask", fmt.Sprintf("%X", mask)), false) multiList = multiList.AppendKeyValuePair("Sample Shading Enabled", api.CreatePoDDataValue("VkBool32", multiState.SampleShadingEnable() != 0), false) - multiList = multiList.AppendKeyValuePair("Min Sample Shading", api.CreatePoDDataValue("f32", multiState.MinSampleShading()), false) + multiList = multiList.AppendDependentKeyValuePair("Min Sample Shading", api.CreatePoDDataValue("f32", multiState.MinSampleShading()), false, "Sample Shading Enabled", multiState.SampleShadingEnable() != 0) multiList = multiList.AppendKeyValuePair("Alpha to Coverage", api.CreatePoDDataValue("VkBool32", multiState.AlphaToCoverageEnable() != 0), false) multiList = multiList.AppendKeyValuePair("Alpha to One", api.CreatePoDDataValue("VkBool32", multiState.AlphaToOneEnable() != 0), false) } @@ -1499,6 +1502,7 @@ func (p GraphicsPipelineObjectʳ) rasterizer(s *api.GlobalState, dynamicStates m Headers: []string{"X", "Y", "Width", "Height", "Min Depth", "Max Depth"}, Rows: viewportRows, Dynamic: viewDyanmic, + Active: true, } scissors := make(map[uint32]VkRect2D) @@ -1531,6 +1535,7 @@ func (p GraphicsPipelineObjectʳ) rasterizer(s *api.GlobalState, dynamicStates m Headers: []string{"X", "Y", "Width", "Height"}, Rows: scissorRows, Dynamic: sciDynamic, + Active: true, } dataGroups := []*api.DataGroup{ @@ -1587,121 +1592,125 @@ func (p GraphicsPipelineObjectʳ) colorBlending(ctx context.Context, s *api.Glob depthList := &api.KeyValuePairList{} stencilTable := &api.Table{ - Headers: []string{"Face", "Fail Op", "Pass Op", "Depth Fail Op", "Func", "Compare Mask", "Write Mask", "Ref"}, + Headers: []string{"Face", "Fail Op", "Pass Op", "Depth Fail Op", "Func", "Compare Mask", "Write Mask", "Ref"}, + Dependee: "Stencil Test Enabled", + Active: false, } if !depthData.IsNil() { depthList = depthList.AppendKeyValuePair("Test Enabled", api.CreatePoDDataValue("VkBool32", depthData.DepthTestEnable() != 0), false) - depthList = depthList.AppendKeyValuePair("Write Enabled", api.CreatePoDDataValue("VkBool32", depthData.DepthWriteEnable() != 0), false) - depthList = depthList.AppendKeyValuePair("Function", api.CreateEnumDataValue("VkCompareOp", depthData.DepthCompareOp()), false) - depthList = depthList.AppendKeyValuePair("Bounds Test Enabled", api.CreatePoDDataValue("VkBool32", depthData.DepthBoundsTestEnable() != 0), false) + depthList = depthList.AppendDependentKeyValuePair("Write Enabled", api.CreatePoDDataValue("VkBool32", depthData.DepthWriteEnable() != 0), false, "Test Enabled", depthData.DepthTestEnable() != 0) + depthList = depthList.AppendDependentKeyValuePair("Function", api.CreateEnumDataValue("VkCompareOp", depthData.DepthCompareOp()), false, "Test Enabled", depthData.DepthTestEnable() != 0) + depthList = depthList.AppendDependentKeyValuePair("Bounds Test Enabled", api.CreatePoDDataValue("VkBool32", depthData.DepthBoundsTestEnable() != 0), false, "Test Enabled", depthData.DepthTestEnable() != 0) if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_DEPTH_BOUNDS]; ok { ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) if ok2 { - depthList = depthList.AppendKeyValuePair("Min Depth Bounds", api.CreatePoDDataValue("f32", ldps.MinDepthBounds()), true) - depthList = depthList.AppendKeyValuePair("Max Depth Bounds", api.CreatePoDDataValue("f32", ldps.MaxDepthBounds()), true) + depthList = depthList.AppendDependentKeyValuePair("Min Depth Bounds", api.CreatePoDDataValue("f32", ldps.MinDepthBounds()), true, "Bounds Test Enabled", depthData.DepthBoundsTestEnable() != 0) + depthList = depthList.AppendDependentKeyValuePair("Max Depth Bounds", api.CreatePoDDataValue("f32", ldps.MaxDepthBounds()), true, "Bounds Test Enabled", depthData.DepthBoundsTestEnable() != 0) } } else { - depthList = depthList.AppendKeyValuePair("Min Depth Bounds", api.CreatePoDDataValue("f32", depthData.MinDepthBounds()), false) - depthList = depthList.AppendKeyValuePair("Max Depth Bounds", api.CreatePoDDataValue("f32", depthData.MaxDepthBounds()), false) + depthList = depthList.AppendDependentKeyValuePair("Min Depth Bounds", api.CreatePoDDataValue("f32", depthData.MinDepthBounds()), false, "Bounds Test Enabled", depthData.DepthBoundsTestEnable() != 0) + depthList = depthList.AppendDependentKeyValuePair("Max Depth Bounds", api.CreatePoDDataValue("f32", depthData.MaxDepthBounds()), false, "Bounds Test Enabled", depthData.DepthBoundsTestEnable() != 0) } stencilRows := []*api.Row{} stencilDynamic := false if depthData.StencilTestEnable() != 0 { - frontStencil := depthData.Front() - frontRow := []*api.DataValue{ - api.CreatePoDDataValue("string", "Front"), - api.CreateEnumDataValue("VkStencilOp", frontStencil.FailOp()), - api.CreateEnumDataValue("VkStencilOp", frontStencil.PassOp()), - api.CreateEnumDataValue("VkStencilOp", frontStencil.DepthFailOp()), - api.CreateEnumDataValue("VkCompareOp", frontStencil.CompareOp()), - } + stencilTable.Active = true + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + frontStencil := depthData.Front() + frontRow := []*api.DataValue{ + api.CreatePoDDataValue("string", "Front"), + api.CreateEnumDataValue("VkStencilOp", frontStencil.FailOp()), + api.CreateEnumDataValue("VkStencilOp", frontStencil.PassOp()), + api.CreateEnumDataValue("VkStencilOp", frontStencil.DepthFailOp()), + api.CreateEnumDataValue("VkCompareOp", frontStencil.CompareOp()), + } - if ok2 { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilFront().CompareMask()))) - stencilDynamic = true - } - } else { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", frontStencil.CompareMask()))) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + + if ok2 { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilFront().CompareMask()))) + stencilDynamic = true } + } else { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", frontStencil.CompareMask()))) + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) - if ok2 { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilFront().WriteMask()))) - stencilDynamic = true - } - } else { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", frontStencil.WriteMask()))) + if ok2 { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilFront().WriteMask()))) + stencilDynamic = true } + } else { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", frontStencil.WriteMask()))) + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_REFERENCE]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_REFERENCE]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) - if ok2 { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", ldps.StencilFront().Reference())) - stencilDynamic = true - } - } else { - frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", frontStencil.Reference())) + if ok2 { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", ldps.StencilFront().Reference())) + stencilDynamic = true } + } else { + frontRow = append(frontRow, api.CreatePoDDataValue("uint32_t", frontStencil.Reference())) + } - stencilRows = append(stencilRows, &api.Row{RowValues: frontRow}) + stencilRows = append(stencilRows, &api.Row{RowValues: frontRow}) - backStencil := depthData.Back() + backStencil := depthData.Back() - backRow := []*api.DataValue{ - api.CreatePoDDataValue("string", "Back"), - api.CreateEnumDataValue("VkStencilOp", backStencil.FailOp()), - api.CreateEnumDataValue("VkStencilOp", backStencil.PassOp()), - api.CreateEnumDataValue("VkStencilOp", backStencil.DepthFailOp()), - api.CreateEnumDataValue("VkCompareOp", backStencil.CompareOp()), - } + backRow := []*api.DataValue{ + api.CreatePoDDataValue("string", "Back"), + api.CreateEnumDataValue("VkStencilOp", backStencil.FailOp()), + api.CreateEnumDataValue("VkStencilOp", backStencil.PassOp()), + api.CreateEnumDataValue("VkStencilOp", backStencil.DepthFailOp()), + api.CreateEnumDataValue("VkCompareOp", backStencil.CompareOp()), + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) - if ok2 { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilBack().CompareMask()))) - stencilDynamic = true - } - } else { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", backStencil.CompareMask()))) + if ok2 { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilBack().CompareMask()))) + stencilDynamic = true } + } else { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", backStencil.CompareMask()))) + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) - if ok2 { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilBack().WriteMask()))) - stencilDynamic = true - } - } else { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", backStencil.WriteMask()))) + if ok2 { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", ldps.StencilBack().WriteMask()))) + stencilDynamic = true } + } else { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", fmt.Sprintf("%X", backStencil.WriteMask()))) + } - if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_REFERENCE]; ok { - ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) + if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_STENCIL_REFERENCE]; ok { + ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) - if ok2 { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", ldps.StencilBack().Reference())) - stencilDynamic = true - } - } else { - backRow = append(backRow, api.CreatePoDDataValue("uint32_t", backStencil.Reference())) + if ok2 { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", ldps.StencilBack().Reference())) + stencilDynamic = true } - - stencilRows = append(stencilRows, &api.Row{RowValues: backRow}) + } else { + backRow = append(backRow, api.CreatePoDDataValue("uint32_t", backStencil.Reference())) } + stencilRows = append(stencilRows, &api.Row{RowValues: backRow}) + stencilTable.Rows = stencilRows stencilTable.Dynamic = stencilDynamic } @@ -1712,11 +1721,12 @@ func (p GraphicsPipelineObjectʳ) colorBlending(ctx context.Context, s *api.Glob targetTable := &api.Table{ Headers: []string{"Enabled", "Color Src", "Color Dst", "Color Op", "Alpha Src", "Alpha Dst", "Alpha Op", "Color Write Mask"}, Dynamic: false, + Active: true, } if !blendData.IsNil() { blendList = blendList.AppendKeyValuePair("Logic Op Enabled", api.CreatePoDDataValue("VkBool32", blendData.LogicOpEnable() != 0), false) - blendList = blendList.AppendKeyValuePair("Logic Op", api.CreateEnumDataValue("VkLogicOp", blendData.LogicOp()), false) + blendList = blendList.AppendDependentKeyValuePair("Logic Op", api.CreateEnumDataValue("VkLogicOp", blendData.LogicOp()), false, "Logic Op Enabled", blendData.LogicOpEnable() != 0) if _, ok := dynamicStates[VkDynamicState_VK_DYNAMIC_STATE_BLEND_CONSTANTS]; ok { ldps, ok2 := GetState(s).LastDynamicPipelineStates().Lookup(GetState(s).LastBoundQueue().VulkanHandle()) From 642d36f1ae56a54607a93e2d60faa8544ed3701e Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Wed, 19 Feb 2020 11:06:22 +0000 Subject: [PATCH 0077/1218] Rename GAPID to AGI in license listings (#70) --- gapic/res/text/licenses.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gapic/res/text/licenses.html b/gapic/res/text/licenses.html index 2e309ea462..baa41a80e2 100644 --- a/gapic/res/text/licenses.html +++ b/gapic/res/text/licenses.html @@ -1,11 +1,11 @@ - GAPIC Licenses + Android GPU Inspector Licenses -

GAPIC Licenses

+

Android GPU Inspector Licenses

-

GAPID

+

Android GPU Inspector

 Copyright (C) 2017 Google Inc.
 

From f1bc3fbd018aba5caa2bc54375a11def2b87dc6c Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Wed, 19 Feb 2020 11:41:35 +0000
Subject: [PATCH 0078/1218] Delete a swapchain image only if it is not shared
 (#57)

When a swapchain is passed as the oldSwapchain argument of
vkCreateSwapchainKHR(), its images may be reused by the newly created
swapchain, and this can lead to images being shared between
swapchains. Hence, when a swapchain is destroyed, we must delete only
the images that are not being used by another swapchain.

Bug: b/148774659
Test: Manual: capturing Khronos sample AFBC does not crash anymore
---
 gapis/api/vulkan/extensions/khr_swapchain.api | 27 ++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/gapis/api/vulkan/extensions/khr_swapchain.api b/gapis/api/vulkan/extensions/khr_swapchain.api
index def80b6d8f..d2158c0430 100644
--- a/gapis/api/vulkan/extensions/khr_swapchain.api
+++ b/gapis/api/vulkan/extensions/khr_swapchain.api
@@ -185,6 +185,24 @@ cmd VkResult vkCreateSwapchainKHR(
   return ?
 }
 
+sub bool imageUsedByAnotherSwapchain(
+    ref!ImageObject     imageObject,
+    ref!SwapchainObject swapchainObject) {
+  found := MutableBool(false)
+  if (swapchainObject != null) && (imageObject != null) {
+    for _, _, s in Swapchains {
+      if (s != null) && (s != swapchainObject) {
+        for _, _, i in s.SwapchainImages {
+          if i == imageObject {
+            found.b = true
+          }
+        }
+      }
+    }
+  }
+  return found.b
+}
+
 @extension("VK_KHR_swapchain")
 @indirect("VkDevice")
 cmd void vkDestroySwapchainKHR(
@@ -192,13 +210,16 @@ cmd void vkDestroySwapchainKHR(
     VkSwapchainKHR      swapchain,
     AllocationCallbacks pAllocator) {
   if !(device in Devices) { vkErrorInvalidDevice(device) }
+  if !(swapchain in Swapchains) { vkErrorInvalidSwapchain(swapchain) }
   swapObject := Swapchains[swapchain]
-  if swapObject != null {
-    for _ , _ , v in swapObject.SwapchainImages {
+  for _ , _ , v in swapObject.SwapchainImages {
+    // Some images may be reused between swapchains via the oldSwapchain
+    // argument of vkCreateSwapchainKHR
+    if !imageUsedByAnotherSwapchain(v, swapObject) {
       delete(Images, v.VulkanHandle)
     }
-    delete(Swapchains, swapchain)
   }
+  delete(Swapchains, swapchain)
 }
 
 @extension("VK_KHR_swapchain")

From fa336f63e726ce89433214317f83ec1f5abef656 Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Wed, 19 Feb 2020 15:57:28 +0000
Subject: [PATCH 0079/1218] Fix typo, bug report URL, and comment out binary
 releases (#65)

Fix typo in error message.
Update bug-report URL to point to agi repo.
Binary release: workflow is under construction, we will un-comment once the binary releases are ready.

Fix #64
---
 README.md                                      | 6 +++---
 cmd/gapit/perfetto.go                          | 2 +-
 gapic/src/main/com/google/gapid/util/URLs.java | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index a8e6625bb5..66f8113b8b 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,11 @@
 Windows
 [![Windows Build Status](https://agi-build.storage.googleapis.com/badges/build_status_windows.svg)](https://agi-build.storage.googleapis.com/badges/build_result_windows.html)
 
-## Downloads
+
 
-**[Download the latest version of AGI here.](https://github.com/google/agi/releases)**
+
 
-*Unstable* developer releases are [here](https://github.com/google/agi-dev-releases/releases).
+
 
 ## Documentation
 
diff --git a/cmd/gapit/perfetto.go b/cmd/gapit/perfetto.go
index 48fb8d31b3..eed8ff7915 100644
--- a/cmd/gapit/perfetto.go
+++ b/cmd/gapit/perfetto.go
@@ -729,7 +729,7 @@ func WriteResultsToJSONOutput(metricsResults MetricsResults, outputPath string)
 
 	jsonResult, err := json.MarshalIndent(&metricsResults, "", "  ")
 	if err != nil {
-		return fmt.Errorf("Error converting the metrics results to Json. Please file a bug and provide as much as information as possbile to address this issue. Error: %v", err)
+		return fmt.Errorf("Error converting the metrics results to Json. Please file a bug and provide as much as information as possible to address this issue. Error: %v", err)
 	}
 	if _, err := output.Write(jsonResult); err != nil {
 		return fmt.Errorf("Error writing to the output file %s: %v.", outputPath, err)
diff --git a/gapic/src/main/com/google/gapid/util/URLs.java b/gapic/src/main/com/google/gapid/util/URLs.java
index 2237f2afe4..68c88124d1 100644
--- a/gapic/src/main/com/google/gapid/util/URLs.java
+++ b/gapic/src/main/com/google/gapid/util/URLs.java
@@ -17,7 +17,7 @@
 
 public interface URLs {
   public static final String FILE_BUG_URL =
-      "https://github.com/google/gapid/issues/new?template=standard-bug-report-for-gapid.md";
+      "https://github.com/google/agi/issues/new?template=standard-bug-report-for-gapid.md";
   // TODO(b/148700785): Create the device compatibility doc and update here
   public static final String DEVICE_COMPATIBILITY_URL =
       "https://github.com/google/agi";

From a914a4b385ddf0007e045c083b6b5c069aea1a9d Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Wed, 19 Feb 2020 11:04:26 -0800
Subject: [PATCH 0080/1218] Change the success validation icon to check mark
 (#69)

Making the validation success icon to be a bit more formal.
---
 gapic/res/icons/check_circle.png                  | Bin 0 -> 254 bytes
 gapic/res/icons/check_circle@2x.png               | Bin 0 -> 402 bytes
 .../main/com/google/gapid/views/TracerDialog.java |   2 +-
 .../src/main/com/google/gapid/widgets/Theme.java  |   1 +
 4 files changed, 2 insertions(+), 1 deletion(-)
 create mode 100644 gapic/res/icons/check_circle.png
 create mode 100644 gapic/res/icons/check_circle@2x.png

diff --git a/gapic/res/icons/check_circle.png b/gapic/res/icons/check_circle.png
new file mode 100644
index 0000000000000000000000000000000000000000..6472ef1d81d300ba3bd141265296d71926a5b20a
GIT binary patch
literal 254
zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rheqn<8~Ar*{C3)mkpB&93#v0t%r
zH{fv&6lq&(pdr@P>NI!$*~$QoE5^&8hb*sRD_xiF*ILEZdZ>A~{H*CYyDN7_ZnFRR
z<;ffwqZ!%;4;pH2Jea5)*~~hrN!@G3)Cfhlo|os{Iu0_MvsAqGHRwwzxUo^udClKM
z7e78jen*G)n@cVU}^<+KdTnjBnjZ$*F}V(@hJb6Mw<&;$T)
CW?%gP

literal 0
HcmV?d00001

diff --git a/gapic/res/icons/check_circle@2x.png b/gapic/res/icons/check_circle@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1a0cbc45ebc4de4cdf993c5392f959b1e496a00
GIT binary patch
literal 402
zcmV;D0d4+?P)_FL=7ac3X3{JVpwvgj*y6+*h5u{0TR#^U(R(~s463j$?)IK8FkX!oiWN7
zqAfb-J>~7N;uv7!jec2q4EW4=x~)0}Xnccuh-1Jvx(H*yZ#=ykv-4csHU{{eGpNJX
z^C#9Z;Hh{Tw4(xz0p}@CEkr-cJO&){Jk=2WDB~EQoH~e!ew29(I1YQt@X(JkkLfX4
z1<{Q%i~$Nvw!x?zWf^lv0#yYhvK+IjA(51rU5YCtum+1u1K+7L5|}HDC&>Xv1Z{%~
w4~Wu;5-FmUAxDiCgY%-h;erEFymz1e0Nhk;LAK?PJpcdz07*qoM6N<$f?;~1<^TWy

literal 0
HcmV?d00001

diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java
index 68235ba46c..2fc568b829 100644
--- a/gapic/src/main/com/google/gapid/views/TracerDialog.java
+++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java
@@ -362,7 +362,7 @@ public TraceInput(Composite parent, Models models, Widgets widgets, Runnable ref
         // dummy label to fill the 3rd column
         createLabel(mainGroup, "");
 
-        validationStatusLoader = widgets.loading.createWidgetWithImage(mainGroup, widgets.theme.smile(), widgets.theme.error());
+        validationStatusLoader = widgets.loading.createWidgetWithImage(mainGroup, widgets.theme.check(), widgets.theme.error());
         validationStatusLoader.setLayoutData(
             withIndents(new GridData(SWT.LEFT, SWT.BOTTOM, false, false), 0, 0));
         validationStatusText = createLink(mainGroup, "", e-> {
diff --git a/gapic/src/main/com/google/gapid/widgets/Theme.java b/gapic/src/main/com/google/gapid/widgets/Theme.java
index 20e3c2071c..86777699a4 100644
--- a/gapic/src/main/com/google/gapid/widgets/Theme.java
+++ b/gapic/src/main/com/google/gapid/widgets/Theme.java
@@ -61,6 +61,7 @@ public interface Theme {
   @Icon(file = "arrow_drop_right.png") public Image arrowDropRightLight();
   @Icon(file = "arrow_drop_down.png", color = 0xFFFFFF) public Image arrowDropDownDark();
   @Icon(file = "arrow_drop_right.png", color = 0xFFFFFF) public Image arrowDropRightDark();
+  @Icon(file = "check_circle.png") public Image check();
   @Icon(file = "clipboard.png") public Image clipboard();
   @Icon(file = "color_buffer0.png") public Image colorBuffer0();
   @Icon(file = "color_buffer1.png") public Image colorBuffer1();

From 068a7858b62645858e9354d24242bcac240cc3e5 Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Wed, 19 Feb 2020 11:39:47 -0800
Subject: [PATCH 0081/1218] Do the app cleanup for validation in the background
 context (#49)

Force-stop the app with the background context always.
---
 gapis/trace/android/trace.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go
index a826c9e656..bcfdc96c81 100644
--- a/gapis/trace/android/trace.go
+++ b/gapis/trace/android/trace.go
@@ -183,7 +183,7 @@ func (t *androidTracer) Validate(ctx context.Context) error {
 
 	// Force to stop the application, ignore any error that happens as it
 	// doesn't affect validation.
-	defer d.ForceStop(ctx, gapidPackage)
+	defer d.ForceStop(context.Background(), gapidPackage)
 
 	var buf bytes.Buffer
 	var written int64

From 53641b24865f293af39f20e35f4913834a7fdaf2 Mon Sep 17 00:00:00 2001
From: Peiyong Lin 
Date: Wed, 19 Feb 2020 13:41:42 -0800
Subject: [PATCH 0082/1218] Add basic validation framework for Mali. (#40)

This patch sets up the basic validation framework for Mali with empty GPU
counters list. Currently, Mali platform doesn't implement Vulkan Event and
attach proper submission id, hence this validation will fail for now.

Bug: b/149346641
---
 gapis/trace/android/BUILD.bazel          |  1 +
 gapis/trace/android/mali/BUILD.bazel     | 26 +++++++++++++
 gapis/trace/android/mali/validate.go     | 48 ++++++++++++++++++++++++
 gapis/trace/android/trace.go             |  3 ++
 gapis/trace/android/validate/validate.go | 11 +++---
 5 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 gapis/trace/android/mali/BUILD.bazel
 create mode 100644 gapis/trace/android/mali/validate.go

diff --git a/gapis/trace/android/BUILD.bazel b/gapis/trace/android/BUILD.bazel
index 33ae2d03f7..dce1c75b64 100644
--- a/gapis/trace/android/BUILD.bazel
+++ b/gapis/trace/android/BUILD.bazel
@@ -39,6 +39,7 @@ go_library(
         "//gapis/service:go_default_library",
         "//gapis/service/path:go_default_library",
         "//gapis/trace/android/adreno:go_default_library",
+        "//gapis/trace/android/mali:go_default_library",
         "//gapis/trace/android/validate:go_default_library",
         "//gapis/trace/tracer:go_default_library",
         "//tools/build/third_party/perfetto:config_go_proto",
diff --git a/gapis/trace/android/mali/BUILD.bazel b/gapis/trace/android/mali/BUILD.bazel
new file mode 100644
index 0000000000..1dd8da1cb7
--- /dev/null
+++ b/gapis/trace/android/mali/BUILD.bazel
@@ -0,0 +1,26 @@
+# Copyright (C) 2020 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["validate.go"],
+    importpath = "github.com/google/gapid/gapis/trace/android/mali",
+    visibility = ["//visibility:public"],
+    deps = [
+        "//gapis/perfetto:go_default_library",
+        "//gapis/trace/android/validate:go_default_library",
+    ],
+)
diff --git a/gapis/trace/android/mali/validate.go b/gapis/trace/android/mali/validate.go
new file mode 100644
index 0000000000..ef8d27877a
--- /dev/null
+++ b/gapis/trace/android/mali/validate.go
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mali
+
+import (
+	"context"
+
+	"github.com/google/gapid/gapis/perfetto"
+	"github.com/google/gapid/gapis/trace/android/validate"
+)
+
+var (
+	// All counters must be inside this array.
+	counters = []validate.GpuCounter{}
+)
+
+type MaliValidator struct {
+}
+
+func (v *MaliValidator) Validate(ctx context.Context, processor *perfetto.Processor) error {
+	if err := validate.ValidateGpuCounters(ctx, processor, v.GetCounters()); err != nil {
+		return err
+	}
+	if err := validate.ValidateGpuSlices(ctx, processor); err != nil {
+		return err
+	}
+	if err := validate.ValidateVulkanEvents(ctx, processor); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (v *MaliValidator) GetCounters() []validate.GpuCounter {
+	return counters
+}
diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go
index bcfdc96c81..890f04bfcd 100644
--- a/gapis/trace/android/trace.go
+++ b/gapis/trace/android/trace.go
@@ -50,6 +50,7 @@ import (
 	perfetto_android "github.com/google/gapid/gapis/perfetto/android"
 	"github.com/google/gapid/gapis/service"
 	"github.com/google/gapid/gapis/trace/android/adreno"
+	"github.com/google/gapid/gapis/trace/android/mali"
 	"github.com/google/gapid/gapis/trace/android/validate"
 	"github.com/google/gapid/gapis/trace/tracer"
 )
@@ -79,6 +80,8 @@ func newValidator(dev bind.Device) validate.Validator {
 	gpu := dev.Instance().GetConfiguration().GetHardware().GetGPU()
 	if strings.Contains(gpu.GetName(), "Adreno") {
 		return &adreno.AdrenoValidator{}
+	} else if strings.Contains(gpu.GetName(), "Mali") {
+		return &mali.MaliValidator{}
 	}
 	return nil
 }
diff --git a/gapis/trace/android/validate/validate.go b/gapis/trace/android/validate/validate.go
index eb7e161c32..3327e92667 100644
--- a/gapis/trace/android/validate/validate.go
+++ b/gapis/trace/android/validate/validate.go
@@ -199,17 +199,18 @@ func ValidateGpuSlices(ctx context.Context, processor *perfetto.Processor) error
 	}
 	for _, tId := range tIds {
 		queryResult, err := processor.Query(fmt.Sprintf(renderStageSlicesQuery, tId))
-		if err != nil || queryResult.GetNumRecords() <= 0 {
+		if err != nil {
 			return log.Errf(ctx, err, "Failed to query with %v", fmt.Sprintf(renderStageSlicesQuery, tId))
 		}
-		columns := queryResult.GetColumns()
 		numRecords := queryResult.GetNumRecords()
+		if numRecords == 0 {
+			log.W(ctx, "No gpu slices found in GPU track: %v", tId)
+			continue
+		}
+		columns := queryResult.GetColumns()
 		names := columns[0].GetStringValues()
 		commandBuffers := columns[1].GetLongValues()
 		submissionIds := columns[2].GetLongValues()
-		if numRecords == 0 {
-			return log.Err(ctx, nil, "No gpu slices")
-		}
 		for i := uint64(0); i < numRecords; i++ {
 			if commandBuffers[i] == 0 {
 				return log.Errf(ctx, nil, "Gpu slice %v has null command buffer", names[i])

From 0bae82e612febb24a943e4ca953fc807d8fc9d39 Mon Sep 17 00:00:00 2001
From: Peiyong Lin 
Date: Wed, 19 Feb 2020 16:02:13 -0800
Subject: [PATCH 0083/1218] Remove internet permission of the apk. (#75)

Previously gathering gpu slices require internet permission because the data
producer created TCP/IP socket to communicate with the driver. Now that the
architecture has changed, the data producer no longer needs to create it and
hence we can remove internet permission.

Bug: b/144872032
Test: bazel run gapit -- validate_gpu_profiling --os android
---
 gapidapk/android/apk/AndroidManifest.xml.in | 1 -
 1 file changed, 1 deletion(-)

diff --git a/gapidapk/android/apk/AndroidManifest.xml.in b/gapidapk/android/apk/AndroidManifest.xml.in
index a157cef26b..bbb922d22f 100644
--- a/gapidapk/android/apk/AndroidManifest.xml.in
+++ b/gapidapk/android/apk/AndroidManifest.xml.in
@@ -23,7 +23,6 @@
     
-    
     
Date: Wed, 19 Feb 2020 16:37:04 -0800
Subject: [PATCH 0084/1218] Draw vulkan event linking arrow based on slices'
 distance. (#54)

 - Extend the arrow to the start of the linked gpu queue slices group.
 - Bug: http://b/148964552.
---
 .../perfetto/models/VulkanEventTrack.java      | 18 +++++++++++++++---
 .../gapid/perfetto/views/VulkanEventPanel.java | 10 ++++++----
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java
index 414e187dad..2e1e280c0e 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java
@@ -51,6 +51,14 @@ public class VulkanEventTrack extends Track.WithQueryEngine= %d - dur and ts <= %d order by ts";
+  private static final String QUEUE_GROUP_START_SQL =
+      "select submission_id, min(ts) start from gpu_track t left join gpu_slice s " +
+          "on (t.id = s.track_id) where t.scope = 'gpu_render_stage' group by submission_id";
+  private static final String SLICES_WITH_DIST_SQL =
+      "with basics as (" + SLICES_SQL + ")," +
+      "queue_starts as ("+ QUEUE_GROUP_START_SQL + ") " +
+      "select basics.*, queue_starts.start - ts dist from basics left join queue_starts " +
+          "on (basics.submission_id = queue_starts.submission_id)";
   private static final String SLICE_RANGE_SQL =
       "select " + BASE_COLUMNS + " from %s " +
           "where ts < %d and ts + dur >= %d and depth >= %d and depth <= %d";
@@ -84,7 +92,8 @@ private ListenableFuture computeSlices(DataRequest req) {
         transform(qe.getAllArgs(res.stream().mapToLong(r -> r.getLong(7))), args -> {
           int rows = res.getNumRows();
           Data data = new Data(req, new long[rows], new long[rows], new long[rows],
-              new String[rows], new int[rows], new long[rows], new long[rows], new ArgSet[rows]);
+              new String[rows], new int[rows], new long[rows], new long[rows], new ArgSet[rows],
+              new long[rows]);
           res.forEachRow((i, row) -> {
             long start = row.getLong(1);
             data.ids[i] = row.getLong(0);
@@ -95,13 +104,14 @@ private ListenableFuture computeSlices(DataRequest req) {
             data.commandBuffers[i] = row.getLong(5);
             data.submissionIds[i] = row.getLong(6);
             data.args[i] = args.getOrDefault(row.getLong(7), ArgSet.EMPTY);
+            data.dists[i] = row.getLong(8);
           });
           return data;
         }));
   }
 
   private String slicesSql(DataRequest req) {
-    return format(SLICES_SQL, tableName("slices"), req.range.start, req.range.end);
+    return format(SLICES_WITH_DIST_SQL, tableName("slices"), req.range.start, req.range.end);
   }
 
   public ListenableFuture getSlice(long id) {
@@ -135,9 +145,10 @@ public static class Data extends Track.Data {
     public final long[] commandBuffers;
     public final long[] submissionIds;
     public final ArgSet[] args;
+    public final long[] dists; // Distance between a vulkan event and the linked GPU queue events.
 
     public Data(DataRequest request, long[] ids, long[] starts, long[] ends, String[] names,
-        int[] depths, long[] commandBuffers, long[] submissionIds, ArgSet[] args) {
+        int[] depths, long[] commandBuffers, long[] submissionIds, ArgSet[] args, long[] dists) {
       super(request);
       this.ids = ids;
       this.starts = starts;
@@ -147,6 +158,7 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, String[
       this.commandBuffers = commandBuffers;
       this.submissionIds = submissionIds;
       this.args = args;
+      this.dists = dists;
     }
   }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java
index 40b016b03c..9535eb4d2b 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java
@@ -41,7 +41,7 @@
 
 public class VulkanEventPanel extends TrackPanel implements Selectable {
   private static final double ARROW_HEIGHT = 10;
-  private static final double ARROW_WIDTH = 10;
+  private static final double ARROW_WIDTH_MIN = 10;
   private static final double ARROW_TIP = 2;
   private static final double SLICE_Y = ARROW_HEIGHT;
   private static final double SLICE_HEIGHT = 25;
@@ -130,10 +130,12 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
         ctx.drawRect(rectStart, SLICE_Y + depth * SLICE_HEIGHT, rectWidth, SLICE_HEIGHT, BOUNDING_BOX_LINE_WIDTH);
 
         double mid = rectStart + rectWidth / 2;
+        double arrowWidth = Math.max(ARROW_WIDTH_MIN,
+            state.durationToDeltaPx(data.dists[index]) - rectWidth / 2);
         ctx.drawLine(mid, ARROW_TIP, mid, SLICE_Y);
-        ctx.drawLine(mid, ARROW_TIP, mid + ARROW_WIDTH, ARROW_TIP);
-        ctx.drawLine(mid + ARROW_WIDTH, ARROW_TIP, mid + ARROW_WIDTH - ARROW_TIP, 0);
-        ctx.drawLine(mid + ARROW_WIDTH, ARROW_TIP, mid + ARROW_WIDTH - ARROW_TIP, ARROW_TIP * 2);
+        ctx.drawLine(mid, ARROW_TIP, mid + arrowWidth, ARROW_TIP);
+        ctx.drawLine(mid + arrowWidth, ARROW_TIP, mid + arrowWidth - ARROW_TIP, 0);
+        ctx.drawLine(mid + arrowWidth, ARROW_TIP, mid + arrowWidth - ARROW_TIP, ARROW_TIP * 2);
       }
 
       if (hoveredName != null) {

From 195d8a813ecc2c13234f056c2842e79b4af95709 Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Wed, 19 Feb 2020 17:45:11 -0800
Subject: [PATCH 0085/1218] Hide the validation related components when no
 device is selected (#74)

---
 gapic/src/main/com/google/gapid/views/TracerDialog.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java
index 2fc568b829..ea56cf9b3a 100644
--- a/gapic/src/main/com/google/gapid/views/TracerDialog.java
+++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java
@@ -612,8 +612,12 @@ private void updateOnDeviceChange(Settings settings, DeviceCaptureInfo dev) {
 
       private void runValidationCheck(DeviceCaptureInfo dev) {
         if (dev == null) {
+          validationStatusLoader.setVisible(false);
+          validationStatusText.setVisible(false);
           return;
         }
+        validationStatusLoader.setVisible(true);
+        validationStatusText.setVisible(true);
         setValidationStatus(models.devices.getValidationStatus(dev));
         if (!models.devices.getValidationStatus(dev).passed) {
           validationStatusLoader.startLoading();

From ad003ca09fbc87ff516fbca839d26b69fb147088 Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Tue, 18 Feb 2020 14:50:56 -0800
Subject: [PATCH 0086/1218] Rework bound descriptors output to be able to
 handle missing descriptors

Sheds some light on why we're not seeing some samplers etc
---
 gapis/api/vulkan/resources.go | 149 ++++++++++++++++++----------------
 1 file changed, 79 insertions(+), 70 deletions(-)

diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go
index 409cd756fe..d3296ead1a 100644
--- a/gapis/api/vulkan/resources.go
+++ b/gapis/api/vulkan/resources.go
@@ -1073,79 +1073,88 @@ func commonShaderDataGroups(ctx context.Context,
 			dsetRows := []*api.Row{}
 			for _, usedSet := range usedSets {
 				setInfo, ok := boundDsets[usedSet.Set()]
-				if ok {
-					setHandle := setInfo.VulkanHandle()
-					setPath := path.NewField("DescriptorSets", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(setHandle)
-
-					bindingInfo := setInfo.Bindings().Get(usedSet.Binding())
-					if !bindingInfo.IsNil() {
-						layoutBinding := setInfo.Layout().Bindings().Get(usedSet.Binding())
-
-						if layoutBinding.Stages()&VkShaderStageFlags(vkStage) != 0 {
-							bindingType := bindingInfo.BindingType()
-
-							for i := uint32(0); i < usedSet.DescriptorCount(); i++ {
-								currentSetData := []*api.DataValue{
-									api.CreateLinkedDataValue("url", setPath, api.CreatePoDDataValue("u32", usedSet.Set())),
-									api.CreatePoDDataValue("u32", usedSet.Binding()),
-									api.CreatePoDDataValue("u32", i),
-									api.CreateEnumDataValue("VkDescriptorType", bindingType),
-								}
-
-								switch bindingType {
-								case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER, VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-									VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
-									VkDescriptorType_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
-									descInfo := bindingInfo.ImageBinding().Get(i)
-
-									samplerHandle := descInfo.Sampler()
-									samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle)
-									currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle)))
-
-									viewHandle := descInfo.ImageView()
-									viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle)
-									currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", viewPath, api.CreatePoDDataValue("VkImageView", viewHandle)))
-
-									currentSetData = append(currentSetData, api.CreateEnumDataValue("VkImageLayout", descInfo.ImageLayout()))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-
-								case VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
-									VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
-									descInfo := bindingInfo.BufferViewBindings().Get(i)
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-
-									bufferViewPath := path.NewField("BufferViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo)
-									currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferViewPath, api.CreatePoDDataValue("VkBufferView", descInfo)))
-
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-
-								case VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
-									VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
-									VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
-									descInfo := bindingInfo.BufferBinding().Get(i)
-
-									bufferHandle := descInfo.Buffer()
-									bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo.Buffer())
-									currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", bufferHandle)))
-
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Offset()))
-									currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Range()))
-
-								}
-
-								dsetRows = append(dsetRows, &api.Row{
-									RowValues: currentSetData,
-								})
-							}
+				if !ok {
+					continue
+				}
+
+				setHandle := setInfo.VulkanHandle()
+				setPath := path.NewField("DescriptorSets", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(setHandle)
+
+				layoutBinding, ok := setInfo.Layout().Bindings().Lookup(usedSet.Binding())
+				if !ok || layoutBinding.Stages()&VkShaderStageFlags(vkStage) == 0 {
+					continue
+				}
+
+				bindingType := layoutBinding.Type()
+				bindingInfo := setInfo.Bindings().Get(usedSet.Binding())
+
+				for i := uint32(0); i < usedSet.DescriptorCount(); i++ {
+					currentSetData := []*api.DataValue{
+						api.CreateLinkedDataValue("url", setPath, api.CreatePoDDataValue("u32", usedSet.Set())),
+						api.CreatePoDDataValue("u32", usedSet.Binding()),
+						api.CreatePoDDataValue("u32", i),
+						api.CreateEnumDataValue("VkDescriptorType", bindingType),
+					}
+
+					if bindingInfo.IsNil() {
+						// Missing descriptor, fill with placeholders
+						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
+						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
+						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
+						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
+						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
+					} else {
+						switch bindingType {
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER, VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+							VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+							VkDescriptorType_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+							descInfo := bindingInfo.ImageBinding().Get(i)
+
+							samplerHandle := descInfo.Sampler()
+							samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle)
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle)))
+
+							viewHandle := descInfo.ImageView()
+							viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle)
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", viewPath, api.CreatePoDDataValue("VkImageView", viewHandle)))
+
+							currentSetData = append(currentSetData, api.CreateEnumDataValue("VkImageLayout", descInfo.ImageLayout()))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+							VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+							descInfo := bindingInfo.BufferViewBindings().Get(i)
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+							bufferViewPath := path.NewField("BufferViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo)
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferViewPath, api.CreatePoDDataValue("VkBufferView", descInfo)))
+
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+							VkDescriptorType_VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+							VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+							descInfo := bindingInfo.BufferBinding().Get(i)
+
+							bufferHandle := descInfo.Buffer()
+							bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo.Buffer())
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", bufferHandle)))
+
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Offset()))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Range()))
+
 						}
 					}
-				}
 
+					dsetRows = append(dsetRows, &api.Row{
+						RowValues: currentSetData,
+					})
+				}
 			}
 
 			dsetTable := &api.Table{

From ab53ed5980a9ad13da3a2eb76f6c746013665acd Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Thu, 20 Feb 2020 09:54:10 +0000
Subject: [PATCH 0087/1218] Use Android NDK r21 and VK_LAYER_KHRONOS_validation
 (#61)

Upgrade the NDK to r21. This let us use the unified
VK_LAYER_KHRONOS_validation meta validation layer, which is available
on both Desktop and Android.

This change does a bit of refactoring of the code handling the
validation layers, to make use of the new unified one.

Bug: b/148519068
---
 BUILDING.md                                   |  2 +-
 .../api/templates/vulkan_gfx_api_extras.tmpl  | 37 ++++++--------
 gapis/api/vulkan/find_issues.go               | 49 ++++++++-----------
 kokoro/linux/build.sh                         |  6 +--
 kokoro/macos/build.sh                         |  6 +--
 kokoro/windows/build.bat                      |  6 +--
 tools/build/rules/android.bzl                 | 16 +++---
 7 files changed, 52 insertions(+), 70 deletions(-)

diff --git a/BUILDING.md b/BUILDING.md
index 33a3f5922a..9415fc3a3e 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -59,7 +59,7 @@ cd 
 tools\bin\sdkmanager.bat "platforms;android-26" "build-tools;29.0.2" ndk-bundle
 ```
 
-Note: this will install the latest NDK in `\ndk-bundle`. The minimum required version of the NDK is r16b.
+Note: this will install the latest NDK in `\ndk-bundle`. The minimum required version of the NDK is **r21**.
 
 If you do not have adb installed you can do so with:
 ```
diff --git a/gapis/api/templates/vulkan_gfx_api_extras.tmpl b/gapis/api/templates/vulkan_gfx_api_extras.tmpl
index e2148b05d8..28846e1c53 100644
--- a/gapis/api/templates/vulkan_gfx_api_extras.tmpl
+++ b/gapis/api/templates/vulkan_gfx_api_extras.tmpl
@@ -55,8 +55,11 @@
 ¶
   const char kVirtualSwapchainLayerName[] = "VirtualSwapchain";
   const char kGraphicsSpyLayerName[] = "GraphicsSpy";
-  const char kValidationMetaLayerName[] = "VK_LAYER_LUNARG_standard_validation";
   const char* kValidationLayerNames[] = {
+    // Meta layers
+    "VK_LAYER_KHRONOS_validation",
+    "VK_LAYER_LUNARG_standard_validation",
+    // Regular layers
     "VK_LAYER_GOOGLE_threading",
     "VK_LAYER_LUNARG_parameter_validation",
     "VK_LAYER_LUNARG_object_tracker",
@@ -65,6 +68,14 @@
   };
   const char kDebugReportExtensionName[] = "VK_EXT_debug_report";
 
+¶
+  bool isValidationLayerName(const char* layer) {
+    return std::any_of(std::begin(kValidationLayerNames),
+                       std::end(kValidationLayerNames),
+                       [layer](const char* val) -> bool {
+                         return std::strcmp(layer, val) == 0;
+                       });
+  }
 ¶
   std::vector getVkPhysicalDevices(§
       LazyResolved vkEnumeratePhysicalDevices, Vulkan::VkInstance instance) {
@@ -119,14 +130,7 @@ bool Vulkan::replayCreateVkInstanceImpl(Stack* stack,
               return true;
             }
             if (dropValidationLayersAndDebugReport) {
-              if (strcmp(kValidationMetaLayerName, layer) == 0) {
-                return true;
-              }
-              return std::any_of(std::begin(kValidationLayerNames),
-                                 std::end(kValidationLayerNames),
-                                 [layer](const char* val) -> bool {
-                                   return strcmp(layer, val) == 0;
-                                 });
+              return isValidationLayerName(layer);
             }
             return false;
           }),
@@ -179,14 +183,7 @@ bool Vulkan::replayCreateVkDeviceImpl(Stack* stack, size_val physicalDevice,
       std::remove_if(layers.begin(), layers.end(),
                      [dropValidationLayers](const char* layer) -> bool {
                        if (dropValidationLayers) {
-                         if (strcmp(kValidationMetaLayerName, layer) == 0) {
-                           return true;
-                         }
-                         return std::any_of(std::begin(kValidationLayerNames),
-                                            std::end(kValidationLayerNames),
-                                            [layer](const char* val) -> bool {
-                                              return strcmp(layer, val) == 0;
-                                            });
+                         return isValidationLayerName(layer);
                        }
                        return false;
                      }),
@@ -733,11 +730,7 @@ bool Vulkan::replayDebugReportCallback(uint32_t flags, uint32_t objectType,
 ¶
 bool Vulkan::hasValidationLayers(const char* const* layers, uint32_t count) {
   return std::any_of(layers, layers + count, [](const char* layer) -> bool {
-    return std::any_of(
-      std::begin(kValidationLayerNames), std::end(kValidationLayerNames),
-      [layer](const char* val) -> bool {
-        return strcmp(layer, val) == 0;
-      }) || strcmp(layer, kValidationMetaLayerName) == 0;
+    return isValidationLayerName(layer);
   });
 }
 ¶
diff --git a/gapis/api/vulkan/find_issues.go b/gapis/api/vulkan/find_issues.go
index 2157c71d90..9372b4d7c0 100644
--- a/gapis/api/vulkan/find_issues.go
+++ b/gapis/api/vulkan/find_issues.go
@@ -28,7 +28,11 @@ import (
 	"github.com/google/gapid/gapis/service"
 )
 
-var validationLayers = [...]string{
+var validationLayerNames = [...]string{
+	// Meta layers
+	"VK_LAYER_KHRONOS_validation",
+	"VK_LAYER_LUNARG_standard_validation",
+	// Regular layers
 	"VK_LAYER_GOOGLE_threading",
 	"VK_LAYER_LUNARG_parameter_validation",
 	"VK_LAYER_LUNARG_object_tracker",
@@ -37,17 +41,16 @@ var validationLayers = [...]string{
 }
 
 const (
-	validationMetaLayer  = "VK_LAYER_LUNARG_standard_validation"
+	// Since Android NDK r21, the VK_LAYER_KHRONOS_validation meta layer
+	// is available on both desktop and Android.
+	validationMetaLayer  = "VK_LAYER_KHRONOS_validation"
 	debugReportExtension = "VK_EXT_debug_report"
 )
 
 // isValidationLayer returns true if any of the given string matches with any
 // validation layer names. Otherwise returns false.
 func isValidationLayer(n string) bool {
-	if n == validationMetaLayer {
-		return true
-	}
-	for _, v := range validationLayers {
+	for _, v := range validationLayerNames {
 		if n == v {
 			return true
 		}
@@ -115,9 +118,8 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o
 	}
 
 	switch cmd := cmd.(type) {
-	// Modify the vkCreateInstance to remove any validation layers first, and
-	// insert the individual validation layers in order. This is because Android
-	// does not support the meta layer, and the order does matter.Also enable the
+	// Modify the vkCreateInstance to first remove any validation layers,
+	// and then insert the meta validation layer. Also enable the
 	// VK_EXT_debug_report extension.
 	case *VkCreateInstance:
 		cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool())
@@ -130,12 +132,8 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o
 			}
 		}
 
-		validationLayersData := []api.AllocResult{}
-		for _, v := range validationLayers {
-			d := mustAlloc(ctx, v)
-			validationLayersData = append(validationLayersData, d)
-			layers = append(layers, NewCharᶜᵖ(d.Ptr()))
-		}
+		validationMetaLayerData := mustAlloc(ctx, validationMetaLayer)
+		layers = append(layers, NewCharᶜᵖ(validationMetaLayerData.Ptr()))
 		layersData := mustAlloc(ctx, layers)
 
 		extCount := info.EnabledExtensionCount()
@@ -160,10 +158,9 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o
 		infoData := mustAlloc(ctx, info)
 
 		newCmd := cb.VkCreateInstance(infoData.Ptr(), cmd.PAllocator(), cmd.PInstance(), cmd.Result())
-		for _, d := range validationLayersData {
-			newCmd.AddRead(d.Data())
-		}
 		newCmd.AddRead(
+			validationMetaLayerData.Data(),
+		).AddRead(
 			debugReportExtNameData.Data(),
 		).AddRead(
 			infoData.Data(),
@@ -181,8 +178,8 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o
 		}
 		out.MutateAndWrite(ctx, id, newCmd)
 
-	// Modify the vkCreateDevice to remove any validation layers and add individual
-	// layers back later. Same reason as vkCreateInstance
+	// Modify the vkCreateDevice to remove any validation layers and add
+	// the meta layer back later. Same reason as vkCreateInstance
 	case *VkCreateDevice:
 		cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool())
 		info := cmd.PCreateInfo().MustRead(ctx, cmd, s, nil)
@@ -194,21 +191,15 @@ func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, o
 			}
 		}
 
-		validationLayersData := []api.AllocResult{}
-		for _, v := range validationLayers {
-			d := mustAlloc(ctx, v)
-			validationLayersData = append(validationLayersData, d)
-			layers = append(layers, NewCharᶜᵖ(d.Ptr()))
-		}
+		validationMetaLayerData := mustAlloc(ctx, validationMetaLayer)
+		layers = append(layers, NewCharᶜᵖ(validationMetaLayerData.Ptr()))
 		layersData := mustAlloc(ctx, layers)
 		info.SetEnabledLayerCount(uint32(len(layers)))
 		info.SetPpEnabledLayerNames(NewCharᶜᵖᶜᵖ(layersData.Ptr()))
 		infoData := mustAlloc(ctx, info)
 
 		newCmd := cb.VkCreateDevice(cmd.PhysicalDevice(), infoData.Ptr(), cmd.PAllocator(), cmd.PDevice(), cmd.Result())
-		for _, d := range validationLayersData {
-			newCmd.AddRead(d.Data())
-		}
+		newCmd.AddRead(validationMetaLayerData.Data())
 		newCmd.AddRead(infoData.Data()).AddRead(layersData.Data())
 		// Also add back the read/write observations of the original vkCreateDevice
 		for _, r := range cmd.Extras().Observations().Reads {
diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh
index 70b65d7e98..8168a33d1f 100755
--- a/kokoro/linux/build.sh
+++ b/kokoro/linux/build.sh
@@ -33,9 +33,9 @@ sudo apt-get -qy install gcc-8 g++-8
 export CC=/usr/bin/gcc-8
 
 # Get the Android NDK
-curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip
-unzip -q android-ndk-r20b-linux-x86_64.zip
-export ANDROID_NDK_HOME=$PWD/android-ndk-r20b
+curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r21-linux-x86_64.zip
+unzip -q android-ndk-r21-linux-x86_64.zip
+export ANDROID_NDK_HOME=$PWD/android-ndk-r21
 
 # Get recent build tools
 echo y | $ANDROID_HOME/tools/bin/sdkmanager --install 'build-tools;29.0.2'
diff --git a/kokoro/macos/build.sh b/kokoro/macos/build.sh
index 896f686bdc..63714d92c4 100755
--- a/kokoro/macos/build.sh
+++ b/kokoro/macos/build.sh
@@ -24,10 +24,10 @@ curl -L -k -O -s https://dl.google.com/android/repository/tools_r25.2.3-macosx.z
 mkdir android
 unzip -q tools_r25.2.3-macosx.zip -d android
 echo y | ./android/tools/bin/sdkmanager build-tools\;29.0.2 platforms\;android-26
-curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r20b-darwin-x86_64.zip
-unzip -q android-ndk-r20b-darwin-x86_64.zip -d android
+curl -L -k -O -s https://dl.google.com/android/repository/android-ndk-r21-darwin-x86_64.zip
+unzip -q android-ndk-r21-darwin-x86_64.zip -d android
 export ANDROID_HOME=$PWD/android
-export ANDROID_NDK_HOME=$PWD/android/android-ndk-r20b
+export ANDROID_NDK_HOME=$PWD/android/android-ndk-r21
 
 # Get bazel.
 BAZEL_VERSION=2.0.0
diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat
index 1f9012f138..4e85ea7b6e 100644
--- a/kokoro/windows/build.bat
+++ b/kokoro/windows/build.bat
@@ -31,9 +31,9 @@ copy /Y "%SRC%\kokoro\windows\android-sdk-license" "%ANDROID_HOME%\licenses\"
 
 REM Install Android SDK platform, build tools and NDK
 call %ANDROID_HOME%\tools\bin\sdkmanager.bat platforms;android-26 build-tools;29.0.2
-wget -q https://dl.google.com/android/repository/android-ndk-r20b-windows-x86_64.zip
-unzip -q android-ndk-r20b-windows-x86_64.zip
-set ANDROID_NDK_HOME=%CD%\android-ndk-r20b
+wget -q https://dl.google.com/android/repository/android-ndk-r21-windows-x86_64.zip
+unzip -q android-ndk-r21-windows-x86_64.zip
+set ANDROID_NDK_HOME=%CD%\android-ndk-r21
 
 REM Install WiX Toolset.
 wget -q https://github.com/wixtoolset/wix3/releases/download/wix311rtm/wix311-binaries.zip
diff --git a/tools/build/rules/android.bzl b/tools/build/rules/android.bzl
index 760393bcb9..a20aa89cb6 100644
--- a/tools/build/rules/android.bzl
+++ b/tools/build/rules/android.bzl
@@ -107,18 +107,16 @@ android_native_app_glue = repository_rule(
 )
 
 # Retrieve Vulkan validation layers from the Android NDK
-
+# Since NDK r21, use the single VK_LAYER_KHRONOS_validation
 def _ndk_vk_validation_layer(ctx):
     build = ""
     for abi in ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]:
-
-        for layer in ["core_validation", "object_tracker", "parameter_validation", "threading", "unique_objects"]:
-            layerpath = abi + "/libVkLayer_" + layer + ".so"
-            ctx.symlink(
-                ctx.path(ctx.os.environ["ANDROID_NDK_HOME"] +
-                         "/sources/third_party/vulkan/src/build-android/jniLibs/" + layerpath),
-                ctx.path(layerpath),
-            )
+        layerpath = abi + "/libVkLayer_khronos_validation.so"
+        ctx.symlink(
+            ctx.path(ctx.os.environ["ANDROID_NDK_HOME"] +
+                        "/sources/third_party/vulkan/src/build-android/jniLibs/" + layerpath),
+            ctx.path(layerpath),
+        )
 
         build += "\n".join([
             "cc_library(",

From f969140cf707632f3a8012625de59871f53632b1 Mon Sep 17 00:00:00 2001
From: Adam Bodnar 
Date: Thu, 20 Feb 2020 12:33:25 -0800
Subject: [PATCH 0088/1218] Fix handle mappings (#77)

The existing logic was always failing the SizedTy cast and was thus
always returning 64bits for the handle sizes which in turn causes an out
of bounds memcpy on 32bit apps.
---
 gapis/replay/mapping_exporter.go | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/gapis/replay/mapping_exporter.go b/gapis/replay/mapping_exporter.go
index 5f07ee4dcd..c33b99bfb6 100644
--- a/gapis/replay/mapping_exporter.go
+++ b/gapis/replay/mapping_exporter.go
@@ -118,12 +118,7 @@ func (m *MappingExporter) ExtractRemappings(ctx context.Context, s *api.GlobalSt
 
 	for k, v := range b.Remappings {
 		typ := reflect.TypeOf(k)
-		var size uint64
-		if t, ok := k.(memory.SizedTy); ok {
-			size = t.TypeSize(s.MemoryLayout)
-		} else {
-			size = uint64(typ.Size())
-		}
+		size := memory.SizeOf(typ, s.MemoryLayout)
 
 		if size != 1 && size != 2 && size != 4 && size != 8 {
 			// Ignore objects that are not handles

From 24d5743a948a5da56616afc24a48d09c78f12a76 Mon Sep 17 00:00:00 2001
From: AWoloszyn 
Date: Wed, 19 Feb 2020 13:20:20 -0500
Subject: [PATCH 0089/1218] Small fix for command_splitter.

---
 gapis/api/vulkan/command_splitter.go | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/gapis/api/vulkan/command_splitter.go b/gapis/api/vulkan/command_splitter.go
index 8f5244dbcb..e18093f1a3 100644
--- a/gapis/api/vulkan/command_splitter.go
+++ b/gapis/api/vulkan/command_splitter.go
@@ -452,6 +452,7 @@ func (t *commandSplitter) splitCommandBuffer(ctx context.Context, embedBuffer Vk
 
 	for i := 0; i < commandBuffer.CommandReferences().Len(); i++ {
 		splitAfterCommand := false
+		replaceCommand := false
 		newCuts := []api.SubCmdIdx{}
 		for _, s := range cuts {
 			if s[0] == uint64(i) {
@@ -513,6 +514,7 @@ func (t *commandSplitter) splitCommandBuffer(ctx context.Context, embedBuffer Vk
 				}
 			}
 		case VkCmdExecuteCommandsArgsʳ:
+			replaceCommand = true
 			for j := 0; j < ar.CommandBuffers().Len(); j++ {
 				splitAfterExecute := false
 				newSubCuts := []api.SubCmdIdx{}
@@ -526,6 +528,7 @@ func (t *commandSplitter) splitCommandBuffer(ctx context.Context, embedBuffer Vk
 						}
 					}
 				}
+
 				cbo := st.CommandBuffers().Get(ar.CommandBuffers().Get(uint32(j)))
 				t.splitCommandBuffer(ctx, embedBuffer, cbo, queueSubmit, append(id, uint64(i), uint64(j)), newSubCuts, out)
 				if splitAfterExecute {
@@ -537,15 +540,6 @@ func (t *commandSplitter) splitCommandBuffer(ctx context.Context, embedBuffer Vk
 					}, out)
 				}
 			}
-			if splitAfterCommand {
-				t.WriteCommand(ctx, &InsertionCommand{
-					embedBuffer,
-					append([]VkCommandBuffer{}, t.pendingCommandBuffers...),
-					append(id, uint64(i)),
-					queueSubmit,
-				}, out)
-			}
-			continue
 		}
 		if splitAfterCommand {
 			// If we are inside a renderpass, then drop out for this call.
@@ -570,12 +564,14 @@ func (t *commandSplitter) splitCommandBuffer(ctx context.Context, embedBuffer Vk
 						t.thisRenderPass.DeviceGroupBeginInfo()))
 			}
 		}
-		cleanup, cmd, err := AddCommand(ctx, cb, embedBuffer, s, s, args)
-		if err != nil {
-			panic(fmt.Errorf("Invalid command-buffer detected %+v", err))
+		if !replaceCommand {
+			cleanup, cmd, err := AddCommand(ctx, cb, embedBuffer, s, s, args)
+			if err != nil {
+				panic(fmt.Errorf("Invalid command-buffer detected %+v", err))
+			}
+			t.WriteCommand(ctx, cmd, out)
+			cleanup()
 		}
-		t.WriteCommand(ctx, cmd, out)
-		cleanup()
 		for _, ea := range extraArgs {
 			if ins, ok := ea.(api.Cmd); ok {
 				t.WriteCommand(ctx, ins, out)

From 618b5ade9c782be854bd31e31ca63767b612d7c6 Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Fri, 21 Feb 2020 11:41:18 +0000
Subject: [PATCH 0090/1218] Consider if handle types match when replacing the
 replay handles (#72)

with trace handles

b/147979675
---
 gapis/trace/android/adreno/profiling_data.go | 47 +++++++++++---------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go
index 0e66b9e33f..d93d35f994 100644
--- a/gapis/trace/android/adreno/profiling_data.go
+++ b/gapis/trace/android/adreno/profiling_data.go
@@ -54,6 +54,29 @@ func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, ca
 	return &service.ProfilingData{Slices: slices, Counters: counters}, nil
 }
 
+func extractTraceHandles(ctx context.Context, replayHandles *[]int64, replayHandleType string, handleMapping *map[uint64][]service.VulkanHandleMappingItem) {
+	for i, v := range *replayHandles {
+		handles, ok := (*handleMapping)[uint64(v)]
+		if !ok {
+			log.E(ctx, "%v not found in replay: %v", replayHandleType, v)
+			continue
+		}
+
+		found := false
+		for _, handle := range handles {
+			if handle.HandleType == replayHandleType {
+				(*replayHandles)[i] = int64(handle.TraceValue)
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			log.E(ctx, "Incorrect Handle type for %v: %v", replayHandleType, v)
+		}
+	}
+}
+
 func processGpuSlices(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData_GpuSlices, error) {
 	slicesQueryResult, err := processor.Query(slicesQuery)
 	if err != nil {
@@ -83,31 +106,13 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur
 	// Grab all the column values. Depends on the order of columns selected in slicesQuery
 
 	contextIds := slicesColumns[0].GetLongValues()
-	for i, v := range contextIds {
-		if m, ok := (*handleMapping)[uint64(v)]; ok {
-			contextIds[i] = int64(m[0].TraceValue)
-		} else {
-			log.E(ctx, "Context Id not found: %v", v)
-		}
-	}
+	extractTraceHandles(ctx, &contextIds, "VkDevice", handleMapping)
 
 	renderTargets := slicesColumns[1].GetLongValues()
-	for i, v := range renderTargets {
-		if m, ok := (*handleMapping)[uint64(v)]; ok {
-			renderTargets[i] = int64(m[0].TraceValue)
-		} else {
-			log.E(ctx, "Render Target not found: %v", v)
-		}
-	}
+	extractTraceHandles(ctx, &renderTargets, "VkFramebuffer", handleMapping)
 
 	commandBuffers := slicesColumns[5].GetLongValues()
-	for i, v := range commandBuffers {
-		if m, ok := (*handleMapping)[uint64(v)]; ok {
-			commandBuffers[i] = int64(m[0].TraceValue)
-		} else {
-			log.E(ctx, "Command Buffer not found: %v", v)
-		}
-	}
+	extractTraceHandles(ctx, &commandBuffers, "VkCommandBuffer", handleMapping)
 
 	submissionIds := slicesColumns[3].GetLongValues()
 	currentSubId := int64(-1)

From 7467d184e43e3f1d2561742b1002e1b9b90f491b Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Fri, 21 Feb 2020 14:05:11 +0000
Subject: [PATCH 0091/1218] Remove the issues in initial commands from report
 (#73)

and log them instead

b/149014498
---
 gapis/api/vulkan/find_issues.go | 12 +++++-------
 gapis/config/config.go          |  1 +
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/gapis/api/vulkan/find_issues.go b/gapis/api/vulkan/find_issues.go
index 9372b4d7c0..3cc1288af2 100644
--- a/gapis/api/vulkan/find_issues.go
+++ b/gapis/api/vulkan/find_issues.go
@@ -23,6 +23,7 @@ import (
 	"github.com/google/gapid/gapis/api"
 	"github.com/google/gapid/gapis/api/transform"
 	"github.com/google/gapid/gapis/capture"
+	"github.com/google/gapid/gapis/config"
 	"github.com/google/gapid/gapis/replay"
 	"github.com/google/gapid/gapis/replay/builder"
 	"github.com/google/gapid/gapis/service"
@@ -279,18 +280,15 @@ func (t *findIssues) Flush(ctx context.Context, out transform.Writer) error {
 			issue.Severity = service.Severity(uint32(eMsg.GetSeverity()))
 
 			if issue.Command == api.CmdNoID {
-				// The debug report is issued for state rebuilding command
 				// TODO: Fix all the errors reported for initial commands.
-				// TODO: Provide a way for the UI to distinguish these issues
-				// from issues on command 0.
-				issue.Command = api.CmdID(0)
-				issue.Error = fmt.Errorf("[State rebuilding command : %s]	", msg)
+				if config.LogInitialCmdsIssues {
+					log.E(ctx, "Error in state rebuilding command : %s", msg)
+				}
 			} else {
 				// The debug report is issued for a trace command
 				issue.Error = fmt.Errorf("%s", msg)
+				t.issues = append(t.issues, issue)
 			}
-
-			t.issues = append(t.issues, issue)
 		})
 	}))
 	if err != nil {
diff --git a/gapis/config/config.go b/gapis/config/config.go
index 2e0093f8f1..9faf3d4ad1 100644
--- a/gapis/config/config.go
+++ b/gapis/config/config.go
@@ -32,6 +32,7 @@ const (
 	LogMappingsToFile        = false
 	LogTransformsToFile      = false
 	LogTransformsToCapture   = false
+	LogInitialCmdsIssues     = false
 	SeparateMutateStates     = false
 	CheckRebuiltStateMatches = false
 )

From b789f4122b017af22c7d3b578ae87c4f773818d3 Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Fri, 21 Feb 2020 13:55:10 -0800
Subject: [PATCH 0092/1218] Fix GPU counter's config update issue. (#68)

- Populate the remembered counter selection from the most updated
 perfetto settings, rather than from a possibly outdated copy.
 - Bug: http://b/149737345.
---
 .../com/google/gapid/perfetto/views/TraceConfigDialog.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
index 0c09ebdab0..edb2763700 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
@@ -488,8 +488,8 @@ public BasicInputArea(Composite parent, Settings settings, Theme theme,
 
           gpuCountersLabels[0] = createLabel(counterGroup, sGpu.getCounterIdsCount() + " selected");
           gpuCountersSelect = Widgets.createButton(counterGroup, "Select", e -> {
-            GpuCountersDialog dialog =
-                new GpuCountersDialog(getShell(), theme, caps, sGpu.getCounterIdsList());
+            List currentIds = settings.perfetto().getGpuOrBuilder().getCounterIdsList();
+            GpuCountersDialog dialog = new GpuCountersDialog(getShell(), theme, caps, currentIds);
             if (dialog.open() == Window.OK) {
               List newIds = dialog.getSelectedIds();
               settings.writePerfetto().getGpuBuilder()

From 451aec7d0b0a7d139b515ae436675f27196fb41d Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Mon, 24 Feb 2020 09:57:55 -0800
Subject: [PATCH 0093/1218] Don't automatically select default counters at
 empty selection. (#80)

- Bug: http://b/150017682.
---
 .../com/google/gapid/perfetto/views/TraceConfigDialog.java     | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
index edb2763700..caa608185c 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
@@ -810,8 +810,7 @@ protected Control createDialogArea(Composite parent) {
         table.setInput(caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList());
         table.setCheckedElements(
             caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList().stream()
-                .filter(currentIds.isEmpty() ?
-                    SELECT_DEFAULT : c -> currentIds.contains(c.getCounterId()))
+                .filter(c -> currentIds.contains(c.getCounterId()))
                 .toArray(GpuProfiling.GpuCounterDescriptor.GpuCounterSpec[]::new));
         table.getTable().getColumn(0).pack();
         table.getTable().getColumn(1).pack();

From 2a1e5450dda42384316c2c538401b0a23dfeb7bf Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Mon, 24 Feb 2020 10:00:30 -0800
Subject: [PATCH 0094/1218] Fix several bugs in counter panel. (#79)

 - Identify a counter selection by counter id rather than the combinition of name and start time ts.
 - It will avoid losing track of the selection when quantization do some approximations on the time.
 - Bug 1: http://b/147922469, #5.
 - Bug 2: http://b/149959272, #2.
 - Bug 3: http://b/149959272. #1.
---
 .../gapid/perfetto/models/CounterTrack.java   | 93 ++++++++-----------
 .../gapid/perfetto/models/Selection.java      |  2 +-
 .../gapid/perfetto/views/CounterPanel.java    | 11 +--
 3 files changed, 47 insertions(+), 59 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java
index 5987bf9472..8c39396444 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java
@@ -39,17 +39,19 @@
 
 public class CounterTrack extends Track.WithQueryEngine {
   private static final String VIEW_SQL_DELTA =
-      "select ts + 1 ts, lead(ts) over win - ts dur, lead(value) over win value " +
+      "select ts + 1 ts, lead(ts) over win - ts dur, lead(value) over win value, lead(id) over win id " +
       "from counter where track_id = %d window win as (order by ts)";
   private static final String VIEW_SQL_EVENT =
-      "select ts, lead(ts, 1, (select end_ts from trace_bounds)) over win - ts dur, value " +
+      "select ts, lead(ts, 1, (select end_ts from trace_bounds)) over win - ts dur, value, id " +
       "from counter where track_id = %d window win as (order by ts)";
   private static final String SUMMARY_SQL =
-      "select min(ts), max(ts + dur), avg(value) from %s group by quantum_ts";
-  private static final String COUNTER_SQL = "select ts, ts + dur, value from %s";
-  private static final String VALUE_SQL = "select ts, ts + dur, value from %s where ts = %d";
+      "select min(ts), max(ts + dur), avg(value), best_id from " +
+        "(select *, first_value(id) over (partition by quantum_ts order by dur desc) as best_id from %s) " +
+      "group by quantum_ts";
+  private static final String COUNTER_SQL = "select ts, ts + dur, value, id from %s";
+  private static final String VALUE_SQL = "select ts, ts + dur, value, id from %s where id = %d";
   private static final String RANGE_SQL =
-      "select ts, ts + dur, value from %s " +
+      "select ts, ts + dur, value, id from %s " +
       "where ts + dur >= %d and ts <= %d order by ts";
 
   private final CounterInfo counter;
@@ -99,13 +101,15 @@ private ListenableFuture computeData(DataRequest req, Window win) {
         return Data.empty(req);
       }
 
-      Data data = new Data(req, new long[rows + 1], new double[rows + 1]);
+      Data data = new Data(req, new long[rows + 1], new double[rows + 1], new long[rows + 1]);
       res.forEachRow((i, r) -> {
         data.ts[i] = r.getLong(0);
         data.values[i] = r.getDouble(2);
+        data.ids[i] = r.getLong(3);
       });
       data.ts[rows] = res.getLong(rows - 1, 1, 0);
       data.values[rows] = data.values[rows - 1];
+      data.ids[rows] = data.ids[rows - 1];
       return data;
     });
   }
@@ -118,13 +122,15 @@ private String counterSQL() {
     return format(COUNTER_SQL, tableName("span"));
   }
 
-  public ListenableFuture getValue(long t) {
-    return transform(expectOneRow(qe.query(valueSql(t))), row -> {
-      Data data = new Data(null, new long[2], new double[2]);
+  public ListenableFuture getValue(long id) {
+    return transform(expectOneRow(qe.query(valueSql(id))), row -> {
+      Data data = new Data(null, new long[2], new double[2], new long[2]);
       data.ts[0] = row.getLong(0);
       data.ts[1] = row.getLong(1);
       data.values[0] = row.getDouble(2);
       data.values[1] = data.values[0];
+      data.ids[0] = row.getLong(3);
+      data.ids[1] = data.ids[0];
       return data;
     });
   }
@@ -136,19 +142,21 @@ public ListenableFuture getValues(TimeSpan ts) {
         return Data.empty(null);
       }
 
-      Data data = new Data(null, new long[rows + 1], new double[rows + 1]);
+      Data data = new Data(null, new long[rows + 1], new double[rows + 1], new long[rows + 1]);
       res.forEachRow((i, r) -> {
         data.ts[i] = r.getLong(0);
         data.values[i] = r.getDouble(2);
+        data.ids[i] = r.getLong(3);
       });
       data.ts[rows] = res.getLong(rows - 1, 1, 0);
       data.values[rows] = data.values[rows - 1];
+      data.ids[rows] = data.ids[rows - 1];
       return data;
     });
   }
 
-  private String valueSql(long t) {
-    return format(VALUE_SQL, tableName("vals"), t);
+  private String valueSql(long id) {
+    return format(VALUE_SQL, tableName("vals"), id);
   }
 
   private String rangeSql(TimeSpan ts) {
@@ -158,44 +166,46 @@ private String rangeSql(TimeSpan ts) {
   public static class Data extends Track.Data {
     public final long[] ts;
     public final double[] values;
+    public final long[] ids;
 
-    public Data(DataRequest request, long[] ts, double[] values) {
+    public Data(DataRequest request, long[] ts, double[] values, long[] ids) {
       super(request);
       this.ts = ts;
       this.values = values;
+      this.ids = ids;
     }
 
     public static Data empty(DataRequest req) {
-      return new Data(req, new long[0], new double[0]);
+      return new Data(req, new long[0], new double[0], new long[0]);
     }
   }
 
-  public static class Values implements Selection, Selection.Builder {
+  public static class Values implements Selection, Selection.Builder {
     public final long[] ts;
     public final String[] names;
     public final double[][] values;
-    private final Set valueKeys = Sets.newHashSet();
+    public final long[][] ids;
+    private final Set valueKeys = Sets.newHashSet();
 
     public Values(String name, Data data) {
       this.ts = data.ts;
       this.names = new String[] { name };
       this.values = new double[][] { data.values };
+      this.ids = new long[][] { data.ids };
       initKeys();
     }
 
-    private Values(long[] ts, String[] names, double[][] values) {
+    private Values(long[] ts, String[] names, double[][] values, long[][] ids) {
       this.ts = ts;
       this.names = names;
       this.values = values;
+      this.ids = ids;
       initKeys();
     }
 
     private void initKeys() {
-      for (String name : names) {
-        // Skip the last dummy entry for the range end.
-        Arrays.stream(ts, 0, ts.length - 1)
-            .boxed()
-            .forEach(t -> valueKeys.add(new Values.Key(name, t)));
+      for (long[] keys : ids) {
+        Arrays.stream(keys).forEach(valueKeys::add);
       }
     }
 
@@ -205,7 +215,7 @@ public String getTitle() {
     }
 
     @Override
-    public boolean contains(Values.Key key) {
+    public boolean contains(Long key) {
       return valueKeys.contains(key);
     }
 
@@ -237,34 +247,39 @@ public Values combine(Values other) {
       long[] newTs = combineTs(ts, other.ts);
 
       double[][] newValues = new double[names.length + other.names.length][newTs.length];
+      long[][] newIds = new long[names.length + other.names.length][newTs.length];
       for (int i = 0, me = 0, them = 0; i < newTs.length; i++) {
         long rTs = newTs[i], meTs = ts[me], themTs = other.ts[them];
         if (rTs == meTs) {
           for (int n = 0; n < names.length; n++) {
             newValues[n][i] = values[n][me];
+            newIds[n][i] = ids[n][me];
           }
           me = Math.min(me + 1, ts.length - 1);
         } else if (i > 0) {
           for (int n = 0; n < names.length; n++) {
             newValues[n][i] = newValues[n][i - 1];
+            newIds[n][i] = newIds[n][i - 1];
           }
         }
 
         if (rTs == themTs) {
           for (int n = 0; n < other.names.length; n++) {
             newValues[n + names.length][i] = other.values[n][them];
+            newIds[n + names.length][i] = other.ids[n][them];
           }
           them = Math.min(them + 1, other.ts.length - 1);
         } else if (i > 0) {
           for (int n = 0; n < other.names.length; n++) {
             newValues[names.length + n][i] = newValues[names.length + n][i - 1];
+            newIds[names.length + n][i] = newIds[names.length + n][i - 1];
           }
         }
       }
 
       String[] newNames = Arrays.copyOf(names, names.length + other.names.length);
       System.arraycopy(other.names, 0, newNames, names.length, other.names.length);
-      return new Values(newTs, newNames, newValues);
+      return new Values(newTs, newNames, newValues, newIds);
     }
 
     private static long[] combineTs(long[] a, long[] b) {
@@ -295,34 +310,8 @@ private static long[] combineTs(long[] a, long[] b) {
     }
 
     @Override
-    public Selection build() {
+    public Selection build() {
       return this;
     }
-
-    public static class Key {
-      public final String name;
-      public final long ts;
-
-      public Key(String name, long ts) {
-        this.name = name;
-        this.ts = ts;
-      }
-
-      @Override
-      public boolean equals(Object obj) {
-        if (obj == this) {
-          return true;
-        } else if (!(obj instanceof Key)) {
-          return false;
-        }
-        Key o = (Key)obj;
-        return name.equals(o.name) && ts == o.ts;
-      }
-
-      @Override
-      public int hashCode() {
-        return name.hashCode() ^ Long.hashCode(ts);
-      }
-    }
   }
 }
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
index 7714877b66..73d453ab7b 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
@@ -207,7 +207,7 @@ public static class Kind implements Comparable>{
     public static final Kind Cpu = new Kind(2);
     public static final Kind Gpu = new Kind(3);
     public static final Kind VulkanEvent = new Kind(4);
-    public static final Kind Counter = new Kind(5);
+    public static final Kind Counter = new Kind(5);
     public static final Kind FrameEvents = new Kind(6);
 
     public int priority;
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java
index fa6f81b5bc..b20c22bfb3 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java
@@ -29,7 +29,6 @@
 import com.google.gapid.perfetto.canvas.Size;
 import com.google.gapid.perfetto.models.CounterInfo;
 import com.google.gapid.perfetto.models.CounterTrack;
-import com.google.gapid.perfetto.models.CounterTrack.Values;
 import com.google.gapid.perfetto.models.Selection;
 import com.google.gapid.perfetto.models.Selection.CombiningBuilder;
 
@@ -94,7 +93,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
       CounterInfo counter = track.getCounter();
       double min = counter.range.min, range = counter.range.range();
 
-      Selection selected = state.getSelection(Selection.Kind.Counter);
+      Selection selected = state.getSelection(Selection.Kind.Counter);
       List visibleSelected = Lists.newArrayList();
       mainGradient().applyBaseAndBorder(ctx);
       ctx.path(path -> {
@@ -107,7 +106,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
           path.lineTo(nextX, nextY);
           lastX = nextX;
           lastY = nextY;
-          if (selected.contains(new Values.Key(track.getCounter().name, data.ts[i]))) {
+          if (selected.contains(data.ids[i])) {
             visibleSelected.add(i);
           }
         }
@@ -179,7 +178,7 @@ protected Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int m
       return Hover.NONE;
     }
 
-    long t = data.ts[idx];
+    long id = data.ids[idx];
     double startX = state.timeToPx(data.ts[idx]);
     double endX = (idx >= data.ts.length - 1) ? startX : state.timeToPx(data.ts[idx + 1]);
     hovered = new HoverCard(m, track.getCounter(), data.values[idx], startX, endX, x);
@@ -203,10 +202,10 @@ public void stop() {
       public boolean click() {
         if ((mods & SWT.MOD1) == SWT.MOD1) {
           state.addSelection(Selection.Kind.Counter,
-              transform(track.getValue(t), d -> new CounterTrack.Values(track.getCounter().name, d)));
+              transform(track.getValue(id), d -> new CounterTrack.Values(track.getCounter().name, d)));
         } else {
           state.setSelection(Selection.Kind.Counter,
-              transform(track.getValue(t), d -> new CounterTrack.Values(track.getCounter().name, d)));
+              transform(track.getValue(id), d -> new CounterTrack.Values(track.getCounter().name, d)));
         }
         return true;
       }

From 1a5621699af6902b23ac88d0b4efe47527ffe356 Mon Sep 17 00:00:00 2001
From: Paul Thomson 
Date: Tue, 25 Feb 2020 09:52:01 +0000
Subject: [PATCH 0095/1218] CI: Trace Vulkan sample app via SwiftShader (#76)

---
 kokoro/linux/build.sh | 44 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh
index 8168a33d1f..7eee6c41bf 100755
--- a/kokoro/linux/build.sh
+++ b/kokoro/linux/build.sh
@@ -81,6 +81,50 @@ do
 done
 echo $(date): Smoketests completed.
 
+set -e
+
 # Build the release packages.
 mkdir $BUILD_ROOT/out
 $SRC/kokoro/linux/package.sh $BUILD_ROOT/out
+
+##
+## Test capture and replay of the Vulkan Sample App.
+##
+
+# Install the Vulkan loader and xvfb (X virtual framebuffer).
+sudo apt-get -qy install libvulkan1 xvfb
+
+# Get prebuilt SwiftShader.
+# This is the latest commit at the time of writing.
+# Should be updated periodically.
+curl -fsSL -o swiftshader.zip https://github.com/google/gfbuild-swiftshader/releases/download/github%2Fgoogle%2Fgfbuild-swiftshader%2F0bbf7ba9f909092f0328b1d519d5f7db1773be57/gfbuild-swiftshader-0bbf7ba9f909092f0328b1d519d5f7db1773be57-Linux_x64_Debug.zip
+unzip -d swiftshader swiftshader.zip
+
+# Use SwiftShader.
+export VK_ICD_FILENAMES="$(pwd)/swiftshader/lib/vk_swiftshader_icd.json"
+export VK_LOADER_DEBUG=all
+
+# Just try running the app first.
+
+# Allow non-zero exit status.
+set +e
+
+xvfb-run -e xvfb.log -a timeout --preserve-status -s INT -k 5 5 bazel-bin/cmd/vulkan_sample/vulkan_sample
+
+APP_EXIT_STATUS="${?}"
+
+set -e
+
+if test -f xvfb.log; then
+  cat xvfb.log
+fi
+
+# This line will exit with status 1 if the app's exit status
+# was anything other than 130 (128+SIGINT).
+test "${APP_EXIT_STATUS}" -eq 130
+
+# TODO(https://github.com/google/gapid/issues/3163): The coherent memory
+#  tracker must be disabled with SwiftShader for now.
+xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample
+
+xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 vulkan_sample.gfxtrace

From 0f3e5369186281056af3d1f79f0f300d7d8a72cd Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Tue, 25 Feb 2020 13:43:33 -0800
Subject: [PATCH 0096/1218] Add the option to allow users to mark flags along
 the timeline (#66)

Add Flags on timeline panel
---
 gapic/res/icons/flag.png                      | Bin 0 -> 117 bytes
 gapic/res/icons/flag@2x.png                   | Bin 0 -> 160 bytes
 gapic/res/icons/flag_filled.png               | Bin 0 -> 108 bytes
 gapic/res/icons/flag_filled@2x.png            | Bin 0 -> 148 bytes
 gapic/res/icons/flag_greyed.png               | Bin 0 -> 138 bytes
 gapic/res/icons/flag_greyed@2x.png            | Bin 0 -> 207 bytes
 gapic/res/icons/flag_white.png                | Bin 0 -> 126 bytes
 gapic/res/icons/flag_white@2x.png             | Bin 0 -> 183 bytes
 gapic/res/icons/flag_white_filled.png         | Bin 0 -> 108 bytes
 gapic/res/icons/flag_white_filled@2x.png      | Bin 0 -> 147 bytes
 .../google/gapid/perfetto/canvas/Panel.java   |  17 +++
 .../gapid/perfetto/canvas/PanelCanvas.java    |   4 +
 .../gapid/perfetto/views/RootPanel.java       | 111 ++++++++++++++++++
 .../gapid/perfetto/views/StyleConstants.java  |  26 ++++
 .../com/google/gapid/views/ProfileView.java   |   5 +
 .../main/com/google/gapid/widgets/Theme.java  |   5 +
 16 files changed, 168 insertions(+)
 create mode 100644 gapic/res/icons/flag.png
 create mode 100644 gapic/res/icons/flag@2x.png
 create mode 100644 gapic/res/icons/flag_filled.png
 create mode 100644 gapic/res/icons/flag_filled@2x.png
 create mode 100644 gapic/res/icons/flag_greyed.png
 create mode 100644 gapic/res/icons/flag_greyed@2x.png
 create mode 100644 gapic/res/icons/flag_white.png
 create mode 100644 gapic/res/icons/flag_white@2x.png
 create mode 100644 gapic/res/icons/flag_white_filled.png
 create mode 100644 gapic/res/icons/flag_white_filled@2x.png

diff --git a/gapic/res/icons/flag.png b/gapic/res/icons/flag.png
new file mode 100644
index 0000000000000000000000000000000000000000..b902f6f7efbcadc83a30ec78f09c4a8e4abc2e59
GIT binary patch
literal 117
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjHl8kyAr*|t5?c~P{-`(bX5=2M
zdKJ+iJLh=5Hmh%hi5S&};Q{8{!$
Ppg9blu6{1-oD!MbtCa1sMj032h!PC{xWt~$(
F696Y+8=wFH

literal 0
HcmV?d00001

diff --git a/gapic/res/icons/flag_filled@2x.png b/gapic/res/icons/flag_filled@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..27e31ca2bdbdc43146413067c8209b1048374d9c
GIT binary patch
literal 148
zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtXipc%kP61PHw<|j92i&}y`BU-
z=n%4;!r>$q@j#f%Y^JZ@fi31QQztF?z4&bDfhhJjr3Y@Z_3#6=GB7;I2U86j*I7MS
l!Mx2Xfs-NWxEMrCjN6j;OXk;vd$@?2>>%KD%=17

literal 0
HcmV?d00001

diff --git a/gapic/res/icons/flag_greyed@2x.png b/gapic/res/icons/flag_greyed@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..89a0bc7aca505e5a41f20c2e26ebc1d357bea8bc
GIT binary patch
literal 207
zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtX`U{QAr*{ouM6@tI7qZTG&nQ8
zc!Kx4eFm00e*fGy=MWGUpVNHa^!aU6?$_M+yZ`<;m|V^(C>ZFc*z&oz+i=VAjOTWGNlf^3@BOO=SCImHUZ6cdP*JehDj}3z=2pWO?bY_|
yckbl9T7S_~_QGqXOWOn){%C>~O%P;IQrg83cKTJ!?(ec+L1Lb+elF{r5}E)7W>U@o

literal 0
HcmV?d00001

diff --git a/gapic/res/icons/flag_white.png b/gapic/res/icons/flag_white.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8a47b617d688fc76df395a3c5c0c05d7396ea72
GIT binary patch
literal 126
zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjuAVNAAr*|t5_1wn{;2a6T)4#~
z+@*U!(Oi1|+AA9rW=|6fSeJf_Le;vywsm#4^dX2GIcEdHsYK{;4{xbr#!hl>}zg5C&=4n<5
iTntIa#lXT1DleIMf(ren@7&@H67Y2Ob6Mw<&;$VK|0t{g

literal 0
HcmV?d00001

diff --git a/gapic/src/main/com/google/gapid/perfetto/canvas/Panel.java b/gapic/src/main/com/google/gapid/perfetto/canvas/Panel.java
index 122e3136c0..0677d2ef43 100644
--- a/gapic/src/main/com/google/gapid/perfetto/canvas/Panel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/canvas/Panel.java
@@ -135,6 +135,7 @@ public default void stop() { /* empty */ }
 
     /** Returns whether the screen should be redrawn. */
     public default boolean click() { return false; }
+    public default boolean rightClick() { return click(); }
 
     public default Panel.Hover translated(double dx, double dy) {
       return transformed(a -> a.translate(dx, dy));
@@ -167,6 +168,11 @@ public boolean isOverlay() {
         public boolean click() {
           return Hover.this.click();
         }
+
+        @Override
+        public boolean rightClick() {
+          return Hover.this.rightClick();
+        }
       };
     }
 
@@ -197,6 +203,12 @@ public boolean click() {
           boolean r1 = Hover.this.click(), r2 = onClick.getAsBoolean();
           return r1 || r2;
         }
+
+        @Override
+        public boolean rightClick() {
+          boolean r1 = Hover.this.rightClick(), r2 = onClick.getAsBoolean();
+          return r1 || r2;
+        }
       };
     }
 
@@ -226,6 +238,11 @@ public boolean isOverlay() {
         public boolean click() {
           return Hover.this.click();
         }
+
+        @Override
+        public boolean rightClick() {
+          return Hover.this.rightClick();
+        }
       };
     }
   }
diff --git a/gapic/src/main/com/google/gapid/perfetto/canvas/PanelCanvas.java b/gapic/src/main/com/google/gapid/perfetto/canvas/PanelCanvas.java
index 30802d18b2..94a4832632 100644
--- a/gapic/src/main/com/google/gapid/perfetto/canvas/PanelCanvas.java
+++ b/gapic/src/main/com/google/gapid/perfetto/canvas/PanelCanvas.java
@@ -99,6 +99,10 @@ public PanelCanvas(Composite parent, int style, Theme theme, Panel panel) {
         redraw(dragger.onDragEnd(e.x, e.y), false);
         dragger = Panel.Dragger.NONE;
         updateMousePosition(e.x, e.y, 0, false, true);
+      } else if (e.button == 3) {
+        if (hover.rightClick()) {
+          structureHasChanged();
+        }
       } else if (hover.click()) {
         structureHasChanged();
       }
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/RootPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/RootPanel.java
index 443c5d8282..190000f234 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/RootPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/RootPanel.java
@@ -19,10 +19,14 @@
 import static com.google.gapid.perfetto.views.StyleConstants.HIGHLIGHT_EDGE_NEARBY_WIDTH;
 import static com.google.gapid.perfetto.views.StyleConstants.LABEL_WIDTH;
 import static com.google.gapid.perfetto.views.StyleConstants.colors;
+import static com.google.gapid.perfetto.views.StyleConstants.flag;
+import static com.google.gapid.perfetto.views.StyleConstants.flagFilled;
+import static com.google.gapid.perfetto.views.StyleConstants.flagGreyed;
 import static com.google.gapid.widgets.Widgets.createToggleToolItem;
 import static com.google.gapid.widgets.Widgets.exclusiveSelection;
 import static java.util.Arrays.stream;
 
+import com.google.common.collect.Maps;
 import com.google.gapid.models.Settings;
 import com.google.gapid.perfetto.TimeSpan;
 import com.google.gapid.perfetto.canvas.Area;
@@ -43,6 +47,8 @@
 import org.eclipse.swt.widgets.ToolBar;
 import org.eclipse.swt.widgets.ToolItem;
 
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntConsumer;
@@ -56,6 +62,8 @@ public abstract class RootPanel extends Panel.Base implements S
   private static final double HIGHLIGHT_BOTTOM = 30;
   private static final double HIGHLIGHT_CENTER = (HIGHLIGHT_TOP + HIGHLIGHT_BOTTOM) / 2;
   private static final double HIGHLIGHT_PADDING = 3;
+  private static final double FLAG_WIDTH = 17;  // Width of the actual flag, not the image's pixel width
+  public static final double FLAGS_Y = 30;
 
   protected final Settings settings;
   protected final TimelinePanel timeline;
@@ -70,11 +78,16 @@ public abstract class RootPanel extends Panel.Base implements S
   private boolean isHighlightStartHovered = false;
   private boolean isHighlightEndHovered = false;
 
+  protected TreeMap flags;
+  protected boolean flagHovered = false;
+  protected double flagHoverXpos;
+
   public RootPanel(S state, Settings settings) {
     this.settings = settings;
     this.timeline = new TimelinePanel(state);
     this.state = state;
     this.showVSync = settings.ui().getPerfetto().getShowVsync();
+    this.flags = Maps.newTreeMap();
     state.addListener(this);
   }
 
@@ -106,6 +119,36 @@ public void setSize(double w, double h) {
     state.setMaxScrollOffset(bottomHeight - h + topHeight);
   }
 
+  private SortedMap searchForFlag(double x) {
+    long time = state.pxToTime(x);
+    // If the click falls within the flag icon's boundaries, the flag is considered to be hit.
+    // Leave an additional two pixels to the left of the flag to get a better hit box
+    long rightOffset = state.deltaPxToDuration(FLAG_WIDTH);
+    long leftOffset = state.deltaPxToDuration(2);
+
+    return flags.subMap(time - rightOffset, time + leftOffset);
+  }
+
+  protected void searchAndRemoveFlag(double x) {
+    SortedMap subMap = searchForFlag(x);
+    if (!subMap.isEmpty()) {
+      subMap.clear();
+    }
+  }
+
+  protected void searchAndAddFlag(double x) {
+    SortedMap subMap = searchForFlag(x);
+    if (subMap.isEmpty()) {
+      flags.put(state.pxToTime(x), true);
+    } else {
+      toggleFlag(subMap);
+    }
+  }
+
+  private static void toggleFlag(SortedMap subMap) {
+    subMap.replaceAll((k,v) -> v = !v);
+  }
+
   @Override
   public void render(RenderContext ctx, Repainter repainter) {
     double topHeight = top.getPreferredHeight();
@@ -125,6 +168,8 @@ public void render(RenderContext ctx, Repainter repainter) {
       });
     }
 
+    postMainUiRender(ctx);
+
     TimeSpan highlight = state.getHighlight();
     if (highlight != TimeSpan.ZERO) {
       double newClipX = Math.max(clip.x, LABEL_WIDTH);
@@ -196,6 +241,7 @@ public void render(RenderContext ctx, Repainter repainter) {
 
   protected abstract void preTopUiRender(RenderContext ctx, Repainter repainter);
   protected abstract void preMainUiRender(RenderContext ctx, Repainter repainter);
+  protected abstract void postMainUiRender(RenderContext ctx);
 
   @Override
   public void visit(Visitor v, Area area) {
@@ -359,6 +405,9 @@ protected void finishSelection(int mods) {
 
   @Override
   public Hover onMouseMove(Fonts.TextMeasurer m, double x, double y, int mods) {
+    if (y >= (timeline.getPreferredHeight()/2) && y <= timeline.getPreferredHeight() && x > LABEL_WIDTH) {
+      return flagHover(x);
+    }
     double topHeight = top.getPreferredHeight();
     Hover result = (y < topHeight) ? top.onMouseMove(m, x, y, mods) :
       bottom.onMouseMove(m, x, y - topHeight + state.getScrollOffset(), mods)
@@ -382,6 +431,41 @@ public Hover onMouseMove(Fonts.TextMeasurer m, double x, double y, int mods) {
     return result;
   }
 
+  private Hover flagHover(double x) {
+    if (searchForFlag(x - LABEL_WIDTH).isEmpty()) {
+      flagHovered = true;
+      flagHoverXpos = x;
+    } else {
+      flagHovered = false;
+    }
+    return new Panel.Hover() {
+      @Override
+      public Area getRedraw() {
+        TimeSpan visible = state.getVisibleTime();
+        // Redraw the entire visible range
+        return new Area(
+            state.timeToPx(visible.start), 0, bottom.getPreferredHeight(), state.timeToPx(visible.end));
+      }
+
+      @Override
+      public boolean click() {
+        searchAndAddFlag(x - LABEL_WIDTH);
+        return true;
+      }
+
+      @Override
+      public boolean rightClick() {
+        searchAndRemoveFlag(x - LABEL_WIDTH);
+        return true;
+      }
+
+      @Override
+      public void stop() {
+        flagHovered = false;
+      }
+    };
+  }
+
   private double findHighlightFixedEnd(double sx) {
     double hStart = state.timeToPx(state.getHighlight().start) + LABEL_WIDTH;
     double hEnd = state.timeToPx(state.getHighlight().end) + LABEL_WIDTH;
@@ -466,6 +550,33 @@ protected void preMainUiRender(RenderContext ctx, Repainter repainter) {
       }
     }
 
+    @Override
+    protected void postMainUiRender(RenderContext ctx) {
+      // Render the Flag in the timeline panel and the vertical line in the bottom panel group
+      renderFlags(ctx, bottom);
+    }
+
+    private void renderFlags(RenderContext ctx, Panel panel) {
+      flags.forEach((k,v) -> {
+        double x = Math.rint(LABEL_WIDTH + state.timeToPx(k));
+        if (x > LABEL_WIDTH) {
+          if (v) {
+            ctx.drawIcon(flagFilled(ctx.theme), x - 5, FLAGS_Y, 0);
+            ctx.setForegroundColor(colors().flagLine);
+            ctx.drawLine(x, FLAGS_Y, x, panel.getPreferredHeight());
+          } else {
+            ctx.drawIcon(flag(ctx.theme), x - 5, FLAGS_Y, 0);
+          }
+        }
+      });
+      if (flagHovered) {
+        double x = flagHoverXpos;
+        ctx.drawIcon(flagGreyed(ctx.theme), x - 5, FLAGS_Y, 0);
+        ctx.setForegroundColor(colors().flagHover);
+        ctx.drawLine(x, FLAGS_Y, x, panel.getPreferredHeight());
+      }
+    }
+
     private void renderVSync(RenderContext ctx, Repainter repainter, Panel panel, VSync vsync) {
       ctx.trace("VSync", () -> {
         VSync.Data data = vsync.getData(state.toRequest(),
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/StyleConstants.java b/gapic/src/main/com/google/gapid/perfetto/views/StyleConstants.java
index 9b4fbd7afe..fd310f1cd3 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/StyleConstants.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/StyleConstants.java
@@ -67,6 +67,8 @@ public static class Colors {
     public final RGBA cpuFreqIdle;
     public final RGBA timelineRuler;
     public final RGBA vsyncBackground;
+    public final RGBA flagLine;
+    public final RGBA flagHover;
 
     public final RGBA textMain;
     public final RGBA textAlt;
@@ -86,6 +88,8 @@ public Colors(RGBA background,
         RGBA cpuFreqIdle,
         RGBA timelineRuler,
         RGBA vsyncBackground,
+        RGBA flagLine,
+        RGBA flagHover,
         RGBA textMain,
         RGBA textAlt) {
       this.background = background;
@@ -103,6 +107,8 @@ public Colors(RGBA background,
       this.cpuFreqIdle = cpuFreqIdle;
       this.timelineRuler = timelineRuler;
       this.vsyncBackground = vsyncBackground;
+      this.flagLine = flagLine;
+      this.flagHover = flagHover;
       this.textMain = textMain;
       this.textAlt = textAlt;
     }
@@ -122,6 +128,8 @@ public Colors(RGBA background,
     private static final RGBA LIGHT_CPU_FREQ_IDLE = rgb(0xf0, 0xf0, 0xf0);
     private static final RGBA LIGHT_TIMELINE_RULER = rgb(0x99, 0x99, 0x99);
     private static final RGBA LIGHT_VSYNC_BACKGROUND = rgb(0xf5, 0xf5, 0xf5);
+    private static final RGBA LIGHT_FLAG_LINE = rgb(0, 0, 0);
+    private static final RGBA LIGHT_FLAG_HOVER = rgb(0x80, 0x80, 0x80);
 
     private static final RGBA LIGHT_TEXT_MAIN = rgb(0x32, 0x34, 0x35);
     private static final RGBA LIGHT_TEXT_ALT = rgb(101, 102, 104);
@@ -143,6 +151,8 @@ public static Colors light() {
             LIGHT_CPU_FREQ_IDLE,
             LIGHT_TIMELINE_RULER,
             LIGHT_VSYNC_BACKGROUND,
+            LIGHT_FLAG_LINE,
+            LIGHT_FLAG_HOVER,
             LIGHT_TEXT_MAIN,
             LIGHT_TEXT_ALT);
     }
@@ -162,6 +172,8 @@ public static Colors light() {
     private static final RGBA DARK_CPU_FREQ_IDLE = rgb(0x55, 0x55, 0x55);
     private static final RGBA DARK_TIMELINE_RULER = rgb(0x99, 0x99, 0x99);
     private static final RGBA DARK_VSYNC_BACKGROUND = rgb(0x24, 0x24, 0x24);
+    private static final RGBA DARK_FLAG_LINE = rgb(0xff, 0xff, 0xff);
+    private static final RGBA DARK_FLAG_HOVER = rgb(0x80, 0x80, 0x80);
 
     private static final RGBA DARK_TEXT_MAIN = rgb(0xf1, 0xf1, 0xf8);
     private static final RGBA DARK_TEXT_ALT = rgb(0xdd, 0xdd, 0xdd);
@@ -183,6 +195,8 @@ public static Colors dark() {
             DARK_CPU_FREQ_IDLE,
             DARK_TIMELINE_RULER,
             DARK_VSYNC_BACKGROUND,
+            DARK_FLAG_LINE,
+            DARK_FLAG_HOVER,
             DARK_TEXT_MAIN,
             DARK_TEXT_ALT);
     }
@@ -303,6 +317,18 @@ public static Image pinInactive(Theme theme) {
     return isDark ? theme.pinInactiveDark() : theme.pinInactiveLight();
   }
 
+  public static Image flag(Theme theme) {
+    return isDark ? theme.flagDark() : theme.flagLight();
+  }
+
+  public static Image flagFilled(Theme theme) {
+    return isDark ? theme.flagFilledDark() : theme.flagFilledLight();
+  }
+
+  public static Image flagGreyed(Theme theme) {
+    return theme.flagGreyed();
+  }
+
   public static class Gradient {
     private static final float HIGH_TARGET = 0.9f;
     private static final float LOW_TARGET = 0.2f;
diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java
index 9887e2f0cf..d59ad4357c 100644
--- a/gapic/src/main/com/google/gapid/views/ProfileView.java
+++ b/gapic/src/main/com/google/gapid/views/ProfileView.java
@@ -209,6 +209,11 @@ protected void preTopUiRender(RenderContext ctx, Repainter repainter) {
         protected void preMainUiRender(RenderContext ctx, Repainter repainter) {
           // Do nothing.
         }
+
+        @Override
+        protected void postMainUiRender(RenderContext ctx) {
+          // Do nothing.
+        }
       };
     }
 
diff --git a/gapic/src/main/com/google/gapid/widgets/Theme.java b/gapic/src/main/com/google/gapid/widgets/Theme.java
index 86777699a4..7c2e647258 100644
--- a/gapic/src/main/com/google/gapid/widgets/Theme.java
+++ b/gapic/src/main/com/google/gapid/widgets/Theme.java
@@ -74,6 +74,11 @@ public interface Theme {
   @Icon(file = "expand_less.png") public Image expandLess();
   @Icon(file = "expand_more.png") public Image expandMore();
   @Icon(file = "faceted.png") public Image faceted();
+  @Icon(file = "flag.png") public Image flagLight();
+  @Icon(file = "flag_filled.png") public Image flagFilledLight();
+  @Icon(file = "flag_white.png") public Image flagDark();
+  @Icon(file = "flag_white_filled.png") public Image flagFilledDark();
+  @Icon(file = "flag_greyed.png") public Image flagGreyed();
   @Icon(file = "flat.png") public Image flat();
   @Icon(file = "flip_vertically.png") public Image flipVertically();
   @Icon(file = "fullscreen.png") public Image fullscreen();

From 6526c857a239da586bf99a516004895624d0abd0 Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Tue, 25 Feb 2020 11:33:57 -0800
Subject: [PATCH 0097/1218] Fix ordering of reported issues

Previously we were passing all the issues through a map and so losing
the order in which they were generated. This change still keeps the
grouping behavior, but emits the messages in the order of their first
occurrence.

Bug: b/150221484
---
 gapis/service/report.go | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/gapis/service/report.go b/gapis/service/report.go
index 614f88d691..faced24dcb 100644
--- a/gapis/service/report.go
+++ b/gapis/service/report.go
@@ -156,6 +156,8 @@ func (b *ReportBuilder) processMessage(msg *stringtable.Msg) (*MsgRef, error) {
 func (b *ReportBuilder) processGroups() error {
 	groupItems := map[string][]uint32{}
 	groups := map[string]*MsgRef{}
+	emitted := map[string]bool{}
+
 	for i, item := range b.report.Items {
 		ref := item.Message
 		key := ref.key()
@@ -166,11 +168,17 @@ func (b *ReportBuilder) processGroups() error {
 			groups[key] = ref
 		}
 	}
-	for key, items := range groupItems {
-		b.report.Groups = append(b.report.Groups, &ReportGroup{
-			Name:  groups[key],
-			Items: items,
-		})
+
+	for _, item := range b.report.Items {
+		key := item.Message.key()
+		if _, ok := emitted[key]; !ok {
+			emitted[key] = true
+			b.report.Groups = append(b.report.Groups, &ReportGroup{
+				Name:  groups[key],
+				Items: groupItems[key],
+			})
+		}
 	}
+
 	return nil
 }

From c816be5b932c05f063f1b8cfe84052a4f433d79b Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Wed, 26 Feb 2020 08:58:25 -0800
Subject: [PATCH 0098/1218] Fix mishandling of imageview part of sampler
 descriptor update struct

Sampler updates use the same update structure as image descriptors, but
the VkImageView / VkImageLayout parts of the structure are allowed to be
left as uninitialized junk.

* Do not try to validate whether the imageview part of a sampler
  descriptor is valid, since that will cause us to drop the update
  on the floor completely in state reconstruction.

* Do not record the junk values into the state, for new traces.

Bug: b/150300807
---
 gapis/api/vulkan/api/descriptor.api           | 34 ++++++++++++++++---
 .../khr_descriptor_update_template.api        | 19 +++++++++--
 gapis/api/vulkan/state_rebuilder.go           | 28 +++++++++++++--
 3 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/gapis/api/vulkan/api/descriptor.api b/gapis/api/vulkan/api/descriptor.api
index 5ebfedecd5..46a77941e1 100644
--- a/gapis/api/vulkan/api/descriptor.api
+++ b/gapis/api/vulkan/api/descriptor.api
@@ -371,8 +371,22 @@ sub map!(u32, DescriptorSetWrite) RewriteWriteDescriptorSets
       }
 
       switch (write.descriptorType) {
-        case VK_DESCRIPTOR_TYPE_SAMPLER,
-            VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+        case VK_DESCRIPTOR_TYPE_SAMPLER: {
+          imageInfos := write.pImageInfo[0:updating.UpdateIndex + 1]
+          imageInfo := imageInfos[updating.UpdateIndex]
+          ret_val.Map[len(ret_val.Map)] = DescriptorSetWrite(
+            Binding:            updating.Binding,
+            BindingArrayIndex:  updating.ArrayIndex,
+            DstSet:             write.dstSet,
+            Type:               write.descriptorType,
+            ImageInfo:          new!VkDescriptorImageInfo(
+              Sampler:      imageInfo.Sampler,
+              ImageView:    0,
+              ImageLayout:  as!VkImageLayout(0)
+            )
+          )
+        }
+        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
@@ -654,8 +668,20 @@ cmd void vkUpdateDescriptorSets(
       vkErrorInvalidDescriptorCopy(c.SrcSet, c.SrcBinding, c.DstSet, c.DstBinding)
     } else {
       switch (srcBinding.BindingType) {
-        case VK_DESCRIPTOR_TYPE_SAMPLER,
-            VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+        case VK_DESCRIPTOR_TYPE_SAMPLER: {
+          imageBinding := dstBinding.ImageBinding
+          imageBinding[c.DstArrayIndex] = srcBinding.ImageBinding[c.SrcArrayIndex]
+          dstBinding.ImageBinding = imageBinding
+
+          vkSam := srcBinding.ImageBinding[c.SrcArrayIndex].Sampler
+          if vkSam in Samplers {
+            samObj := Samplers[vkSam]
+            if samObj != null {
+              registerDescriptorUser!SamplerObject(samObj, c.DstSet, c.DstBinding, c.DstArrayIndex)
+            }
+          }
+        }
+        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
             VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
             VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
             VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
diff --git a/gapis/api/vulkan/extensions/khr_descriptor_update_template.api b/gapis/api/vulkan/extensions/khr_descriptor_update_template.api
index b863b88059..5464e532e0 100644
--- a/gapis/api/vulkan/extensions/khr_descriptor_update_template.api
+++ b/gapis/api/vulkan/extensions/khr_descriptor_update_template.api
@@ -168,8 +168,23 @@ sub void updateDescriptorSetWithTemplate(
                     new!DescriptorBinding(BindingType: set.Layout.Bindings[entry.dstBinding].Type)
                 }
                 switch(entry.descriptorType) {
-                    case VK_DESCRIPTOR_TYPE_SAMPLER,
-                        VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+                    case VK_DESCRIPTOR_TYPE_SAMPLER: {
+                        inf := as!VkDescriptorImageInfo[](dat[entry.offset:entry.offset + as!size(24)])[0]
+                        imageBinding := setBinding.ImageBinding
+                        imageBinding[entry.dstArrayElement] = new!VkDescriptorImageInfo(
+                            Sampler: inf.Sampler,
+                            ImageView: 0,
+                            ImageLayout: as!VkImageLayout(0)
+                        )
+                        setBinding.ImageBinding = imageBinding
+                        if inf.Sampler in Samplers {
+                          samObj := Samplers[inf.Sampler]
+                          if samObj != null {
+                            registerDescriptorUser!SamplerObject(samObj, descriptorSet, entry.dstBinding, entry.dstArrayElement)
+                          }
+                        }
+                    }
+                    case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
                         VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
                         VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
                         VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
diff --git a/gapis/api/vulkan/state_rebuilder.go b/gapis/api/vulkan/state_rebuilder.go
index 4530ce39a8..fa5332cbb5 100644
--- a/gapis/api/vulkan/state_rebuilder.go
+++ b/gapis/api/vulkan/state_rebuilder.go
@@ -2757,8 +2757,32 @@ func (sb *stateBuilder) writeDescriptorSet(ds DescriptorSetObjectʳ) {
 	for _, k := range ds.Bindings().Keys() {
 		binding := ds.Bindings().Get(k)
 		switch binding.BindingType() {
-		case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER,
-			VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+		case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER:
+			numImages := uint32(binding.ImageBinding().Len())
+			for i := uint32(0); i < numImages; i++ {
+				im := binding.ImageBinding().Get(i)
+				if im.Sampler() == 0 {
+					continue
+				}
+
+				if im.Sampler() != 0 && !ns.Samplers().Contains(im.Sampler()) {
+					continue
+				}
+
+				writes = append(writes, NewVkWriteDescriptorSet(sb.ta,
+					VkStructureType_VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+					0,                     // pNext
+					ds.VulkanHandle(),     // dstSet
+					k,                     // dstBinding
+					i,                     // dstArrayElement
+					1,                     // descriptorCount
+					binding.BindingType(), // descriptorType
+					NewVkDescriptorImageInfoᶜᵖ(sb.MustAllocReadData(im.Get()).Ptr()), // pImageInfo
+					0, // pBufferInfo
+					0, // pTexelBufferView
+				))
+			}
+		case VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
 			VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
 			VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
 			VkDescriptorType_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:

From 68b8cf08310d3a8c532b32d479d65cd2a95aa4d2 Mon Sep 17 00:00:00 2001
From: hliatis <47799839+hliatis@users.noreply.github.com>
Date: Wed, 26 Feb 2020 16:51:41 -0800
Subject: [PATCH 0099/1218] Enum tooltip takes precedence over activation
 tooltip (#85)

---
 .../com/google/gapid/views/PipelineView.java     | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java
index 03f3651f4e..3fe81942db 100644
--- a/gapic/src/main/com/google/gapid/views/PipelineView.java
+++ b/gapic/src/main/com/google/gapid/views/PipelineView.java
@@ -390,11 +390,11 @@ private Composite createStage(Composite parent, API.Stage currentStage) {
               Label valueLabel = withLayoutData( createLabel(valueComposite, dv.displayValue),
                   new GridData(SWT.LEFT, SWT.CENTER, true, true));
 
-              if (kvp.getActive()) {
-                valueLabel.setToolTipText(kvp.getDependee().equals("") ? dv.tooltipValue : "Activated by " + kvp.getDependee());
+              if (dv.tooltipValue == null && !kvp.getDependee().equals("")) {
+                valueLabel.setToolTipText((kvp.getActive() ?  "Activated by " : "Deactivated by ") + kvp.getDependee());
+                valueLabel.setEnabled(kvp.getActive());
               } else {
-                valueComposite.setToolTipText("Deactivated by " + kvp.getDependee());
-                valueLabel.setEnabled(false);
+                valueLabel.setToolTipText(dv.tooltipValue);
               }
             }
           }
@@ -475,12 +475,8 @@ public void update(ViewerCell cell) {
               public String getToolTipText(Object element) {
                 DataValue dv = convertDataValue(((API.Row)element).getRowValues(col));
                 if (dv != null) {
-                  if (!dataTable.getDependee().equals("")) {
-                    if (dataTable.getActive()) {
-                        return (dv.tooltipValue != null ? dv.tooltipValue : "Activated by " + dataTable.getDependee());
-                    } else {
-                      return "Deactivated by " + dataTable.getDependee();
-                    }
+                  if (dv.tooltipValue == null && !dataTable.getDependee().equals("")) {
+                    return ((dataTable.getActive() ? "Activated by "  : "Deactivated by ") + dataTable.getDependee());   
                   } else {
                     return dv.tooltipValue;
                   }

From 191f7e1ffad1301aefcb4b4f353e33255570c0ac Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Thu, 27 Feb 2020 11:01:28 +0000
Subject: [PATCH 0100/1218] Fix the infinite wait if profile request fails
 (#90)

---
 gapis/api/vulkan/wait_for_perfetto.go | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/gapis/api/vulkan/wait_for_perfetto.go b/gapis/api/vulkan/wait_for_perfetto.go
index f30eb9e488..f8f075ab83 100644
--- a/gapis/api/vulkan/wait_for_perfetto.go
+++ b/gapis/api/vulkan/wait_for_perfetto.go
@@ -20,6 +20,8 @@ import (
 	"bytes"
 	"context"
 
+	"github.com/google/gapid/core/event/task"
+	"github.com/google/gapid/core/log"
 	"github.com/google/gapid/gapir"
 	"github.com/google/gapid/gapis/api"
 	"github.com/google/gapid/gapis/api/transform"
@@ -75,13 +77,26 @@ func (t *WaitForPerfetto) BuffersCommands() bool                              {
 
 func NewWaitForPerfetto(traceOptions *service.TraceOptions, h *replay.SignalHandler, buffer *bytes.Buffer) *WaitForPerfetto {
 	tcb := func(ctx context.Context, p *gapir.FenceReadyRequest) {
+		errChannel := make(chan error)
 		go func() {
-			trace.TraceBuffered(ctx, traceOptions.Device, h.StartSignal, h.StopSignal, h.ReadyFunc, traceOptions, buffer)
+			err := trace.TraceBuffered(ctx, traceOptions.Device, h.StartSignal, h.StopSignal, h.ReadyFunc, traceOptions, buffer)
+			if err != nil {
+				errChannel <- err
+			}
 			if !h.DoneSignal.Fired() {
 				h.DoneFunc(ctx)
 			}
 		}()
-		h.ReadySignal.Wait(ctx)
+
+		select {
+		case err := <-errChannel:
+			log.W(ctx, "Profiling error: %v", err)
+			return
+		case <-task.ShouldStop(ctx):
+			return
+		case <-h.ReadySignal:
+			return
+		}
 	}
 
 	fcb := func(ctx context.Context, p *gapir.FenceReadyRequest) {

From 7dd2e0763dae8e3c89cb5134a48ce6096a35fb34 Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Thu, 27 Feb 2020 09:49:40 -0800
Subject: [PATCH 0101/1218] Fix wrong counter selection count in config window.
 (#91)

- Bug: http://b/150290967.
---
 .../com/google/gapid/perfetto/views/TraceConfigDialog.java    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
index caa608185c..1ba0c7b04e 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
@@ -486,7 +486,9 @@ public BasicInputArea(Composite parent, Settings settings, Theme theme,
           gpuCountersRate = createSpinner(counterGroup, sGpu.getCounterRate(), 1, 1000);
           gpuCountersLabels[2] = createLabel(counterGroup, "ms");
 
-          gpuCountersLabels[0] = createLabel(counterGroup, sGpu.getCounterIdsCount() + " selected");
+          long count = caps.getGpuProfiling().getGpuCounterDescriptor().getSpecsList().stream()
+              .filter(c -> sGpu.getCounterIdsList().contains(c.getCounterId())).count();
+          gpuCountersLabels[0] = createLabel(counterGroup, count + " selected");
           gpuCountersSelect = Widgets.createButton(counterGroup, "Select", e -> {
             List currentIds = settings.perfetto().getGpuOrBuilder().getCounterIdsList();
             GpuCountersDialog dialog = new GpuCountersDialog(getShell(), theme, caps, currentIds);

From 96d0de8d0afa00e8dc910be6f7cf98473536ecd0 Mon Sep 17 00:00:00 2001
From: rschiu 
Date: Thu, 27 Feb 2020 16:01:15 -0800
Subject: [PATCH 0102/1218] Temporarily disable vulkan memory layer for android
 (#94)

The layer is causing issues and not well tested.
Temporily disabling it until the issues are resolved.

Bug: 150371900
---
 core/os/device/deviceinfo/cc/android/query.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp
index 2d694816e7..e944958221 100644
--- a/core/os/device/deviceinfo/cc/android/query.cpp
+++ b/core/os/device/deviceinfo/cc/android/query.cpp
@@ -519,7 +519,7 @@ void glDriverPlatform(device::OpenGLDriver* driver) {
 device::VulkanProfilingLayers* get_vulkan_profiling_layers() {
   auto layers = new device::VulkanProfilingLayers();
   layers->set_cpu_timing(true);
-  layers->set_memory_tracker(true);
+  layers->set_memory_tracker(false);
   return layers;
 }
 

From d0d1b0ca4b929c24d234f3dbc4e3ee0d98c0d9f8 Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Thu, 27 Feb 2020 16:49:37 -0800
Subject: [PATCH 0103/1218] Add option to right truncate the track name (#89)

Add option to right truncate the track name
---
 .../gapid/perfetto/canvas/RenderContext.java  | 39 +++++++++++++++++++
 .../perfetto/models/BatterySummaryTrack.java  |  2 +-
 .../perfetto/models/MemorySummaryTrack.java   |  2 +-
 .../google/gapid/perfetto/models/Tracks.java  | 23 ++++++-----
 .../gapid/perfetto/views/TrackContainer.java  | 24 ++++++------
 5 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/canvas/RenderContext.java b/gapic/src/main/com/google/gapid/perfetto/canvas/RenderContext.java
index 55e5c178b1..112892cd10 100644
--- a/gapic/src/main/com/google/gapid/perfetto/canvas/RenderContext.java
+++ b/gapic/src/main/com/google/gapid/perfetto/canvas/RenderContext.java
@@ -284,6 +284,45 @@ public void drawTextLeftTruncate(
     }
   }
 
+  // draws text centered vertically, right truncated to fit into the given width.
+  public void drawTextRightTruncate(
+      Fonts.Style style, String text, double x, double y, double w, double h) {
+    drawTextRightTruncate(style, text, x, y, w, h, false);
+  }
+
+  // draws text centered horizontally and vertically, right truncated to fit into the given width.
+  public void drawTextCenteredRightTruncate(
+      Fonts.Style style, String text, double x, double y, double w, double h) {
+    drawTextRightTruncate(style, text, x, y, w, h, true);
+  }
+
+  private void drawTextRightTruncate(
+      Fonts.Style style, String text, double x, double y, double w, double h, boolean centered) {
+    String toDisplay = text;
+    for (int l = text.length(); ; ) {
+      Size size = fontContext.measure(style, toDisplay);
+      if (size.w < w) {
+        drawText(style, toDisplay, x + (centered ? (w - size.w) / 2 : 0), y + (h - size.h) / 2);
+        break;
+      }
+
+      l = Math.min(l - textSizeGreediness, (int)(w / (size.w / toDisplay.length())));
+      if (l <= 0) {
+        break;
+      }
+      toDisplay = text.substring(0, l) + "...";
+    }
+  }
+
+  public void drawTextTruncate(
+      Fonts.Style style, String text, double x, double y, double w, double h, boolean rightTruncate) {
+    if (rightTruncate) {
+      drawTextRightTruncate(style, text, x, y, w, h);
+    } else {
+      drawTextLeftTruncate(style, text, x, y, w, h);
+    }
+  }
+
   // draws the text centered vertically and on the left of x.
   public void drawTextRightJustified(Fonts.Style style, String text, double x, double y, double h) {
     Size size = fontContext.measure(style, text);
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
index 393df41333..1ad44cf322 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
@@ -135,7 +135,7 @@ public static Perfetto.Data.Builder enumerate(Perfetto.Data.Builder data) {
 
     BatterySummaryTrack track = new BatterySummaryTrack(data.qe, battCap, battCharge, battCurrent);
     data.tracks.addTrack(null, track.getId(), "Battery Usage",
-        single(state -> new BatterySummaryPanel(state, track), true));
+        single(state -> new BatterySummaryPanel(state, track), true, false));
     return data;
   }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
index f2790554c7..dbcefdbf3f 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
@@ -146,7 +146,7 @@ public static Perfetto.Data.Builder enumerate(Perfetto.Data.Builder data) {
     MemorySummaryTrack track = new MemorySummaryTrack(
         data.qe, (long)total.max, total.id, free.id, buffers.id, cached.id, swapCached.id);
     data.tracks.addTrack(null, track.getId(), "Memory Usage",
-        single(state -> new MemorySummaryPanel(state, track), true));
+        single(state -> new MemorySummaryPanel(state, track), true, false));
     return data;
   }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java
index f27314c303..2b485afdb0 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java
@@ -80,11 +80,11 @@ private static Perfetto.Data.Builder enumerateCpu(Perfetto.Data.Builder data) {
     for (CpuInfo.Cpu cpu : data.getCpu().cpus()) {
       CpuTrack track = new CpuTrack(data.qe, cpu);
       data.tracks.addTrack(summary.getId(), track.getId(), "CPU " + cpu.id,
-          single(state -> new CpuPanel(state, track), false));
+          single(state -> new CpuPanel(state, track), false, false));
       if (cpu.hasFrequency()) {
         CpuFrequencyTrack freqTrack = new CpuFrequencyTrack(data.qe, cpu);
         data.tracks.addTrack(summary.getId(), freqTrack.getId(), "CPU " + cpu.id + " Frequency",
-            single(state -> new CpuFrequencyPanel(state, freqTrack), false));
+            single(state -> new CpuFrequencyPanel(state, freqTrack), false, false));
         hasAnyFrequency = true;
       }
     }
@@ -131,7 +131,7 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) {
       for (GpuInfo.Queue queue : data.getGpu().queues()) {
         SliceTrack track = SliceTrack.forGpuQueue(data.qe, queue);
         data.tracks.addTrack(parent, track.getId(), queue.getDisplay(),
-            single(state -> new GpuQueuePanel(state, queue, track), true));
+            single(state -> new GpuQueuePanel(state, queue, track), true, false));
       }
     }
 
@@ -145,7 +145,7 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) {
       for (GpuInfo.VkApiEvent vkApiEvent : data.getGpu().vkApiEvents()) {
         VulkanEventTrack track = new VulkanEventTrack(data.qe, vkApiEvent);
         data.tracks.addTrack(parent, track.getId(), vkApiEvent.getDisplay(),
-            single(state -> new VulkanEventPanel(state, vkApiEvent, track), true));
+            single(state -> new VulkanEventPanel(state, vkApiEvent, track), true, false));
       }
     }
 
@@ -159,7 +159,7 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) {
       for (GpuInfo.Buffer buffer : data.getGpu().buffers()) {
         FrameEventsTrack track = FrameEventsTrack.forBuffer(data.qe, buffer);
         data.tracks.addTrack(parent, track.getId(), buffer.getDisplay(),
-            single(state -> new FrameEventsSummaryPanel(state, buffer, track), true));
+            single(state -> new FrameEventsSummaryPanel(state, buffer, track), true, false));
       }
     }
 
@@ -173,7 +173,8 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) {
       for (CounterInfo counter : counters) {
         CounterTrack track = new CounterTrack(data.qe, counter);
         data.tracks.addTrack(parent, track.getId(), counter.name,
-            single(state -> new CounterPanel(state, track, DEFAULT_COUNTER_TRACK_HEIGHT), true));
+            single(state -> new CounterPanel(state, track, DEFAULT_COUNTER_TRACK_HEIGHT), true,
+                /*right truncate*/ true));
       }
     }
     return data;
@@ -213,7 +214,7 @@ public static Perfetto.Data.Builder enumerateProcesses(Perfetto.Data.Builder dat
         for (CounterInfo counter : counters) {
           CounterTrack track = new CounterTrack(data.qe, counter);
           data.tracks.addTrack(groupId, track.getId(), counter.name,
-              single(state -> new VulkanCounterPanel(state, track), false));
+              single(state -> new VulkanCounterPanel(state, track), false, false));
         }
       }
 
@@ -232,7 +233,8 @@ public static Perfetto.Data.Builder enumerateProcesses(Perfetto.Data.Builder dat
         for (CounterInfo counter : counters) {
           CounterTrack track = new CounterTrack(data.qe, counter);
           data.tracks.addTrack(parentId, track.getId(), counter.name,
-              single(state -> new CounterPanel(state, track, PROCESS_COUNTER_TRACK_HIGHT), false));
+              single(state -> new CounterPanel(state, track, PROCESS_COUNTER_TRACK_HIGHT),false,
+                  false));
         }
       }
 
@@ -251,11 +253,12 @@ public static Perfetto.Data.Builder enumerateProcesses(Perfetto.Data.Builder dat
         boolean isIdleThread = hasIdleThreads && track.getThread().totalDur < idleCutoffThread;
         TrackConfig.Track.UiFactory ui;
         if (track.getThread().maxDepth == 0) {
-          ui = single(state -> new ThreadPanel(state, track, false), false);
+          ui = single(state -> new ThreadPanel(state, track, false), false, false);
         } else {
           boolean expanded = !isIdleProcess && !isIdleThread;
           ui = single(state ->
-            new ThreadPanel(state, track, expanded), false, ThreadPanel::setCollapsed, !expanded);
+            new ThreadPanel(state, track, expanded), false, ThreadPanel::setCollapsed, !expanded,
+            false);
         }
         String threadParent = isIdleThread ? summary.getId() + "_idle" : summary.getId();
         data.tracks.addTrack(threadParent, track.getId(), track.getThread().getDisplay(), ui);
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TrackContainer.java b/gapic/src/main/com/google/gapid/perfetto/views/TrackContainer.java
index d4f994530f..b97a772b61 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/TrackContainer.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/TrackContainer.java
@@ -53,19 +53,19 @@ private TrackContainer() {
   }
 
   public static > TrackConfig.Track.UiFactory single(
-      TrackConfig.Track.UiFactory track, boolean sep) {
-    return state -> new Single(state, track.createPanel(state), sep, null, true);
+      TrackConfig.Track.UiFactory track, boolean sep, boolean rightTruncate) {
+    return state -> new Single(state, track.createPanel(state), sep, null, true, rightTruncate);
   }
 
   public static > TrackConfig.Track.UiFactory single(
       TrackConfig.Track.UiFactory track, boolean sep, BiConsumer filter,
-      boolean initial) {
+      boolean initial, boolean rightTruncate) {
     return state -> {
       T panel = track.createPanel(state);
       if (initial) {
         filter.accept(panel, initial);
       }
-      return new Single(state, panel, sep, filter, initial);
+      return new Single(state, panel, sep, filter, initial, rightTruncate);
     };
   }
 
@@ -101,31 +101,33 @@ private static class Single> extends Panel.Base
     private final boolean sep;
     protected final BiConsumer filter;
     private final PinState pinState;
+    private final boolean rightTruncate; // False -> Left truncate, True -> Right truncate
 
     protected boolean filtered;
     protected boolean hovered = false;
 
     public Single(State.ForSystemTrace state, T track, boolean sep, BiConsumer filter,
-        boolean filtered) {
-      this(track ,sep, filter, filtered, new PinState(state));
+        boolean filtered, boolean rightTruncate) {
+      this(track ,sep, filter, filtered, new PinState(state), rightTruncate);
     }
 
     private Single(T track, boolean sep, BiConsumer filter,
-        boolean filtered, PinState pinState) {
+        boolean filtered, PinState pinState, boolean rightTruncate) {
       this.track = track;
       this.sep = sep;
       this.filter = filter;
       this.pinState = pinState;
       this.filtered = filtered;
+      this.rightTruncate = rightTruncate;
     }
 
     @Override
     public Single copy() {
-      return new Single(track.copy(), sep, filter, filtered, pinState);
+      return new Single(track.copy(), sep, filter, filtered, pinState, rightTruncate);
     }
 
     private Single copyWithSeparator() {
-      return new Single(track.copy(), true, filter, filtered, pinState);
+      return new Single(track.copy(), true, filter, filtered, pinState, rightTruncate);
     }
 
     @Override
@@ -143,9 +145,9 @@ public void setSize(double w, double h) {
     public void render(RenderContext ctx, Repainter repainter) {
       ctx.withClip(0, 0, LABEL_WIDTH, height, () -> {
         ctx.setForegroundColor(colors().textMain);
-        ctx.drawTextLeftTruncate(Fonts.Style.Normal, track.getTitle(), LABEL_OFFSET, 0,
+        ctx.drawTextTruncate(Fonts.Style.Normal, track.getTitle(), LABEL_OFFSET, 0,
             ((filter == null) ? LABEL_PIN_X  : LABEL_TOGGLE_X) - LABEL_MARGIN - LABEL_OFFSET,
-            TITLE_HEIGHT);
+            TITLE_HEIGHT, rightTruncate);
         if (filter != null) {
           ctx.drawIcon(filtered ? unfoldMore(ctx.theme) : unfoldLess(ctx.theme),
               LABEL_TOGGLE_X, 0, TITLE_HEIGHT);

From 5f1f13ad0acaed694cf69497e7ceea7c27671c46 Mon Sep 17 00:00:00 2001
From: Adam Bodnar 
Date: Fri, 28 Feb 2020 10:33:08 -0800
Subject: [PATCH 0104/1218] Fix bad indices for debug markers (#99)

---
 gapis/api/vulkan/vulkan.go | 23 ++---------------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go
index fbcc3e2cfe..71a512dca5 100644
--- a/gapis/api/vulkan/vulkan.go
+++ b/gapis/api/vulkan/vulkan.go
@@ -179,29 +179,10 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 	}
 
 	popMarker := func(ty MarkerType, id uint64, nCommands uint64) {
-		numMarkers := len(markerStack)
-		inStack := false
-		for i := numMarkers - 1; i >= 0 && len(markerStack) > 0; i-- {
+		if len(markerStack) > 0 {
 			marker := markerStack[len(markerStack)-1]
-			if marker.ty == ty {
-				inStack = true
-				break
-			}
-		}
-		if !inStack {
-			return
-		}
-
-		if id < nCommands-1 {
-			id++
-		}
-		for i := numMarkers - 1; i >= 0 && len(markerStack) > 0; i-- {
-			marker := markerStack[len(markerStack)-1]
-			d.SubCommandMarkerGroups.NewMarkerGroup(marker.parent, marker.name, marker.start, id)
+			d.SubCommandMarkerGroups.NewMarkerGroup(marker.parent, marker.name, marker.start, id+1)
 			markerStack = markerStack[0 : len(markerStack)-1]
-			if marker.ty != ty {
-				break
-			}
 		}
 	}
 	var walkCommandBuffer func(cb CommandBufferObjectʳ, idx api.SubCmdIdx) ([]sync.SubcommandReference, []api.SubCmdIdx)

From e764b535339077c23f39e045d8db31642626789e Mon Sep 17 00:00:00 2001
From: hliatis <47799839+hliatis@users.noreply.github.com>
Date: Fri, 28 Feb 2020 11:04:58 -0800
Subject: [PATCH 0105/1218] Have VK_WHOLE_SIZE show the actual size in PV
 tables of descriptors (#98)

---
 gapis/api/vulkan/resources.go | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go
index d3296ead1a..8d2c60cfac 100644
--- a/gapis/api/vulkan/resources.go
+++ b/gapis/api/vulkan/resources.go
@@ -1146,7 +1146,19 @@ func commonShaderDataGroups(ctx context.Context,
 							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
 							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
 							currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Offset()))
-							currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Range()))
+
+							if descInfo.Range() == ^VkDeviceSize(0) {
+								bufferObject, ok := GetState(s).Buffers().Lookup(descInfo.Buffer())
+
+								if ok {
+									currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", fmt.Sprintf("VK_WHOLE_SIZE(%d)", bufferObject.Info().Size())))
+								} else {
+									currentSetData = append(currentSetData, api.CreatePoDDataValue("VKDeviceSize", "VK_WHOLE_SIZE"))
+								}
+
+							} else {
+								currentSetData = append(currentSetData, api.CreatePoDDataValue("VkDeviceSize", descInfo.Range()))
+							}
 
 						}
 					}

From e9894e3998e5eebce9fae7f6c14d0bcb319e4706 Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Fri, 28 Feb 2020 11:17:14 -0800
Subject: [PATCH 0106/1218] Disable Frame lifecycle by default (#95)

Disable Frame lifecycle by default
---
 gapic/src/main/com/google/gapid/models/Settings.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gapic/src/main/com/google/gapid/models/Settings.java b/gapic/src/main/com/google/gapid/models/Settings.java
index 10c12f9fe6..7c41a52a01 100644
--- a/gapic/src/main/com/google/gapid/models/Settings.java
+++ b/gapic/src/main/com/google/gapid/models/Settings.java
@@ -96,7 +96,7 @@ public class Settings {
               .setSlices(true)
               .setCounters(true)
               .setCounterRate(1)
-              .setSurfaceFlinger(true))
+              .setSurfaceFlinger(false))
           .setMemory(SettingsProto.Perfetto.Memory.newBuilder()
               .setEnabled(true)
               .setRate(10))

From cf41f322ade2b8fa37cfacbbb906aa46ac61e0bc Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Fri, 28 Feb 2020 08:28:44 -0800
Subject: [PATCH 0107/1218] Disable alpha channel by default in ImagePanel

In real Vulkan workloads, particularly with swapchain images, there is
often an alpha channel present but ignored, and the app is not careful
about what it writes into the alpha channel as a result. AGI already had
some logic to try and detect when the alpha channel was "unused" based
on contents, but junk rendered into it defeats that heuristic.

Disabling the alpha is a better default.

Bug: b/150420088
---
 gapic/src/main/com/google/gapid/widgets/ImagePanel.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gapic/src/main/com/google/gapid/widgets/ImagePanel.java b/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
index 614159d319..58d1304c49 100644
--- a/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
+++ b/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
@@ -597,7 +597,7 @@ private static Image[] getImages(Image[] layers) {
   private static final class SceneData {
     public Image[] images = {};
     public MatD[] transforms = {};
-    public final boolean channels[] = { true, true, true, true };
+    public final boolean channels[] = { true, true, true, false };
     public Histogram histogram;
     public Range displayRange = Range.IDENTITY;
     public boolean histogramVisible;

From abb871965ca827b113ae45faed4fa11a1c65ffff Mon Sep 17 00:00:00 2001
From: rschiu 
Date: Fri, 28 Feb 2020 15:21:19 -0800
Subject: [PATCH 0108/1218] Change VK_EXT_debug_utils to instance extension.
 (#97)

Bug: 149437509
---
 .../vk_api_timing_layer/cc/timing_layer.tmpl  | 91 ++++++++++++++++---
 1 file changed, 79 insertions(+), 12 deletions(-)

diff --git a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl
index 3923c1bab4..31ebe0806c 100644
--- a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl
+++ b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl
@@ -93,7 +93,7 @@ static bool debug_marker_ext_supported = false;
 {{range $c := AllCommands $}}
 {{$ind := Title (Macro "InitialIndirection" $c)}}
 {{if and (not (GetAnnotation $c "pfn")) (not (GetAnnotation $c "synthetic"))}}
-{{if and (not (Macro "IS_DEBUG_UTILS_FUNCTIONS" $c)) (not (Macro "IS_DEBUG_MARKER_FUNCTIONS" $c)) (not (eq $c.Name "vkEnumerateDeviceExtensionProperties"))}}
+{{if and (not (Macro "IS_DEBUG_UTILS_FUNCTIONS" $c)) (not (Macro "IS_DEBUG_MARKER_FUNCTIONS" $c)) (not (eq $c.Name "vkEnumerateInstanceExtensionProperties")) (not (eq $c.Name "vkEnumerateDeviceExtensionProperties"))}}
 {{Template "BeginPlatformIfDef" $c}}
 {{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) {
     timer t("{{$ind}}", "{{$c.Name}}");
@@ -219,20 +219,87 @@ VkResult vkDebugMarkerSetObjectNameEXT(
     return debug_marker_ext_supported ? next(device, pNameInfo) : VK_SUCCESS;
 }
 
-static const uint32_t NUM_EXTENSIONS = 2;
-static const VkExtensionProperties new_device_extensions[] = {
+
+namespace {
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+const char* LAYER_NAME = "CPUTiming";
+const VkExtensionProperties INSTANCE_EXTENSIONS[] = {
     {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION},
+};
+const uint32_t NUM_INSTANCE_EXTENSIONS = ARRAY_SIZE(INSTANCE_EXTENSIONS);
+const VkExtensionProperties DEVICE_EXTENSIONS[] = {
     {VK_EXT_DEBUG_MARKER_EXTENSION_NAME, VK_EXT_DEBUG_MARKER_SPEC_VERSION},
 };
+const uint32_t NUM_DEVICE_EXTENSIONS = ARRAY_SIZE(DEVICE_EXTENSIONS);
+
+#undef ARRAY_SIZE
+
+/**
+ * Enumerate extension properties for a specific layer.
+ *
+ * This should expose only the new extensions added by the layer.
+ */
+VkResult enumerateExtensionPropertiesForLayer(
+        uint32_t* pPropertyCount,
+        VkExtensionProperties* pProperties,
+        uint32_t numExtensions,
+        const VkExtensionProperties extensions[]) {
+    if (pProperties == nullptr) {
+        *pPropertyCount = numExtensions;
+        return VK_SUCCESS;
+    }
+    uint32_t capacity = std::min(*pPropertyCount, numExtensions);
+    memcpy(pProperties, extensions, capacity * sizeof(VkExtensionProperties));
+    if (*pPropertyCount < numExtensions) {
+        return VK_INCOMPLETE;
+    } else {
+        *pPropertyCount = numExtensions;
+        return VK_SUCCESS;
+    }
+}
+} // end of anonymous namespace
 
 // This layer needs to add VK_EXT_debug_utils and VK_EXT_debug_marker as a supported extension.
-VkResult vkEnumerateDeviceExtensionProperties(PFN_vkEnumerateDeviceExtensionProperties next, VkPhysicalDevice physicalDevice, char const* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) {
 
+VkResult vkEnumerateInstanceExtensionProperties(
+        PFN_vkEnumerateInstanceExtensionProperties next,
+        char const* pLayerName,
+        uint32_t* pPropertyCount,
+        VkExtensionProperties* pProperties) {
+    timer t("", "vkEnumerateInstanceExtensionProperties");
+    if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) {
+        return enumerateExtensionPropertiesForLayer(
+                pPropertyCount,
+                pProperties,
+                NUM_INSTANCE_EXTENSIONS,
+                INSTANCE_EXTENSIONS);
+    }
+    return next(pLayerName, pPropertyCount, pProperties);
+}
+
+VkResult vkEnumerateDeviceExtensionProperties(
+        PFN_vkEnumerateDeviceExtensionProperties next,
+        VkPhysicalDevice physicalDevice,
+        char const* pLayerName,
+        uint32_t* pPropertyCount,
+        VkExtensionProperties* pProperties) {
     timer t("VkPhysicalDevice", "vkEnumerateDeviceExtensionProperties");
-    if (pProperties == NULL) {
+
+    if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) {
+        return enumerateExtensionPropertiesForLayer(
+                pPropertyCount,
+                pProperties,
+                NUM_DEVICE_EXTENSIONS,
+                DEVICE_EXTENSIONS);
+    }
+    // Manually append device extension.  This should not be necessary, but the Android vulkan
+    // loader does not expose extensions from implicit layer (b/143293104).
+    if (pProperties == nullptr) {
         VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties);
         if (res == VK_SUCCESS) {
-            (*pPropertyCount) += NUM_EXTENSIONS;
+            (*pPropertyCount) += NUM_DEVICE_EXTENSIONS;
         }
         return res;
     }
@@ -248,13 +315,13 @@ VkResult vkEnumerateDeviceExtensionProperties(PFN_vkEnumerateDeviceExtensionProp
                     debug_marker_ext_supported = true;
                 }
             }
-            // *pPropertyCount is expected to be requestedCount - NUM_EXTENSIONS.
-            *pPropertyCount = std::min(*pPropertyCount + NUM_EXTENSIONS, requestedCount);
-            uint32_t count = std::min(NUM_EXTENSIONS, *pPropertyCount);
+            // *pPropertyCount is expected to be requestedCount - NUM_DEVICE_EXTENSIONS.
+            *pPropertyCount = std::min(*pPropertyCount + NUM_DEVICE_EXTENSIONS, requestedCount);
+            uint32_t count = std::min(NUM_DEVICE_EXTENSIONS, *pPropertyCount);
             memcpy(
-                &pProperties[*pPropertyCount - count],
-                new_device_extensions,
-                count * sizeof(VkExtensionProperties));
+                    &pProperties[*pPropertyCount - count],
+                    DEVICE_EXTENSIONS,
+                    count * sizeof(VkExtensionProperties));
         }
         return res;
     }

From cdeca93262ae2d065ffea13d377d48a46fd3a66f Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Fri, 28 Feb 2020 14:48:30 -0800
Subject: [PATCH 0109/1218] Don't show imageview/layout values for sampler
 descriptors

Bug: b/150484970
---
 gapis/api/vulkan/resources.go | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go
index 8d2c60cfac..861841c8cb 100644
--- a/gapis/api/vulkan/resources.go
+++ b/gapis/api/vulkan/resources.go
@@ -1105,7 +1105,19 @@ func commonShaderDataGroups(ctx context.Context,
 						currentSetData = append(currentSetData, api.CreatePoDDataValue("", "!"))
 					} else {
 						switch bindingType {
-						case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER, VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLER:
+							descInfo := bindingInfo.ImageBinding().Get(i)
+
+							samplerHandle := descInfo.Sampler()
+							samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle)
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle)))
+
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
 							VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
 							VkDescriptorType_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
 							descInfo := bindingInfo.ImageBinding().Get(i)

From d04282707b35c9827e8770b5ed24f6184b72c7f5 Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Mon, 2 Mar 2020 15:59:04 -0800
Subject: [PATCH 0110/1218] Add selection behavior for CPU/Process Panel under
 time quantization. (#96)

 - When CPU Panel and Process Panel are under summary mode with time
quantization (showing graph rather than slices), allow selection behavior as well.
 - A very useful use case enabled by this PR would be 1.zooming out and
 have an overview, 2.select a peak point denoting high CPU utilization
 in graph, 3.click 'f'or 'm' to quickly zoom/mark.
 - Bug: http://b/147922469. #1.
---
 .../gapid/perfetto/models/CpuTrack.java       | 34 ++++++++++++--
 .../perfetto/models/ProcessSummaryTrack.java  | 36 +++++++++++++--
 .../google/gapid/perfetto/views/CpuPanel.java | 43 +++++++++++++++++-
 .../perfetto/views/ProcessSummaryPanel.java   | 45 ++++++++++++++++++-
 4 files changed, 146 insertions(+), 12 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
index 26f477a213..16bfe3b592 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
@@ -36,6 +36,7 @@
 import com.google.gapid.perfetto.views.CpuSlicesSelectionView;
 import com.google.gapid.perfetto.views.State;
 
+import java.util.Arrays;
 import org.eclipse.swt.widgets.Composite;
 
 import java.util.Collections;
@@ -49,7 +50,7 @@
  */
 public class CpuTrack extends Track.WithQueryEngine {
   private static final String SUMMARY_SQL =
-      "select quantum_ts, sum(dur)/cast(%d as float) " +
+      "select quantum_ts, group_concat(row_id) ids, sum(dur)/cast(%d as float) util " +
       "from %s where cpu = %d and utid != 0 " +
       "group by quantum_ts";
   private static final String SLICES_SQL =
@@ -61,6 +62,10 @@ public class CpuTrack extends Track.WithQueryEngine {
       "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
       "where cpu = %d and utid != 0 and ts < %d and ts_end >= %d";
+  private static final String SLICE_RANGE_FOR_IDS_SQL =
+      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "from sched left join thread using(utid) " +
+      "where cpu = %d and row_id in (%s)";
   private static final String SLICE_RANGE_FOR_THREAD_SQL =
       "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
@@ -96,8 +101,14 @@ protected ListenableFuture computeData(DataRequest req) {
 
   private ListenableFuture computeSummary(DataRequest req, Window w) {
     return transform(qe.query(summarySql(w.bucketSize)), result -> {
-      Data data = new Data(req, w.bucketSize, new double[w.getNumberOfBuckets()]);
-      result.forEachRow(($, r) -> data.utilizations[r.getInt(0)] = r.getDouble(1));
+      int len = w.getNumberOfBuckets();
+      String[] concatedIds = new String[len];
+      Arrays.fill(concatedIds, "");
+      Data data = new Data(req, w.bucketSize, concatedIds, new double[len]);
+      result.forEachRow(($, r) -> {
+        data.concatedIds[r.getInt(0)] = r.getString(1);
+        data.utilizations[r.getInt(0)] = r.getDouble(2);
+      });
       return data;
     });
   }
@@ -145,6 +156,14 @@ public ListenableFuture> getSlices(TimeSpan ts) {
     });
   }
 
+  public ListenableFuture> getSlices(String ids) {
+    return transform(qe.query(sliceRangeForIdsSql(cpu.id, ids)), result -> {
+      List slices = Lists.newArrayList();
+      result.forEachRow((i, r) -> slices.add(new Slice(r)));
+      return slices;
+    });
+  }
+
   public static ListenableFuture> getSlices(QueryEngine qe, long utid, TimeSpan ts) {
     return transform(qe.query(sliceRangeForThreadSql(utid, ts)), result -> {
       List slices = Lists.newArrayList();
@@ -157,6 +176,10 @@ private static String sliceRangeSql(int cpu, TimeSpan ts) {
     return format(SLICE_RANGE_SQL, cpu, ts.end, ts.start);
   }
 
+  private static String sliceRangeForIdsSql(int cpu, String ids) {
+    return format(SLICE_RANGE_FOR_IDS_SQL, cpu, ids);
+  }
+
   private static String sliceRangeForThreadSql(long utid, TimeSpan ts) {
     return format(SLICE_RANGE_FOR_THREAD_SQL, utid, ts.end, ts.start);
   }
@@ -165,6 +188,7 @@ public static class Data extends Track.Data {
     public final Kind kind;
     // Summary.
     public final long bucketSize;
+    public final String[] concatedIds;    // Concated ids for all cpu slices in a each time bucket.
     public final double[] utilizations;
     // Slice.
     public final long[] ids;
@@ -172,10 +196,11 @@ public static class Data extends Track.Data {
     public final long[] ends;
     public final long[] utids;
 
-    public Data(DataRequest request, long bucketSize, double[] utilizations) {
+    public Data(DataRequest request, long bucketSize, String[] concatedIds, double[] utilizations) {
       super(request);
       this.kind = Kind.summary;
       this.bucketSize = bucketSize;
+      this.concatedIds = concatedIds;
       this.utilizations = utilizations;
       this.ids = null;
       this.starts = null;
@@ -191,6 +216,7 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, long[]
       this.ends = ends;
       this.utids = utids;
       this.bucketSize = 0;
+      this.concatedIds = null;
       this.utilizations = null;
     }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
index 8c6d9b5218..877ed0a72c 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
@@ -25,8 +25,11 @@
 import static java.lang.String.format;
 import static java.util.stream.Collectors.joining;
 
+import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.gapid.perfetto.models.CpuTrack.Slice;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * {@link Track} containing CPU usage data of all threads in a process.
@@ -35,9 +38,13 @@ public class ProcessSummaryTrack extends Track.WithQueryEngine computeData(DataRequest req) {
 
   private ListenableFuture computeSummary(DataRequest req, Window w) {
     return transform(qe.query(summarySql(w.bucketSize)), result -> {
-      Data data = new Data(req, w.bucketSize, new double[w.getNumberOfBuckets()]);
-      result.forEachRow(($, r) -> data.utilizations[r.getInt(0)] = r.getDouble(1));
+      int len = w.getNumberOfBuckets();
+      String[] concatedIds = new String[len];
+      Arrays.fill(concatedIds, "");
+      Data data = new Data(req, w.bucketSize, concatedIds, new double[len]);
+      result.forEachRow(($, r) -> {
+        data.concatedIds[r.getInt(0)] = r.getString(1);
+        data.utilizations[r.getInt(0)] = r.getDouble(2);
+      });
       return data;
     });
   }
@@ -107,6 +120,18 @@ private String slicesSql() {
     return format(SLICES_SQL, tableName("span"));
   }
 
+  public ListenableFuture> getSlices(String ids) {
+    return transform(qe.query(sliceRangeForIdsSql(ids)), result -> {
+      List slices = Lists.newArrayList();
+      result.forEachRow((i, r) -> slices.add(new Slice(r)));
+      return slices;
+    });
+  }
+
+  private static String sliceRangeForIdsSql(String ids) {
+    return format(SLICE_RANGE_FOR_IDS_SQL, ids);
+  }
+
   public ListenableFuture getSlice(long id) {
     return CpuTrack.getSlice(qe, id);
   }
@@ -115,6 +140,7 @@ public static class Data extends Track.Data {
     public final Kind kind;
     // Summary.
     public final long bucketSize;
+    public final String[] concatedIds;    // Concated ids for all cpu slices in a each time bucket.
     public final double[] utilizations;
     // Slice.
     public final long[] ids;
@@ -123,10 +149,11 @@ public static class Data extends Track.Data {
     public final int[] cpus;
     public final long[] utids;
 
-    public Data(DataRequest request, long bucketSize, double[] utilizations) {
+    public Data(DataRequest request, long bucketSize, String[] concatedIds, double[] utilizations) {
       super(request);
       this.kind = Kind.summary;
       this.bucketSize = bucketSize;
+      this.concatedIds = concatedIds;
       this.utilizations = utilizations;
       this.ids = null;
       this.starts = null;
@@ -145,6 +172,7 @@ public Data(
       this.cpus = cpus;
       this.utids = utids;
       this.bucketSize = 0;
+      this.concatedIds = null;
       this.utilizations = null;
     }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java
index e5ff4030a6..949954c4cc 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java
@@ -97,6 +97,9 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double
   private void renderSummary(RenderContext ctx, CpuTrack.Data data, double w, double h) {
     long tStart = data.request.range.start;
     int start = Math.max(0, (int)((state.getVisibleTime().start - tStart) / data.bucketSize));
+    Selection selected = state.getSelection(Selection.Kind.Cpu);
+    List visibleSelected = Lists.newArrayList();
+
     gradient(track.getCpu().id).applyBase(ctx);
     ctx.path(path -> {
       path.moveTo(0, h);
@@ -107,12 +110,26 @@ private void renderSummary(RenderContext ctx, CpuTrack.Data data, double w, doub
         path.lineTo(x, y);
         path.lineTo(x, nextY);
         y = nextY;
+        for (String id : data.concatedIds[i].split(",")) {
+          if (!id.isEmpty() && selected.contains(Long.parseLong(id))) {
+            visibleSelected.add(i);
+            break;
+          }
+        }
       }
       path.lineTo(x, h);
       path.close();
       ctx.fillPath(path);
     });
 
+    // Draw Highlight line after the whole graph is rendered, so that the highlight is on the top.
+    ctx.setBackgroundColor(gradient(track.getCpu().id).highlight);
+    for (int index : visibleSelected) {
+      ctx.fillRect(state.timeToPx(tStart + index * data.bucketSize),
+          Math.round(h * (1 - data.utilizations[index])) - 1,
+          state.durationToDeltaPx(data.bucketSize), 3);
+    }
+
     if (hovered != null && hovered.bucket >= start) {
       double x = state.timeToPx(tStart + hovered.bucket * data.bucketSize + data.bucketSize / 2);
       if (x < w) {
@@ -197,7 +214,7 @@ public Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int mods
 
     switch (data.kind) {
       case slice: return sliceHover(data, m, x, mods);
-      case summary: return summaryHover(data, m, x);
+      case summary: return summaryHover(data, m, x, mods);
       default: return Hover.NONE;
     }
   }
@@ -251,7 +268,7 @@ public boolean click() {
     return Hover.NONE;
   }
 
-  private Hover summaryHover(CpuTrack.Data data, Fonts.TextMeasurer m, double x) {
+  private Hover summaryHover(CpuTrack.Data data, Fonts.TextMeasurer m, double x, int mods) {
     long time = state.pxToTime(x);
     int bucket = (int)((time - data.request.range.start) / data.bucketSize);
     if (bucket < 0 || bucket >= data.utilizations.length) {
@@ -267,6 +284,8 @@ private Hover summaryHover(CpuTrack.Data data, Fonts.TextMeasurer m, double x) {
         data.request.range.start + hovered.bucket * data.bucketSize + data.bucketSize / 2);
     double dx = HOVER_PADDING + hovered.size.w + HOVER_PADDING;
     double dy = height;
+    String ids = data.concatedIds[bucket];
+
     return new Hover() {
       @Override
       public Area getRedraw() {
@@ -277,6 +296,26 @@ public Area getRedraw() {
       public void stop() {
         hovered = null;
       }
+
+      @Override
+      public boolean click() {
+        if (ids.isEmpty()) {
+          return false;
+        }
+        if ((mods & SWT.MOD1) == SWT.MOD1) {
+          state.addSelection(Selection.Kind.Cpu, transform(track.getSlices(ids), r -> {
+            r.stream().forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+            return new CpuTrack.SlicesBuilder(r).build();
+          }));
+        } else {
+          state.clearSelectedThreads();
+          state.setSelection(Selection.Kind.Cpu, transform(track.getSlices(ids), r -> {
+            r.stream().forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+            return new CpuTrack.SlicesBuilder(r).build();
+          }));
+        }
+        return true;
+      }
     };
   }
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
index 095cc86d08..191ca67c60 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
@@ -19,7 +19,9 @@
 import static com.google.gapid.perfetto.views.Loading.drawLoading;
 import static com.google.gapid.perfetto.views.StyleConstants.TRACK_MARGIN;
 import static com.google.gapid.perfetto.views.StyleConstants.colors;
+import static com.google.gapid.perfetto.views.StyleConstants.gradient;
 import static com.google.gapid.perfetto.views.StyleConstants.mainGradient;
+import static com.google.gapid.util.MoreFutures.transform;
 
 import com.google.common.collect.Lists;
 import com.google.gapid.perfetto.TimeSpan;
@@ -28,6 +30,7 @@
 import com.google.gapid.perfetto.canvas.RenderContext;
 import com.google.gapid.perfetto.canvas.Size;
 import com.google.gapid.perfetto.models.CpuInfo;
+import com.google.gapid.perfetto.models.CpuTrack;
 import com.google.gapid.perfetto.models.ProcessSummaryTrack;
 import com.google.gapid.perfetto.models.Selection;
 import com.google.gapid.perfetto.models.ThreadInfo;
@@ -109,6 +112,8 @@ private void renderSummary(
     // TODO: dedupe with CpuRenderer
     long tStart = data.request.range.start;
     int start = Math.max(0, (int)((state.getVisibleTime().start - tStart) / data.bucketSize));
+    Selection selected = state.getSelection(Selection.Kind.Cpu);
+    List visibleSelected = Lists.newArrayList();
 
     mainGradient().applyBaseAndBorder(ctx);
     ctx.path(path -> {
@@ -120,6 +125,12 @@ private void renderSummary(
         path.lineTo(x, y);
         path.lineTo(x, nextY);
         y = nextY;
+        for (String id : data.concatedIds[i].split(",")) {
+          if (!id.isEmpty() && selected.contains(Long.parseLong(id))) {
+            visibleSelected.add(i);
+            break;
+          }
+        }
       }
       path.lineTo(x, h);
       path.close();
@@ -127,6 +138,14 @@ private void renderSummary(
       ctx.drawPath(path);
     });
 
+    // Draw Highlight line after the whole graph is rendered, so that the highlight is on the top.
+    ctx.setBackgroundColor(mainGradient().highlight);
+    for (int index : visibleSelected) {
+      ctx.fillRect(state.timeToPx(tStart + index * data.bucketSize),
+          Math.round(h * (1 - data.utilizations[index])) - 1,
+          state.durationToDeltaPx(data.bucketSize), 3);
+    }
+
     if (hovered != null && hovered.bucket >= start) {
       double x = state.timeToPx(tStart + hovered.bucket * data.bucketSize + data.bucketSize / 2);
       if (x < w) {
@@ -200,7 +219,7 @@ public Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int mods
 
     switch (data.kind) {
       case slice: return sliceHover(data, m, x, y, mods);
-      case summary: return summaryHover(data, m, x);
+      case summary: return summaryHover(data, m, x, mods);
       default: return Hover.NONE;
     }
   }
@@ -262,7 +281,7 @@ public boolean click() {
     return Hover.NONE;
   }
 
-  private Hover summaryHover(ProcessSummaryTrack.Data data, Fonts.TextMeasurer m, double x) {
+  private Hover summaryHover(ProcessSummaryTrack.Data data, Fonts.TextMeasurer m, double x, int mods) {
     long time = state.pxToTime(x);
     int bucket = (int)((time - data.request.range.start) / data.bucketSize);
     if (bucket < 0 || bucket >= data.utilizations.length) {
@@ -278,6 +297,8 @@ private Hover summaryHover(ProcessSummaryTrack.Data data, Fonts.TextMeasurer m,
         data.request.range.start + hovered.bucket * data.bucketSize + data.bucketSize / 2);
     double dx = HOVER_PADDING + hovered.size.w + HOVER_PADDING;
     double dy = height;
+    String ids = data.concatedIds[bucket];
+
     return new Hover() {
       @Override
       public Area getRedraw() {
@@ -288,6 +309,26 @@ public Area getRedraw() {
       public void stop() {
         hovered = null;
       }
+
+      @Override
+      public boolean click() {
+        if (ids.isEmpty()) {
+          return false;
+        }
+        if ((mods & SWT.MOD1) == SWT.MOD1) {
+          state.addSelection(Selection.Kind.Cpu, transform(track.getSlices(ids), r -> {
+            r.stream().forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+            return new CpuTrack.SlicesBuilder(r).build();
+          }));
+        } else {
+          state.clearSelectedThreads();
+          state.setSelection(Selection.Kind.Cpu, transform(track.getSlices(ids), r -> {
+            r.stream().forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+            return new CpuTrack.SlicesBuilder(r).build();
+          }));
+        }
+        return true;
+      }
     };
   }
 

From 4b817df40e280f582e7a119b8565b233e9b76257 Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Tue, 3 Mar 2020 15:41:32 +0000
Subject: [PATCH 0111/1218] Update Android symbols file names (#104)

---
 kokoro/linux/package.sh | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh
index d20e8c3c24..6228dce558 100755
--- a/kokoro/linux/package.sh
+++ b/kokoro/linux/package.sh
@@ -87,9 +87,10 @@ mv agi.deb agi-$VERSION-linux.deb
 echo "$(date): Done."
 
 # Copy the symbol file to the output.
+# Warning: the name MUST be gapir-$VERSION-... , as this format is expected in our release script.
 [ -f "$BIN/cmd/gapir/cc/gapir.sym" ] && cp "$BIN/cmd/gapir/cc/gapir.sym" gapir-$VERSION-linux.sym
-[ -f "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" arm64-v8a_gapir-$VERSION-linux.sym
-[ -f "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" armeabi-v7a_gapir-$VERSION-linux.sym
-[ -f "$BIN/gapidapk/android/apk/x86_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/x86_gapir.sym" x86_gapir-$VERSION-linux.sym
+[ -f "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/arm64-v8a_gapir.sym" gapir-$VERSION-android-arm64-v8a.sym
+[ -f "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/armeabi-v7a_gapir.sym" gapir-$VERSION-android-armeabi-v7a.sym
+[ -f "$BIN/gapidapk/android/apk/x86_gapir.sym" ] && cp "$BIN/gapidapk/android/apk/x86_gapir.sym" gapir-$VERSION-android-x86.sym
 
 popd

From ba0725d59de11f894081caa5be3a586cd2ce2b0a Mon Sep 17 00:00:00 2001
From: purvisa-at-google-com
 <51710753+purvisa-at-google-com@users.noreply.github.com>
Date: Thu, 20 Feb 2020 11:17:15 +0000
Subject: [PATCH 0112/1218] Make some debug checking compile out in release
 builds (#3779)

---
 gapis/api/templates/specific_gfx_api.cpp.tmpl | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/gapis/api/templates/specific_gfx_api.cpp.tmpl b/gapis/api/templates/specific_gfx_api.cpp.tmpl
index 28432a3673..75f5ec658b 100644
--- a/gapis/api/templates/specific_gfx_api.cpp.tmpl
+++ b/gapis/api/templates/specific_gfx_api.cpp.tmpl
@@ -145,7 +145,13 @@
         {{$args := (GetAnnotation $ "indirect").Arguments}}
         {{$elem := (index $.CallParameters 0).Name}}
         {{$func := Macro "CmdName" $}}
-        if ({{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}}) {
+        if (
+        #ifndef NDEBUG
+        {{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}}
+        #else
+        true
+        #endif
+        ) {
       {{else}}
         if (mFunctionStubs.{{$name}} != nullptr) {
       {{end}}

From 3b4ad1f1e9185822ad1264cfcbda73e625daa6a3 Mon Sep 17 00:00:00 2001
From: purvisa-at-google-com
 <51710753+purvisa-at-google-com@users.noreply.github.com>
Date: Thu, 20 Feb 2020 14:58:30 +0000
Subject: [PATCH 0113/1218] Add cached_unordered_map for replay look-ups
 (#3780)

---
 gapir/cc/cached_unordered_map.h             | 89 +++++++++++++++++++++
 gapir/cc/vulkan_gfx_api.inc                 |  8 +-
 gapis/api/templates/specific_gfx_api.h.tmpl |  3 +-
 3 files changed, 95 insertions(+), 5 deletions(-)
 create mode 100644 gapir/cc/cached_unordered_map.h

diff --git a/gapir/cc/cached_unordered_map.h b/gapir/cc/cached_unordered_map.h
new file mode 100644
index 0000000000..3a479f6e0c
--- /dev/null
+++ b/gapir/cc/cached_unordered_map.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This is a wrapper around std::unordered_map that provides a fast return for
+// repeated queries with the same key. Our code has many places that maps are
+// successively queried with the same key, or even where maps contain only a
+// single key/value pair. In these cases this map provides a significant speed
+// up.
+
+#ifndef GAPIR_CACHED_UNORDERED_MAP_H
+#define GAPIR_CACHED_UNORDERED_MAP_H
+
+namespace gapir {
+
+template 
+class cached_unordered_map {
+ public:
+  T2& operator[](const T1& key) {
+    if (mCachedValueInvalid == false && mLastKey == key) {
+      return mLastValue->second;
+    }
+
+    mCachedValueInvalid = false;
+    mLastKey = key;
+    mLastValue = mMap.find(key);
+
+    if (mLastValue == mMap.end()) {
+      mMap[key];
+      mLastValue = mMap.find(key);
+    }
+
+    return mLastValue->second;
+  }
+
+  size_t count(const T1& key) const { return mMap.count(key); }
+  size_t erase(const T1& key) {
+    mCachedValueInvalid = true;
+    return mMap.erase(key);
+  }
+
+  typename std::unordered_map::iterator erase(
+      const typename std::unordered_map::iterator& iter) {
+    mCachedValueInvalid = true;
+    return mMap.erase(iter);
+  }
+
+  typename std::unordered_map::iterator find(const T1& key) {
+    return mMap.find(key);
+  }
+  typename std::unordered_map::const_iterator find(
+      const T1& key) const {
+    return mMap.find(key);
+  }
+
+  typename std::unordered_map::const_iterator begin() const {
+    return mMap.begin();
+  }
+  typename std::unordered_map::iterator begin() { return mMap.begin(); }
+
+  typename std::unordered_map::const_iterator end() const {
+    return mMap.end();
+  }
+  typename std::unordered_map::iterator end() { return mMap.end(); }
+
+ private:
+  mutable bool mCachedValueInvalid = true;
+
+  mutable T1 mLastKey;
+  mutable typename std::unordered_map::iterator mLastValue;
+
+  std::unordered_map mMap;
+};
+
+}  // namespace gapir
+
+#endif
\ No newline at end of file
diff --git a/gapir/cc/vulkan_gfx_api.inc b/gapir/cc/vulkan_gfx_api.inc
index dddd49e877..26d4dc4300 100644
--- a/gapir/cc/vulkan_gfx_api.inc
+++ b/gapir/cc/vulkan_gfx_api.inc
@@ -21,10 +21,10 @@
 // class Vulkan : public Api {
 // public:
 
-typedef std::unordered_map VkPhysicalDeviceToVkInstance;
-typedef std::unordered_map VkDeviceToVkPhysicalDevice;
-typedef std::unordered_map VkQueueToVkDevice;
-typedef std::unordered_map VkCommandBufferToVkDevice;
+typedef gapir::cached_unordered_map VkPhysicalDeviceToVkInstance;
+typedef gapir::cached_unordered_map VkDeviceToVkPhysicalDevice;
+typedef gapir::cached_unordered_map VkQueueToVkDevice;
+typedef gapir::cached_unordered_map VkCommandBufferToVkDevice;
 typedef struct {
     VkPhysicalDeviceToVkInstance VkPhysicalDevicesToVkInstances;
     VkDeviceToVkPhysicalDevice VkDevicesToVkPhysicalDevices;
diff --git a/gapis/api/templates/specific_gfx_api.h.tmpl b/gapis/api/templates/specific_gfx_api.h.tmpl
index dbaa667a80..836dccdd22 100644
--- a/gapis/api/templates/specific_gfx_api.h.tmpl
+++ b/gapis/api/templates/specific_gfx_api.h.tmpl
@@ -34,6 +34,7 @@
 #define GAPIR_{{Upper (Global "API")}}_GFX_API_H
 ¶
 #include "gapir/cc/gfx_api.h"
+#include "gapir/cc/cached_unordered_map.h"
 ¶
 #include "core/cc/static_array.h"
 #include "core/cc/target.h"
@@ -98,7 +99,7 @@ class {{Title (Global "API")}} : public Api {
       {{end}}
     };
     {{if $table}}
-      std::unordered_map<{{$table}}, {{$table}}FunctionStubs> m{{$table}}FunctionStubs;
+      gapir::cached_unordered_map<{{$table}}, {{$table}}FunctionStubs> m{{$table}}FunctionStubs;
     {{else}}
       FunctionStubs mFunctionStubs;
     {{end}}¶

From e07408b447640cdfa85e39210784e59fbc3a89da Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Tue, 3 Mar 2020 09:17:54 -0800
Subject: [PATCH 0114/1218] Make channel selector button image consistent with
 initial state

---
 gapic/src/main/com/google/gapid/widgets/ImagePanel.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gapic/src/main/com/google/gapid/widgets/ImagePanel.java b/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
index 58d1304c49..35889bdfba 100644
--- a/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
+++ b/gapic/src/main/com/google/gapid/widgets/ImagePanel.java
@@ -388,7 +388,7 @@ public void createToolbar(ToolBar bar, Theme theme) {
           analyticsView, show ? ClientAction.ShowHistogram : ClientAction.HideHistogram);
       setShowHistogram(show);
     }, "Toggle histogram");
-    colorChanelsItem = createBaloonToolItem(bar, theme.colorChannels()[15], shell -> {
+    colorChanelsItem = createBaloonToolItem(bar, theme.colorChannels()[7], shell -> {
       analytics.postInteraction(analyticsView, ClientAction.ShowColorChannels);
       Composite c = createComposite(shell, new RowLayout(SWT.HORIZONTAL), SWT.BORDER);
       final ImageComponent i = imageComponent;

From fe9f9f385e96a75c1d413f4f7fef4f3861a6760f Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Tue, 3 Mar 2020 13:55:19 -0800
Subject: [PATCH 0115/1218] Add selection behavior to Memory Panel and Battery
 Panel. (#93)

 - Bug: http://b/147922469. #1.
---
 .../perfetto/models/BatterySummaryTrack.java  | 211 +++++++++++++++--
 .../perfetto/models/MemorySummaryTrack.java   | 214 ++++++++++++++++--
 .../gapid/perfetto/models/Selection.java      |   2 +
 .../perfetto/views/BatterySelectionView.java  |  54 +++++
 .../perfetto/views/BatterySummaryPanel.java   |  40 +++-
 .../perfetto/views/MemorySelectionView.java   |  56 +++++
 .../perfetto/views/MemorySummaryPanel.java    |  42 +++-
 7 files changed, 587 insertions(+), 32 deletions(-)
 create mode 100644 gapic/src/main/com/google/gapid/perfetto/views/BatterySelectionView.java
 create mode 100644 gapic/src/main/com/google/gapid/perfetto/views/MemorySelectionView.java

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
index 1ad44cf322..92c8a15d7b 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java
@@ -20,6 +20,7 @@
 import static com.google.gapid.perfetto.models.QueryEngine.createWindow;
 import static com.google.gapid.perfetto.models.QueryEngine.dropTable;
 import static com.google.gapid.perfetto.models.QueryEngine.dropView;
+import static com.google.gapid.perfetto.models.QueryEngine.expectOneRow;
 import static com.google.gapid.perfetto.views.TrackContainer.single;
 import static com.google.gapid.util.MoreFutures.transform;
 import static com.google.gapid.util.MoreFutures.transformAsync;
@@ -27,26 +28,43 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.gapid.models.Perfetto;
+import com.google.gapid.perfetto.TimeSpan;
+import com.google.gapid.perfetto.views.BatterySelectionView;
 import com.google.gapid.perfetto.views.BatterySummaryPanel;
+import com.google.gapid.perfetto.views.State;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.IntStream;
+import org.eclipse.swt.widgets.Composite;
 
 public class BatterySummaryTrack extends Track.WithQueryEngine{
   private static final String VIEW_SQL =
-      "select ts, lead(ts) over (order by ts) - ts dur, max(a) capacity, max(b) charge," +
+      "select min(id) id, ts, lead(ts) over (order by ts) - ts dur, max(a) capacity, max(b) charge," +
       "   max(c) current " +
-      "from (select ts," +
+      "from (select id, ts," +
       "  case when track_id = %d then cast(value as int) end a," +
       "  case when track_id = %d then cast(value as int) end b," +
       "  case when track_id = %d then cast(value as int) end c " +
       "  from counter where track_id in (%d, %d, %d))" +
       "group by ts";
   private static final String SUMMARY_SQL =
-      "select min(ts), max(ts + dur), cast(avg(capacity) as int), cast(avg(charge) as int)," +
-      "  cast(avg(current) as int) " +
-      "from %s group by quantum_ts";
+      "select id, min(start), max(end), cast(avg(capacity) as int), cast(avg(charge) as int), " +
+      "    cast(avg(current) as int) from ( " +
+      "  select min(id) id, min(ts) start, max(ts + dur) end, cast(avg(capacity) as int) capacity, " +
+      "      cast(avg(charge) as int) charge, cast(avg(current) as int) current " +
+      "  from %s group by quantum_ts)" +
+      "group by id";
   private static final String COUNTER_SQL =
-      "select ts, ts + dur, capacity, charge, current from %s";
+      "select id, ts, ts + dur, capacity, charge, current from %s";
+  private static final String VALUE_SQL =
+      "select id, ts, dur, capacity, charge, current from %s where id = %d";
+  private static final String RANGE_SQL =
+      "select id, ts, dur, capacity, charge, current from %s " +
+          "where ts + dur >= %d and ts <= %d order by ts";
 
   private final long capacityId;
   private final long chargeId;
@@ -100,15 +118,17 @@ private ListenableFuture computeData(DataRequest req, Window win) {
         return Data.empty(req);
       }
 
-      Data data = new Data(
-          req, new long[rows + 1], new long[rows + 1], new long[rows + 1], new long[rows + 1]);
+      Data data = new Data(req, new long[rows + 1], new long[rows + 1], new long[rows + 1],
+          new long[rows + 1], new long[rows + 1]);
       res.forEachRow((i, r) -> {
-        data.ts[i] = r.getLong(0);
-        data.capacity[i] = r.getLong(2);
-        data.charge[i] = r.getLong(3);
-        data.current[i] = r.getLong(4);
+        data.id[i] = r.getLong(0);
+        data.ts[i] = r.getLong(1);
+        data.capacity[i] = r.getLong(3);
+        data.charge[i] = r.getLong(4);
+        data.current[i] = r.getLong(5);
       });
-      data.ts[rows] = res.getLong(rows - 1, 1, 0);
+      data.id[rows] = data.id[rows - 1];
+      data.ts[rows] = res.getLong(rows - 1, 2, 0);
       data.capacity[rows] = data.capacity[rows - 1];
       data.charge[rows] = data.charge[rows - 1];
       data.current[rows] = data.current[rows - 1];
@@ -139,18 +159,60 @@ public static Perfetto.Data.Builder enumerate(Perfetto.Data.Builder data) {
     return data;
   }
 
+  public ListenableFuture getValue(long id) {
+    return transform(expectOneRow(qe.query(valueSql(id))), row -> {
+      Values v = new Values(new long[1], new long[1], new long[1], new long[1], new long[1],
+          Sets.newHashSet());
+      v.valueKeys.add(row.getLong(0));
+      v.ts[0] = row.getLong(1);
+      v.dur[0] = row.getLong(2);
+      v.capacity[0] = row.getLong(3);
+      v.charge[0] = row.getLong(4);
+      v.current[0] = row.getLong(5);
+      return v;
+    });
+  }
+
+  private String valueSql(long id) {
+    return format(VALUE_SQL, tableName("vals"), id);
+  }
+
+  public ListenableFuture getValues(TimeSpan ts) {
+    return transform(qe.query(rangeSql(ts)), res -> {
+      int rows = res.getNumRows();
+      Values v = new Values(new long[rows], new long[rows], new long[rows], new long[rows],
+          new long[rows], Sets.newHashSet());
+      res.forEachRow((i, r) -> {
+        v.valueKeys.add(r.getLong(0));
+        v.ts[i] = r.getLong(1);
+        v.dur[i] = r.getLong(2);
+        v.capacity[i] = r.getLong(3);
+        v.charge[i] = r.getLong(4);
+        v.current[i] = r.getLong(5);
+      });
+      return v;
+    });
+  }
+
+  private String rangeSql(TimeSpan ts) {
+    return format(RANGE_SQL, tableName("vals"), ts.start, ts.end);
+  }
+
   private static CounterInfo onlyOne(ImmutableList counters) {
     return (counters.size() != 1) ? null : counters.get(0);
   }
 
   public static class Data extends Track.Data {
+    public final long[] id;
     public final long[] ts;
     public final long[] capacity;
     public final long[] charge;
     public final long[] current;
 
-    public Data(DataRequest request, long[] ts, long[] capacity, long[] charge, long[] current) {
+    public Data(DataRequest request, long[] id, long[] ts, long[] capacity, long[] charge,
+        long[] current) {
       super(request);
+      this.id = id;
       this.ts = ts;
       this.capacity = capacity;
       this.charge = charge;
@@ -158,7 +220,126 @@ public Data(DataRequest request, long[] ts, long[] capacity, long[] charge, long
     }
 
     public static Data empty(DataRequest req) {
-      return new Data(req, new long[0], new long[0], new long[0], new long[0]);
+      return new Data(req, new long[0], new long[0], new long[0], new long[0], new long[0]);
+    }
+  }
+
+  public static class Values implements Selection, Selection.Builder {
+    public final long[] ts;
+    public final long[] dur;
+    public final long[] capacity;
+    public final long[] charge;
+    public final long[] current;
+    private final Set valueKeys;
+
+    public Values(long[] ts, long[] dur, long[] capacity, long[] charge, long[] current,
+        Set valueKeys) {
+      this.ts = ts;
+      this.dur = dur;
+      this.capacity = capacity;
+      this.charge = charge;
+      this.current = current;
+      this.valueKeys = valueKeys;
+    }
+
+    @Override
+    public String getTitle() {
+      return "Batteries";
+    }
+
+    @Override
+    public boolean contains(Long key) {
+      return valueKeys.contains(key);
+    }
+
+    @Override
+    public Composite buildUi(Composite parent, State state) {
+      return new BatterySelectionView(parent, state, this);
+    }
+
+    @Override
+    public Selection.Builder getBuilder() {
+      return this;
+    }
+
+    @Override
+    public void getRange(Consumer span) {
+      long min = Arrays.stream(ts).min().getAsLong();
+      long max = IntStream.range(0, ts.length).mapToLong(i -> ts[i] + dur[i]).max().getAsLong();
+      span.accept(new TimeSpan(min, max));
+    }
+
+    @Override
+    public Values combine(Values that) {
+      if (ts.length == 0) {
+        return that;
+      } else if (that.ts.length == 0) {
+        return this;
+      }
+
+      long[] newTs = new long[this.ts.length + that.ts.length];
+      long[] newDur = new long[this.ts.length + that.ts.length];
+      long[] newCapacity = new long[this.ts.length + that.ts.length];
+      long[] newCharge = new long[this.ts.length + that.ts.length];
+      long[] newCurrent = new long[this.ts.length + that.ts.length];
+
+      int ai = 0, bi = 0, ri = 0;
+      for (; ai < this.ts.length && bi < that.ts.length; ri++) {
+        long at = this.ts[ai], bt = that.ts[bi];
+        boolean selectThis = true;
+        if (at == bt) {
+          ai++;
+          bi++;
+        } else if (at < bt) {
+          ai++;
+        } else {
+          bi++;
+          selectThis = false;
+        }
+        if (selectThis) {
+          newTs[ri] = at;
+          newDur[ri] = this.dur[ai - 1];
+          newCapacity[ri] = this.capacity[ai - 1];
+          newCharge[ri] = this.charge[ai - 1];
+          newCurrent[ri] = this.current[ai - 1];
+        } else {
+          newTs[ri] = bt;
+          newDur[ri] = that.dur[bi - 1];
+          newCapacity[ri] = that.capacity[bi - 1];
+          newCharge[ri] = that.charge[bi - 1];
+          newCurrent[ri] = that.current[bi - 1];
+        }
+      }
+
+      // Copy the rest trailing parts from the unfinished arrays.
+      for (; ai < this.ts.length; ri++, ai++) {
+        newTs[ri] = this.ts[ai];
+        newDur[ri] = this.dur[ai];
+        newCapacity[ri] = this.capacity[ai];
+        newCharge[ri] = this.charge[ai];
+        newCurrent[ri] = this.current[ai];
+      }
+      for (; bi < that.ts.length; ri++, bi++) {
+        newTs[ri] = that.ts[bi];
+        newDur[ri] = that.dur[bi];
+        newCapacity[ri] = that.capacity[bi];
+        newCharge[ri] = that.charge[bi];
+        newCurrent[ri] = that.current[bi];
+      }
+
+      Set newValueKeys = Sets.newHashSet(this.valueKeys);
+      newValueKeys.addAll(that.valueKeys);
+
+      // Truncate.
+      int newL = ri;
+      return new Values(Arrays.copyOf(newTs, newL), Arrays.copyOf(newDur, newL),
+          Arrays.copyOf(newCapacity, newL), Arrays.copyOf(newCharge, newL),
+          Arrays.copyOf(newCurrent, newL), newValueKeys);
+    }
+
+    @Override
+    public Selection build() {
+      return this;
     }
   }
 }
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
index dbcefdbf3f..2496e98cd8 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java
@@ -20,6 +20,7 @@
 import static com.google.gapid.perfetto.models.QueryEngine.createWindow;
 import static com.google.gapid.perfetto.models.QueryEngine.dropTable;
 import static com.google.gapid.perfetto.models.QueryEngine.dropView;
+import static com.google.gapid.perfetto.models.QueryEngine.expectOneRow;
 import static com.google.gapid.perfetto.views.TrackContainer.single;
 import static com.google.gapid.util.MoreFutures.transform;
 import static com.google.gapid.util.MoreFutures.transformAsync;
@@ -27,18 +28,30 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.gapid.models.Perfetto;
+import com.google.gapid.perfetto.TimeSpan;
+import com.google.gapid.perfetto.views.MemorySelectionView;
 import com.google.gapid.perfetto.views.MemorySummaryPanel;
+import com.google.gapid.perfetto.views.State;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
 
 /**
  * {@link Track} containing the total system memory usage data.
  */
 public class MemorySummaryTrack extends Track.WithQueryEngine {
   private static final String VIEW_SQL =
-      "select ts, lead(ts) over (order by ts) - ts dur, max(a) total, max(b) unused," +
+      "select min(id) id, ts, lead(ts) over (order by ts) - ts dur, max(a) total, max(b) unused," +
       "   max(c) + max(d) + max(e) buffCache " +
-      "from (select ts," +
+      "from (select id, ts," +
       "  case when track_id = %d then cast(value as int) end a," +
       "  case when track_id = %d then cast(value as int) end b," +
       "  case when track_id = %d then cast(value as int) end c," +
@@ -47,11 +60,19 @@ public class MemorySummaryTrack extends Track.WithQueryEngine= %d and ts <= %d order by ts";
 
   private final long maxTotal;
   private final long totalId;
@@ -107,15 +128,17 @@ private ListenableFuture computeData(DataRequest req, Window win) {
         return Data.empty(req);
       }
 
-      Data data = new Data(
-          req, new long[rows + 1], new long[rows + 1], new long[rows + 1], new long[rows + 1]);
+      Data data = new Data(req, new long [rows + 1], new long[rows + 1], new long[rows + 1],
+          new long[rows + 1], new long[rows + 1]);
       res.forEachRow((i, r) -> {
-        data.ts[i] = r.getLong(0);
-        data.total[i] = r.getLong(2);
-        data.unused[i] = r.getLong(3);
-        data.buffCache[i] = r.getLong(4);
+        data.id[i] = r.getLong(0);
+        data.ts[i] = r.getLong(1);
+        data.total[i] = r.getLong(3);
+        data.unused[i] = r.getLong(4);
+        data.buffCache[i] = r.getLong(5);
       });
-      data.ts[rows] = res.getLong(rows - 1, 1, 0);
+      data.id[rows] = data.id[rows - 1];
+      data.ts[rows] = res.getLong(rows - 1, 2, 0);
       data.total[rows] = data.total[rows - 1];
       data.unused[rows] = data.unused[rows - 1];
       data.buffCache[rows] = data.buffCache[rows - 1];
@@ -150,18 +173,60 @@ public static Perfetto.Data.Builder enumerate(Perfetto.Data.Builder data) {
     return data;
   }
 
+  public ListenableFuture getValue(long id) {
+    return transform(expectOneRow(qe.query(valueSql(id))), row -> {
+      Values v = new Values(new long[1], new long[1], new long[1], new long[1], new long[1],
+          Sets.newHashSet());
+      v.valueKeys.add(row.getLong(0));
+      v.ts[0] = row.getLong(1);
+      v.dur[0] = row.getLong(2);
+      v.total[0] = row.getLong(3);
+      v.unused[0] = row.getLong(4);
+      v.buffCache[0] = row.getLong(5);
+      return v;
+    });
+  }
+
+  private String valueSql(long id) {
+    return format(VALUE_SQL, tableName("vals"), id);
+  }
+
+  public ListenableFuture getValues(TimeSpan ts) {
+    return transform(qe.query(rangeSql(ts)), res -> {
+      int rows = res.getNumRows();
+      Values v = new Values(new long[rows], new long[rows], new long[rows], new long[rows],
+          new long[rows], Sets.newHashSet());
+      res.forEachRow((i, r) -> {
+        v.valueKeys.add(r.getLong(0));
+        v.ts[i] = r.getLong(1);
+        v.dur[i] = r.getLong(2);
+        v.total[i] = r.getLong(3);
+        v.unused[i] = r.getLong(4);
+        v.buffCache[i] = r.getLong(5);
+      });
+      return v;
+    });
+  }
+
+  private String rangeSql(TimeSpan ts) {
+    return format(RANGE_SQL, tableName("vals"), ts.start, ts.end);
+  }
+
   private static CounterInfo onlyOne(ImmutableList counters) {
     return (counters.size() != 1) ? null : counters.get(0);
   }
 
   public static class Data extends Track.Data {
+    public final long[] id;
     public final long[] ts;
     public final long[] total;
     public final long[] unused;
     public final long[] buffCache;
 
-    public Data(DataRequest request, long[] ts, long[] total, long[] unusued, long[] buffCache) {
+    public Data(DataRequest request, long[] id, long[] ts, long[] total, long[] unusued,
+        long[] buffCache) {
       super(request);
+      this.id = id;
       this.ts = ts;
       this.total = total;
       this.unused = unusued;
@@ -169,7 +234,126 @@ public Data(DataRequest request, long[] ts, long[] total, long[] unusued, long[]
     }
 
     public static Data empty(DataRequest req) {
-      return new Data(req, new long[0], new long[0], new long[0], new long[0]);
+      return new Data(req, new long[0], new long[0], new long[0], new long[0], new long[0]);
+    }
+  }
+
+  public static class Values implements Selection, Selection.Builder {
+    public final long[] ts;
+    public final long[] dur;
+    public final long[] total;
+    public final long[] unused;
+    public final long[] buffCache;
+    private final Set valueKeys;
+
+    public Values(long[] ts, long[] dur, long[] total, long[] unused, long[] buffCache,
+        Set valueKeys) {
+      this.ts = ts;
+      this.dur = dur;
+      this.total = total;
+      this.unused = unused;
+      this.buffCache = buffCache;
+      this.valueKeys = valueKeys;
+    }
+
+    @Override
+    public String getTitle() {
+      return "Memories";
+    }
+
+    @Override
+    public boolean contains(Long key) {
+      return valueKeys.contains(key);
+    }
+
+    @Override
+    public Composite buildUi(Composite parent, State state) {
+      return new MemorySelectionView(parent, state, this);
+    }
+
+    @Override
+    public Selection.Builder getBuilder() {
+      return this;
+    }
+
+    @Override
+    public void getRange(Consumer span) {
+      long min = Arrays.stream(ts).min().getAsLong();
+      long max = IntStream.range(0, ts.length).mapToLong(i -> ts[i] + dur[i]).max().getAsLong();
+      span.accept(new TimeSpan(min, max));
+    }
+
+    @Override
+    public Values combine(Values that) {
+      if (ts.length == 0) {
+        return that;
+      } else if (that.ts.length == 0) {
+        return this;
+      }
+
+      long[] newTs = new long[this.ts.length + that.ts.length];
+      long[] newDur = new long[this.ts.length + that.ts.length];
+      long[] newTotal = new long[this.ts.length + that.ts.length];
+      long[] newUnused = new long[this.ts.length + that.ts.length];
+      long[] newBuffCache = new long[this.ts.length + that.ts.length];
+
+      int ai = 0, bi = 0, ri = 0;
+      for (; ai < this.ts.length && bi < that.ts.length; ri++) {
+        long at = this.ts[ai], bt = that.ts[bi];
+        boolean selectThis = true;
+        if (at == bt) {
+          ai++;
+          bi++;
+        } else if (at < bt) {
+          ai++;
+        } else {
+          bi++;
+          selectThis = false;
+        }
+        if (selectThis) {
+          newTs[ri] = at;
+          newDur[ri] = this.dur[ai - 1];
+          newTotal[ri] = this.total[ai - 1];
+          newUnused[ri] = this.unused[ai - 1];
+          newBuffCache[ri] = this.buffCache[ai - 1];
+        } else {
+          newTs[ri] = bt;
+          newDur[ri] = that.dur[bi - 1];
+          newTotal[ri] = that.total[bi - 1];
+          newUnused[ri] = that.unused[bi - 1];
+          newBuffCache[ri] = that.buffCache[bi - 1];
+        }
+      }
+
+      // Copy the rest trailing parts from the unfinished arrays.
+      for (; ai < this.ts.length; ri++, ai++) {
+        newTs[ri] = this.ts[ai];
+        newDur[ri] = this.dur[ai];
+        newTotal[ri] = this.total[ai];
+        newUnused[ri] = this.unused[ai];
+        newBuffCache[ri] = this.buffCache[ai];
+      }
+      for (; bi < that.ts.length; ri++, bi++) {
+        newTs[ri] = that.ts[bi];
+        newDur[ri] = that.dur[bi];
+        newTotal[ri] = that.total[bi];
+        newUnused[ri] = that.unused[bi];
+        newBuffCache[ri] = that.buffCache[bi];
+      }
+
+      Set newValueKeys = Sets.newHashSet(this.valueKeys);
+      newValueKeys.addAll(that.valueKeys);
+
+      // Truncate.
+      int newL = ri;
+      return new Values(Arrays.copyOf(newTs, newL), Arrays.copyOf(newDur, newL),
+          Arrays.copyOf(newTotal, newL), Arrays.copyOf(newUnused, newL),
+          Arrays.copyOf(newBuffCache, newL), newValueKeys);
+    }
+
+    @Override
+    public Selection build() {
+      return this;
     }
   }
 }
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
index 73d453ab7b..c77701efbb 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java
@@ -209,6 +209,8 @@ public static class Kind implements Comparable>{
     public static final Kind VulkanEvent = new Kind(4);
     public static final Kind Counter = new Kind(5);
     public static final Kind FrameEvents = new Kind(6);
+    public static final Kind Memory = new Kind(7);
+    public static final Kind Battery = new Kind(8);
 
     public int priority;
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/BatterySelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/BatterySelectionView.java
new file mode 100644
index 0000000000..5719577f6d
--- /dev/null
+++ b/gapic/src/main/com/google/gapid/perfetto/views/BatterySelectionView.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.gapid.perfetto.views;
+
+import static com.google.gapid.perfetto.TimeSpan.timeToString;
+import static com.google.gapid.widgets.Widgets.createTableColumn;
+import static com.google.gapid.widgets.Widgets.createTableViewer;
+import static com.google.gapid.widgets.Widgets.packColumns;
+
+import com.google.gapid.perfetto.models.BatterySummaryTrack;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+
+public class BatterySelectionView extends Composite {
+  public BatterySelectionView(Composite parent, State state, BatterySummaryTrack.Values sel) {
+    super(parent, SWT.None);
+    setLayout(new FillLayout());
+
+    TableViewer viewer = createTableViewer(this, SWT.NONE);
+    viewer.setContentProvider(new ArrayContentProvider());
+    viewer.setLabelProvider(new LabelProvider());
+
+    createTableColumn(
+        viewer, "Time", r -> timeToString(sel.ts[(Integer)r] - state.getTraceTime().start));
+    createTableColumn(viewer, "Dur", r -> String.valueOf(sel.dur[(Integer)r]));
+    createTableColumn(viewer, "Capacity", r -> String.valueOf(sel.capacity[(Integer)r]));
+    createTableColumn(viewer, "Charge", r -> String.valueOf(sel.charge[(Integer)r]));
+    createTableColumn(viewer, "Current", r -> String.valueOf(sel.current[(Integer)r]));
+
+    Integer[] rows = new Integer[sel.ts.length];
+    for (int i = 0; i < rows.length; i++) {
+      rows[i] = i;
+    }
+    viewer.setInput(rows);
+    packColumns(viewer.getTable());
+  }
+}
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java
index cbcd3dc5ff..dbc58c7f69 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java
@@ -20,15 +20,23 @@
 import static com.google.gapid.perfetto.views.StyleConstants.batteryInGradient;
 import static com.google.gapid.perfetto.views.StyleConstants.batteryOutGradient;
 import static com.google.gapid.perfetto.views.StyleConstants.colors;
+import static com.google.gapid.util.MoreFutures.transform;
 
+import com.google.common.collect.Lists;
+import com.google.gapid.perfetto.TimeSpan;
 import com.google.gapid.perfetto.canvas.Area;
 import com.google.gapid.perfetto.canvas.Fonts;
 import com.google.gapid.perfetto.canvas.Fonts.TextMeasurer;
 import com.google.gapid.perfetto.canvas.RenderContext;
 import com.google.gapid.perfetto.canvas.Size;
 import com.google.gapid.perfetto.models.BatterySummaryTrack;
+import com.google.gapid.perfetto.models.Selection;
+import com.google.gapid.perfetto.models.Selection.CombiningBuilder;
+import com.google.gapid.perfetto.models.Selection.Kind;
+import java.util.List;
+import org.eclipse.swt.SWT;
 
-public class BatterySummaryPanel extends TrackPanel {
+public class BatterySummaryPanel extends TrackPanel implements Selectable {
   private static final double HEIGHT = 50;
   private static final double HOVER_MARGIN = 10;
   private static final double HOVER_PADDING = 4;
@@ -70,6 +78,8 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
       }
 
       double maxAbs = track.getMaxAbsCurrent();
+      Selection selected = state.getSelection(Selection.Kind.Battery);
+      List visibleSelected = Lists.newArrayList();
 
       // Draw outgoing battery current above the x axis.
       batteryOutGradient().applyBase(ctx);
@@ -83,6 +93,9 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
           path.lineTo(nextX, nextY);
           lastX = nextX;
           lastY = nextY;
+          if (selected.contains(data.id[i])) {
+            visibleSelected.add(i);
+          }
         }
         path.lineTo(lastX, h / 2);
         path.close();
@@ -107,6 +120,15 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
         ctx.fillPath(path);
       });
 
+      // Draw highlight line after the whole graph is rendered, so that the highlight is on the top.
+      for (int index : visibleSelected) {
+        double startX = state.timeToPx(data.ts[index]);
+        double endX = (index >= data.ts.length - 1) ? startX : state.timeToPx(data.ts[index + 1]);
+        ctx.setBackgroundColor(data.current[index] > 0 ?
+            batteryOutGradient().highlight : batteryInGradient().highlight);
+        ctx.fillRect(startX, h / 2 - h / 2 * data.current[index] / maxAbs - 1, endX - startX, 3);
+      }
+
       // Draw hovered card.
       if (hovered != null) {
         ctx.setBackgroundColor(colors().hoverBackground);
@@ -153,6 +175,7 @@ protected Hover onTrackMouseMove(TextMeasurer m, double x, double y, int mods) {
       }
     }
 
+    long id = data.id[idx];
     hovered = new HoverCard(m, data.capacity[idx], data.charge[idx], data.current[idx]);
     mouseXpos = x;
     mouseYpos = (height - 2 * TRACK_MARGIN - hovered.allSize.h) / 2;
@@ -168,9 +191,24 @@ public Area getRedraw() {
       public void stop() {
         hovered = null;
       }
+
+      @Override
+      public boolean click() {
+        if ((mods & SWT.MOD1) == SWT.MOD1) {
+          state.addSelection(Kind.Battery, track.getValue(id));
+        } else {
+          state.setSelection(Kind.Battery, track.getValue(id));
+        }
+        return true;
+      }
     };
   }
 
+  @Override
+  public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) {
+    builder.add(Selection.Kind.Battery, transform(track.getValues(ts), v -> v));
+  }
+
   private static class HoverCard {
     public static final String REMAINING_POWER_LABEL = "Capacity:";
     public static final String CURRENT_OUT_LABEL = "Current Out:";
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/MemorySelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/MemorySelectionView.java
new file mode 100644
index 0000000000..17fb57d591
--- /dev/null
+++ b/gapic/src/main/com/google/gapid/perfetto/views/MemorySelectionView.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.gapid.perfetto.views;
+
+import static com.google.gapid.perfetto.TimeSpan.timeToString;
+import static com.google.gapid.widgets.Widgets.createTableColumn;
+import static com.google.gapid.widgets.Widgets.createTableViewer;
+import static com.google.gapid.widgets.Widgets.createTreeColumn;
+import static com.google.gapid.widgets.Widgets.packColumns;
+
+import com.google.gapid.perfetto.models.MemorySummaryTrack;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+
+public class MemorySelectionView extends Composite {
+  public MemorySelectionView(Composite parent, State state, MemorySummaryTrack.Values sel) {
+    super(parent, SWT.None);
+    setLayout(new FillLayout());
+
+    TableViewer viewer = createTableViewer(this, SWT.NONE);
+    viewer.setContentProvider(new ArrayContentProvider());
+    viewer.setLabelProvider(new LabelProvider());
+
+    createTableColumn(
+        viewer, "Time", r -> timeToString(sel.ts[(Integer)r] - state.getTraceTime().start));
+    createTableColumn(viewer, "Dur", r -> String.valueOf(sel.dur[(Integer)r]));
+    createTableColumn(viewer, "Total", r -> String.valueOf(sel.total[(Integer)r]));
+    createTableColumn(viewer, "Unused", r -> String.valueOf(sel.unused[(Integer)r]));
+    createTableColumn(viewer, "BuffCache", r -> String.valueOf(sel.buffCache[(Integer)r]));
+
+
+    Integer[] rows = new Integer[sel.ts.length];
+    for (int i = 0; i < rows.length; i++) {
+      rows[i] = i;
+    }
+    viewer.setInput(rows);
+    packColumns(viewer.getTable());
+  }
+}
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java
index 8047d17559..0a0d46159d 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java
@@ -20,17 +20,25 @@
 import static com.google.gapid.perfetto.views.StyleConstants.colors;
 import static com.google.gapid.perfetto.views.StyleConstants.memoryBuffersGradient;
 import static com.google.gapid.perfetto.views.StyleConstants.memoryUsedGradient;
+import static com.google.gapid.util.MoreFutures.transform;
 
+import com.google.common.collect.Lists;
+import com.google.gapid.perfetto.TimeSpan;
 import com.google.gapid.perfetto.canvas.Area;
 import com.google.gapid.perfetto.canvas.Fonts;
 import com.google.gapid.perfetto.canvas.RenderContext;
 import com.google.gapid.perfetto.canvas.Size;
 import com.google.gapid.perfetto.models.MemorySummaryTrack;
+import com.google.gapid.perfetto.models.Selection;
+import com.google.gapid.perfetto.models.Selection.CombiningBuilder;
+import com.google.gapid.perfetto.models.Selection.Kind;
+import java.util.List;
+import org.eclipse.swt.SWT;
 
 /**
  * Displays information about the system memory usage.
  */
-public class MemorySummaryPanel extends TrackPanel {
+public class MemorySummaryPanel extends TrackPanel implements Selectable {
   private static final double HEIGHT = 80;
   private static final double HOVER_MARGIN = 10;
   private static final double HOVER_PADDING = 4;
@@ -72,6 +80,9 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
         return;
       }
 
+      Selection selected = state.getSelection(Selection.Kind.Memory);
+      List visibleSelected = Lists.newArrayList();
+
       memoryBuffersGradient().applyBase(ctx);
       ctx.path(path -> {
         path.moveTo(0, h);
@@ -83,6 +94,9 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
           path.lineTo(nextX, nextY);
           lastX = nextX;
           lastY = nextY;
+          if (selected.contains(data.id[i])) {
+            visibleSelected.add(i);
+          }
         }
         path.lineTo(lastX, h);
         path.close();
@@ -113,6 +127,16 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou
       ctx.setForegroundColor(colors().textMain);
       ctx.drawText(Fonts.Style.Normal, label, 4, 4);
 
+      // Draw highlight line after the whole graph is rendered, so that the highlight is on the top.
+      for (int index : visibleSelected) {
+        double startX = state.timeToPx(data.ts[index]);
+        double endX = (index >= data.ts.length - 1) ? startX : state.timeToPx(data.ts[index + 1]);
+        ctx.setBackgroundColor(memoryBuffersGradient().highlight);
+        ctx.fillRect(startX, h * data.unused[index] / data.total[index] - 1, endX - startX, 3);
+        ctx.setBackgroundColor(memoryUsedGradient().highlight);
+        ctx.fillRect(startX, h * (data.unused[index] + data.buffCache[index]) / data.total[index] - 1, endX - startX, 3);
+      }
+
       if (hovered != null) {
         ctx.setBackgroundColor(colors().hoverBackground);
         ctx.fillRect(mouseXpos + HOVER_MARGIN, mouseYpos,
@@ -164,6 +188,7 @@ protected Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int m
       }
     }
 
+    long id = data.id[idx];
     hovered = new HoverCard(m, data.total[idx], data.unused[idx], data.buffCache[idx]);
     mouseXpos = x;
     mouseYpos = (height - 2 * TRACK_MARGIN - hovered.allSize.h) / 2;
@@ -179,6 +204,16 @@ public Area getRedraw() {
       public void stop() {
         hovered = null;
       }
+
+      @Override
+      public boolean click() {
+        if ((mods & SWT.MOD1) == SWT.MOD1) {
+          state.addSelection(Kind.Memory, track.getValue(id));
+        } else {
+          state.setSelection(Kind.Memory, track.getValue(id));
+        }
+        return true;
+      }
     };
   }
 
@@ -202,6 +237,11 @@ protected static String bytesToString(long val) {
     return String.format("%.1fTb", v);
   }
 
+  @Override
+  public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) {
+    builder.add(Selection.Kind.Memory, transform(track.getValues(ts), v -> v));
+  }
+
   private static class HoverCard {
     public static final String TOTAL_LABEL = "Total:";
     public static final String FREE_LABEL = "Unused:";

From 5a4a20935618ae10d7c70007771cb25b6ca43dc7 Mon Sep 17 00:00:00 2001
From: rschiu 
Date: Tue, 3 Mar 2020 16:39:51 -0800
Subject: [PATCH 0116/1218] Update perfetto to fix segmentation fault in trace
 processor (#102)

Bug: b/149739694
---
 .../gapid/perfetto/models/CpuSummaryTrack.java   |  2 +-
 .../google/gapid/perfetto/models/CpuTrack.java   | 16 ++++++++--------
 .../perfetto/models/ProcessSummaryTrack.java     |  8 ++++----
 .../gapid/perfetto/models/ThreadTrack.java       |  6 +++---
 tools/build/third_party/perfetto/BUILD.bazel     |  1 +
 tools/build/workspace.bzl                        |  4 ++--
 6 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CpuSummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CpuSummaryTrack.java
index a94ce3ab88..a93e2bd41e 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/CpuSummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/CpuSummaryTrack.java
@@ -36,7 +36,7 @@ public class CpuSummaryTrack extends Track.WithQueryEngine
       "select quantum_ts, sum(dur)/cast(%d * %d as float) " +
       "from %s where utid != 0 group by quantum_ts";
   private static final String SLICE_RANGE_SQL =
-      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
       "where utid != 0 and ts < %d and ts_end >= %d";
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
index 16bfe3b592..54a9a4ee80 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java
@@ -50,24 +50,24 @@
  */
 public class CpuTrack extends Track.WithQueryEngine {
   private static final String SUMMARY_SQL =
-      "select quantum_ts, group_concat(row_id) ids, sum(dur)/cast(%d as float) util " +
+      "select quantum_ts, group_concat(id) ids, sum(dur)/cast(%d as float) util " +
       "from %s where cpu = %d and utid != 0 " +
       "group by quantum_ts";
   private static final String SLICES_SQL =
-      "select ts, dur, utid, row_id from %s where cpu = %d and utid != 0";
+      "select ts, dur, utid, id from %s where cpu = %d and utid != 0";
   private static final String SLICE_SQL =
-      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
-      "from sched left join thread using(utid) where row_id = %d";
+      "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "from sched left join thread using(utid) where sched.id = %d";
   private static final String SLICE_RANGE_SQL =
-      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
       "where cpu = %d and utid != 0 and ts < %d and ts_end >= %d";
   private static final String SLICE_RANGE_FOR_IDS_SQL =
-      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
-      "where cpu = %d and row_id in (%s)";
+      "where cpu = %d and sched.id in (%s)";
   private static final String SLICE_RANGE_FOR_THREAD_SQL =
-      "select row_id, ts, dur, cpu, utid, upid, end_state, priority " +
+      "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
       "where utid = %d and ts < %d and ts_end >= %d";
 
diff --git a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
index 877ed0a72c..00f6a58360 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
@@ -38,13 +38,13 @@ public class ProcessSummaryTrack extends Track.WithQueryEngine {
   private static final String SCHED_VIEW =
-      "select ts, dur, end_state, row_id from sched where utid = %d";
+      "select ts, dur, end_state, id from sched where utid = %d";
   private static final String INSTANT_VIEW =
       "with" +
       "  events as (select ts from instants where name = 'sched_wakeup' and ref = %d)," +
@@ -68,11 +68,11 @@ public class ThreadTrack extends Track.WithQueryEngine {
       "  when end_state is not null then 'r'" +
       "  when lag(end_state) over ts_win is not null then lag(end_state) over ts_win" +
       "  else 'R'" +
-      "end as state, row_id " +
+      "end as state, id " +
       "from %s window ts_win as (order by ts)";
 
   private static final String SCHED_SQL =
-      "select ts, dur, state, row_id from %s where state != 'S' and state != 'x'";
+      "select ts, dur, state, id from %s where state != 'S' and state != 'x'";
   private static final String SCHED_RANGE_SQL =
       "select ts, dur, state from %s where ts < %d and ts + dur >= %d";
 
diff --git a/tools/build/third_party/perfetto/BUILD.bazel b/tools/build/third_party/perfetto/BUILD.bazel
index 02aa2f3bf0..b4365ca1ff 100644
--- a/tools/build/third_party/perfetto/BUILD.bazel
+++ b/tools/build/third_party/perfetto/BUILD.bazel
@@ -46,6 +46,7 @@ go_proto_library(
         "@perfetto//:protos_perfetto_config_profiling_protos",
         "@perfetto//:protos_perfetto_config_protos",
         "@perfetto//:protos_perfetto_config_sys_stats_protos",
+        "@perfetto//:protos_perfetto_config_track_event_protos",
     ],
     visibility = ["//visibility:public"],
     deps = [":common_go_proto"],
diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl
index 5e412ee726..f9e5e7baaa 100644
--- a/tools/build/workspace.bzl
+++ b/tools/build/workspace.bzl
@@ -165,8 +165,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}):
         name = "perfetto",
         locals = locals,
         remote = "https://android.googlesource.com/platform/external/perfetto",
-        commit = "15c8c3e5af6e843dfcaf036333b7ccdfbb1b725f",
-        shallow_since = "1580316486 +0000",
+        commit = "f447425f9f7f676bf22d3c5e4a78f30d43c92c95",
+        shallow_since = "1582916230 +0000",
     )
 
     maybe_repository(

From d5451055715c81272515ba8413d381c9f3cc889e Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Tue, 3 Mar 2020 10:33:20 -0800
Subject: [PATCH 0117/1218] Stop overriding GPU queue track names

Early versions of the profiling support provided 'ugly' track names, but
that has since been fixed. Just present the GPU queue names as provided
by the driver.

This fixes the 'GPU Queue ' quirk in the replay profiler,
and prepares us for more descriptive track names from other drivers.

Bug: b/150692802
---
 .../com/google/gapid/perfetto/models/GpuInfo.java  | 14 +++++++-------
 .../main/com/google/gapid/views/ProfileView.java   |  2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java b/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java
index 9e659bb1da..747fcb177d 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java
@@ -88,7 +88,7 @@ private static ListenableFuture info(QueryEngine qe) {
       res.forEachRow(($, r) -> {
         switch (r.getString(2)) {
           case "gpu_render_stage":
-            queues.add(new Queue(queues.size(), r));
+            queues.add(new Queue(r));
             break;
           case "vulkan_events":
             vkApiEvents.add(new VkApiEvent(r));
@@ -106,22 +106,22 @@ private static ListenableFuture info(QueryEngine qe) {
   }
 
   public static class Queue {
-    public final int id;
+    public final String name;
     public final long trackId;
     public final int maxDepth;
 
-    public Queue(int id, long trackId, int maxDepth) {
-      this.id = id;
+    public Queue(long trackId, String name, int maxDepth) {
       this.trackId = trackId;
+      this.name = name;
       this.maxDepth = maxDepth;
     }
 
-    public Queue(int id, QueryEngine.Row row) {
-      this(id, row.getLong(0), row.getInt(3));
+    public Queue(QueryEngine.Row row) {
+      this(row.getLong(0), row.getString(1), row.getInt(3));
     }
 
     public String getDisplay() {
-      return "GPU Queue " + id;
+      return name;
     }
   }
 
diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java
index d59ad4357c..d57a8cc427 100644
--- a/gapic/src/main/com/google/gapid/views/ProfileView.java
+++ b/gapic/src/main/com/google/gapid/views/ProfileView.java
@@ -162,7 +162,7 @@ public void update(Profile.Data data) {
           }
         }
         panels.add(new Container(new GpuQueuePanel(state,
-            new GpuInfo.Queue(track.getId(), track.getId(), maxDepth + 1),
+            new GpuInfo.Queue(track.getId(), track.getName(), maxDepth + 1),
             new GpuSliceTrack(track.getId(), matched))));
       }
 

From 85827988739e45949dbea478e2e0c63f882ae162 Mon Sep 17 00:00:00 2001
From: hliatis <47799839+hliatis@users.noreply.github.com>
Date: Wed, 4 Mar 2020 10:19:38 -0800
Subject: [PATCH 0118/1218] Descriptors without samplers shouldn't have handles
 to them (#108)

---
 gapis/api/vulkan/resources.go | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go
index 861841c8cb..29f963bd5b 100644
--- a/gapis/api/vulkan/resources.go
+++ b/gapis/api/vulkan/resources.go
@@ -1117,11 +1117,23 @@ func commonShaderDataGroups(ctx context.Context,
 							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
 							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
 
-						case VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-							VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VkDescriptorType_VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
 							VkDescriptorType_VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
 							descInfo := bindingInfo.ImageBinding().Get(i)
 
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+							viewHandle := descInfo.ImageView()
+							viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle)
+							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", viewPath, api.CreatePoDDataValue("VkImageView", viewHandle)))
+
+							currentSetData = append(currentSetData, api.CreateEnumDataValue("VkImageLayout", descInfo.ImageLayout()))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+							currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-"))
+
+						case VkDescriptorType_VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+							descInfo := bindingInfo.ImageBinding().Get(i)
+
 							samplerHandle := descInfo.Sampler()
 							samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle)
 							currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle)))

From f5eca681530a6a6ea02c71afdddffad42e568677 Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Wed, 4 Mar 2020 19:47:06 +0000
Subject: [PATCH 0119/1218] Fix render overdraw (#106)

* Revert "Remove the overdraw rendering mode as it's currently broken."

This reverts commit d2ba72a6b2f9f7048abd4144717ddb54e2d46705.

* Fix crash in overdraw caused by ordering of Post Execution commands.

b/147603666

* Add the missing NewVkCommandBufferInheritanceInfo memory read

b/147603666
---
 .../main/com/google/gapid/views/FramebufferView.java  | 11 ++++++++++-
 gapis/api/vulkan/command_buffer_rebuilder.go          |  1 +
 gapis/api/vulkan/overdraw.go                          |  4 ++--
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/views/FramebufferView.java b/gapic/src/main/com/google/gapid/views/FramebufferView.java
index c4e3df2a07..80c24c153a 100644
--- a/gapic/src/main/com/google/gapid/views/FramebufferView.java
+++ b/gapic/src/main/com/google/gapid/views/FramebufferView.java
@@ -78,6 +78,10 @@ public class FramebufferView extends Composite
       .setMaxHeight(MAX_SIZE).setMaxWidth(MAX_SIZE)
       .setDrawMode(Service.DrawMode.WIREFRAME_ALL)
       .build();
+  private static final Service.RenderSettings RENDER_OVERDRAW = Service.RenderSettings.newBuilder()
+      .setMaxHeight(MAX_SIZE).setMaxWidth(MAX_SIZE)
+      .setDrawMode(Service.DrawMode.OVERDRAW)
+      .build();
 
   private final Models models;
   private final SingleInFlight rpcController = new SingleInFlight();
@@ -156,7 +160,12 @@ private ToolBar createToolBar(Theme theme) {
           models.analytics.postInteraction(View.Framebuffer, ClientAction.Wireframe);
           renderSettings = RENDER_WIREFRAME;
           updateBuffer();
-        }, "Render wireframe geometry"));
+        }, "Render wireframe geometry"),
+        createToggleToolItem(bar, theme.overdraw(), e -> {
+          models.analytics.postInteraction(View.Framebuffer, ClientAction.Overdraw);
+          renderSettings = RENDER_OVERDRAW;
+          updateBuffer();
+        }, "Render overdraw"));
     createSeparator(bar);
     return bar;
   }
diff --git a/gapis/api/vulkan/command_buffer_rebuilder.go b/gapis/api/vulkan/command_buffer_rebuilder.go
index 9855cccc7a..51e03dbc06 100644
--- a/gapis/api/vulkan/command_buffer_rebuilder.go
+++ b/gapis/api/vulkan/command_buffer_rebuilder.go
@@ -129,6 +129,7 @@ func allocateNewCmdBufFromExistingOneAndBegin(
 		)
 		inheritanceInfoData := s.AllocDataOrPanic(ctx, inheritanceInfo)
 		cleanup = append(cleanup, func() { inheritanceInfoData.Free() })
+		mem = append(mem, inheritanceInfoData)
 		beginInfo.SetPInheritanceInfo(NewVkCommandBufferInheritanceInfoᶜᵖ(inheritanceInfoData.Ptr()))
 	}
 	beginInfoData := s.AllocDataOrPanic(ctx, beginInfo)
diff --git a/gapis/api/vulkan/overdraw.go b/gapis/api/vulkan/overdraw.go
index f487c2d054..730ff9312c 100644
--- a/gapis/api/vulkan/overdraw.go
+++ b/gapis/api/vulkan/overdraw.go
@@ -1638,7 +1638,6 @@ func (s *stencilOverdraw) renderAspect(ctx context.Context,
 	out transform.Writer,
 ) error {
 	sb := st.newStateBuilder(ctx, newTransformerOutput(out))
-	ip := newImagePrimer(sb)
 	queueHandler, err := newQueueCommandHandler(sb, queue, cmdBuffer)
 	if err != nil {
 		return log.Errf(sb.ctx, err, "failed at creating queue command handler")
@@ -1668,6 +1667,8 @@ func (s *stencilOverdraw) renderAspect(ctx context.Context,
 		framebufferWidth:      uint32(sizes.width),
 		framebufferHeight:     uint32(sizes.height),
 	}
+	ip := newImagePrimer(sb)
+	queueHandler.RecordPostExecuted(func() { ip.Free() })
 	renderKitBuilder := ip.GetRenderKitBuilder(device)
 	kits, err := renderKitBuilder.BuildRenderKits(sb, recipe)
 	if err != nil {
@@ -1731,7 +1732,6 @@ func (s *stencilOverdraw) renderAspect(ctx context.Context,
 	// Make sure it doesn't use temporary memory as that would cause a flush of the scratch resources
 	// queueScratch.memorySize = scratchTask.totalAllocationSize
 
-	queueHandler.RecordPostExecuted(func() { ip.Free() })
 	addCleanup(func() {
 		queueHandler.Submit(sb)
 		queueHandler.WaitUntilFinish(sb)

From 5509c31ec7036d65d161f334f62b6f63f0aa3c6a Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Wed, 4 Mar 2020 11:48:00 -0800
Subject: [PATCH 0120/1218] Enable compact sched events if available.

---
 .../com/google/gapid/perfetto/views/TraceConfigDialog.java    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
index 1ba0c7b04e..dcd9140325 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/TraceConfigDialog.java
@@ -224,7 +224,9 @@ public static PerfettoConfig.TraceConfig.Builder getConfig(
             .getFtraceConfigBuilder()
             .addAllFtraceEvents(Arrays.asList(PROCESS_TRACKING_FTRACE))
             .setDrainPeriodMs(FTRACE_DRAIN_PERIOD)
-            .setBufferSizeKb(FTRACE_BUFFER_SIZE);
+            .setBufferSizeKb(FTRACE_BUFFER_SIZE)
+            .setCompactSched(PerfettoConfig.FtraceConfig.CompactSchedConfig.newBuilder()
+                .setEnabled(true));
     // Record process names at startup into the metadata buffer.
     config.addDataSourcesBuilder()
         .getConfigBuilder()

From a7a32158cd43e702d8708cace313b615b3f7b473 Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Wed, 4 Mar 2020 11:50:35 -0800
Subject: [PATCH 0121/1218] Ignore the API patch level when comparing the API
 version.

Allows replaying on devices if the API version only differs in the patch
level. Any API change would require a minor/major version change, so
ignoring the patch level is fine.
---
 gapis/api/vulkan/replay.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go
index 52955b226f..7b72789d9b 100644
--- a/gapis/api/vulkan/replay.go
+++ b/gapis/api/vulkan/replay.go
@@ -86,7 +86,8 @@ func (a API) GetReplayPriority(ctx context.Context, i *device.Instance, h *captu
 				if devPhyInfo.GetDeviceId() != tracePhyInfo.GetDeviceId() {
 					continue
 				}
-				if devPhyInfo.GetApiVersion() != tracePhyInfo.GetApiVersion() {
+				// Ignore the API patch level (bottom 12 bits) when comparing the API version.
+				if (devPhyInfo.GetApiVersion() & ^uint32(0xfff)) != (tracePhyInfo.GetApiVersion() & ^uint32(0xfff)) {
 					continue
 				}
 				return 1

From 3095c02b9d34c9fc4680613b7d5b2225b4acc076 Mon Sep 17 00:00:00 2001
From: purvisa-at-google-com
 <51710753+purvisa-at-google-com@users.noreply.github.com>
Date: Thu, 5 Mar 2020 17:45:30 +0000
Subject: [PATCH 0122/1218] Revert "Make some debug checking compile out in
 release builds (#3779)" (#117)

This reverts commit ba0725d59de11f894081caa5be3a586cd2ce2b0a.
---
 gapis/api/templates/specific_gfx_api.cpp.tmpl | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/gapis/api/templates/specific_gfx_api.cpp.tmpl b/gapis/api/templates/specific_gfx_api.cpp.tmpl
index 75f5ec658b..28432a3673 100644
--- a/gapis/api/templates/specific_gfx_api.cpp.tmpl
+++ b/gapis/api/templates/specific_gfx_api.cpp.tmpl
@@ -145,13 +145,7 @@
         {{$args := (GetAnnotation $ "indirect").Arguments}}
         {{$elem := (index $.CallParameters 0).Name}}
         {{$func := Macro "CmdName" $}}
-        if (
-        #ifndef NDEBUG
-        {{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}}
-        #else
-        true
-        #endif
-        ) {
+        if ({{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}}) {
       {{else}}
         if (mFunctionStubs.{{$name}} != nullptr) {
       {{end}}

From 56393599a8a982dcfa7688fbc8542e992cef7f38 Mon Sep 17 00:00:00 2001
From: hliatis <47799839+hliatis@users.noreply.github.com>
Date: Thu, 5 Mar 2020 14:00:25 -0800
Subject: [PATCH 0123/1218] Don't look into Dynamic States in PV when
 LastBoundQueue is nil (#114)

---
 gapis/api/vulkan/resources.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go
index 29f963bd5b..f923256cf8 100644
--- a/gapis/api/vulkan/resources.go
+++ b/gapis/api/vulkan/resources.go
@@ -1004,6 +1004,9 @@ func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.Globa
 	var framebuffer FramebufferObjectʳ
 	var boundDsets map[uint32]DescriptorSetObjectʳ
 	var renderpass RenderPassObjectʳ
+	// Convert the DynamicStates map to have VkDynamicState be the key
+	// for quick lookup (i.e. make it a set)
+	dynamicStates := make(map[VkDynamicState]bool)
 	// Use LastDrawInfos to get bound descriptor set data.
 	// TODO: Ideally we could look at just a specific pipeline/descriptor
 	// set pair.  Maybe we could modify mutate to track which what
@@ -1019,14 +1022,11 @@ func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.Globa
 				boundDsets = ldi.DescriptorSets().All()
 			}
 		}
-	}
 
-	// Convert the DynamicStates map to have VkDynamicState be the key
-	// for quick lookup (i.e. make it a set)
-	dynamicStates := make(map[VkDynamicState]bool)
-	if !p.DynamicState().IsNil() {
-		for _, k := range p.DynamicState().DynamicStates().Keys() {
-			dynamicStates[p.DynamicState().DynamicStates().Get(k)] = true
+		if !p.DynamicState().IsNil() {
+			for _, k := range p.DynamicState().DynamicStates().Keys() {
+				dynamicStates[p.DynamicState().DynamicStates().Get(k)] = true
+			}
 		}
 	}
 

From 9d60a144cd39544ef6f0e6eb10e2cb14d9aed8fe Mon Sep 17 00:00:00 2001
From: Adam Bodnar 
Date: Thu, 5 Mar 2020 15:46:40 -0800
Subject: [PATCH 0124/1218] Generate links to renderpasses from gpu slices
 (#109)

---
 gapis/api/cmd_id.go                          |  5 +-
 gapis/api/sync/data.go                       | 10 +--
 gapis/api/vulkan/BUILD.bazel                 |  1 -
 gapis/api/vulkan/replay.go                   | 13 ++--
 gapis/api/vulkan/slice_command_mapper.go     | 71 --------------------
 gapis/api/vulkan/vulkan.go                   | 19 ++++--
 gapis/trace/BUILD.bazel                      |  2 +-
 gapis/trace/android/BUILD.bazel              |  2 +-
 gapis/trace/android/adreno/BUILD.bazel       |  1 +
 gapis/trace/android/adreno/profiling_data.go | 69 +++++++++++--------
 gapis/trace/android/trace.go                 |  6 +-
 gapis/trace/desktop/BUILD.bazel              |  2 +-
 gapis/trace/desktop/trace.go                 |  4 +-
 gapis/trace/trace.go                         |  6 +-
 gapis/trace/tracer/BUILD.bazel               |  2 +-
 gapis/trace/tracer/tracer.go                 |  4 +-
 16 files changed, 85 insertions(+), 132 deletions(-)
 delete mode 100644 gapis/api/vulkan/slice_command_mapper.go

diff --git a/gapis/api/cmd_id.go b/gapis/api/cmd_id.go
index 7be710eb8c..4e2ecb79b4 100644
--- a/gapis/api/cmd_id.go
+++ b/gapis/api/cmd_id.go
@@ -51,7 +51,4 @@ func (id CmdID) String() string {
 }
 
 // TODO(apbodnar) find a more appropriate place for this
-type CommandSubmissionKey struct {
-	SubmissionOrder uint64
-	CommandBuffer   int64
-}
+type CmdSubmissionKey [4]uint64
diff --git a/gapis/api/sync/data.go b/gapis/api/sync/data.go
index 881e776eaf..ffb867b11e 100644
--- a/gapis/api/sync/data.go
+++ b/gapis/api/sync/data.go
@@ -87,10 +87,11 @@ type Data struct {
 	SubCommandMarkerGroups *subCommandMarkerGroupTrie
 	// SyncDependencies contains the commands that must complete
 	// (according to their fences or semaphores) before they can be executed.
-	SyncDependencies map[SyncNodeIdx][]SyncNodeIdx
-	SyncNodes        []SyncNode
-	CmdSyncNodes     map[api.CmdID]SyncNodeIdx
-	SubcommandLookup *api.SubCmdIdxTrie
+	SyncDependencies  map[SyncNodeIdx][]SyncNodeIdx
+	SyncNodes         []SyncNode
+	CmdSyncNodes      map[api.CmdID]SyncNodeIdx
+	SubcommandLookup  *api.SubCmdIdxTrie
+	SubmissionIndices map[api.CmdSubmissionKey][]api.SubCmdIdx
 }
 
 type subCommandMarkerGroupTrie struct {
@@ -124,6 +125,7 @@ func NewData() *Data {
 		SyncNodes:              []SyncNode{},
 		CmdSyncNodes:           map[api.CmdID]SyncNodeIdx{},
 		SubcommandLookup:       new(api.SubCmdIdxTrie),
+		SubmissionIndices:      map[api.CmdSubmissionKey][]api.SubCmdIdx{},
 	}
 }
 
diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel
index 1636731e83..7417454e3c 100644
--- a/gapis/api/vulkan/BUILD.bazel
+++ b/gapis/api/vulkan/BUILD.bazel
@@ -88,7 +88,6 @@ go_library(
         "replay.go",
         "resources.go",
         "scratch_resources.go",
-        "slice_command_mapper.go",
         "state.go",
         "state_rebuilder.go",
         "vulkan.go",
diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go
index 7b72789d9b..fb33bd5350 100644
--- a/gapis/api/vulkan/replay.go
+++ b/gapis/api/vulkan/replay.go
@@ -29,6 +29,7 @@ import (
 	"github.com/google/gapid/gapis/config"
 	"github.com/google/gapid/gapis/memory"
 	"github.com/google/gapid/gapis/replay"
+	"github.com/google/gapid/gapis/resolve"
 	"github.com/google/gapid/gapis/resolve/dependencygraph2"
 	"github.com/google/gapid/gapis/resolve/initialcmds"
 	"github.com/google/gapid/gapis/service"
@@ -833,7 +834,6 @@ type profileRequest struct {
 	handler        *replay.SignalHandler
 	buffer         *bytes.Buffer
 	handleMappings *map[uint64][]service.VulkanHandleMappingItem
-	submissionIds  *map[api.CommandSubmissionKey][]uint64
 }
 
 func (a API) GetInitialPayload(ctx context.Context,
@@ -1049,7 +1049,6 @@ func (a API) Replay(
 			profile.AddResult(rr.Result)
 			makeReadable.imagesOnly = true
 			optimize = false
-			transforms.Add(newSliceCommandMapper(req.submissionIds))
 			transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer))
 			transforms.Add(&profilingLayers{})
 			transforms.Add(replay.NewMappingExporter(ctx, req.handleMappings))
@@ -1238,11 +1237,15 @@ func (a API) Profile(
 	handler := replay.NewSignalHandler()
 	var buffer bytes.Buffer
 	handleMappings := make(map[uint64][]service.VulkanHandleMappingItem)
-	submissionIds := make(map[api.CommandSubmissionKey][]uint64)
-	r := profileRequest{traceOptions, handler, &buffer, &handleMappings, &submissionIds}
+	r := profileRequest{traceOptions, handler, &buffer, &handleMappings}
 	_, err := mgr.Replay(ctx, intent, c, r, a, hints, true)
 	handler.DoneSignal.Wait(ctx)
 
-	d, err := trace.ProcessProfilingData(ctx, intent.Device, intent.Capture, &buffer, &handleMappings, &submissionIds)
+	s, err := resolve.SyncData(ctx, intent.Capture)
+	if err != nil {
+		return nil, err
+	}
+
+	d, err := trace.ProcessProfilingData(ctx, intent.Device, intent.Capture, &buffer, &handleMappings, s)
 	return d, err
 }
diff --git a/gapis/api/vulkan/slice_command_mapper.go b/gapis/api/vulkan/slice_command_mapper.go
deleted file mode 100644
index 0204191a5a..0000000000
--- a/gapis/api/vulkan/slice_command_mapper.go
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (C) 2020 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package vulkan
-
-import (
-	"context"
-
-	"github.com/google/gapid/core/log"
-	"github.com/google/gapid/gapis/api"
-	"github.com/google/gapid/gapis/api/transform"
-)
-
-type sliceCommandMapper struct {
-	subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64
-	submissionCount      uint64
-}
-
-func (t *sliceCommandMapper) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error {
-	ctx = log.Enter(ctx, "Slice Command Mapper")
-	s := out.State()
-
-	switch cmd := cmd.(type) {
-	case *VkQueueSubmit:
-		if id.IsReal() {
-			submitInfoCount := cmd.SubmitCount()
-			submitInfos := cmd.pSubmits.Slice(0, uint64(submitInfoCount), s.MemoryLayout).MustRead(ctx, cmd, s, nil)
-			for i := uint32(0); i < submitInfoCount; i++ {
-				si := submitInfos[i]
-				cmdBufferCount := si.CommandBufferCount()
-				cmdBuffers := si.PCommandBuffers().Slice(0, uint64(cmdBufferCount), s.MemoryLayout).MustRead(ctx, cmd, s, nil)
-				for j := uint32(0); j < cmdBufferCount; j++ {
-					commandIndex := []uint64{uint64(id), uint64(i), uint64(j), 0}
-					key := api.CommandSubmissionKey{SubmissionOrder: t.submissionCount, CommandBuffer: int64(cmdBuffers[j])}
-					(*t.subCommandIndicesMap)[key] = commandIndex
-				}
-			}
-			t.submissionCount++
-		}
-		return out.MutateAndWrite(ctx, id, cmd)
-	default:
-		return out.MutateAndWrite(ctx, id, cmd)
-	}
-	return nil
-}
-
-func (t *sliceCommandMapper) PreLoop(ctx context.Context, out transform.Writer) {
-	out.NotifyPreLoop(ctx)
-}
-func (t *sliceCommandMapper) PostLoop(ctx context.Context, out transform.Writer) {
-	out.NotifyPostLoop(ctx)
-}
-func (t *sliceCommandMapper) Flush(ctx context.Context, out transform.Writer) error { return nil }
-func (t *sliceCommandMapper) BuffersCommands() bool {
-	return false
-}
-
-func newSliceCommandMapper(subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64) *sliceCommandMapper {
-	return &sliceCommandMapper{subCommandIndicesMap: subCommandIndicesMap, submissionCount: 0}
-}
diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go
index 71a512dca5..2861267233 100644
--- a/gapis/api/vulkan/vulkan.go
+++ b/gapis/api/vulkan/vulkan.go
@@ -185,8 +185,8 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 			markerStack = markerStack[0 : len(markerStack)-1]
 		}
 	}
-	var walkCommandBuffer func(cb CommandBufferObjectʳ, idx api.SubCmdIdx) ([]sync.SubcommandReference, []api.SubCmdIdx)
-	walkCommandBuffer = func(cb CommandBufferObjectʳ, idx api.SubCmdIdx) ([]sync.SubcommandReference, []api.SubCmdIdx) {
+	var walkCommandBuffer func(cb CommandBufferObjectʳ, idx api.SubCmdIdx, id api.CmdID, order uint64) ([]sync.SubcommandReference, []api.SubCmdIdx)
+	walkCommandBuffer = func(cb CommandBufferObjectʳ, idx api.SubCmdIdx, id api.CmdID, order uint64) ([]sync.SubcommandReference, []api.SubCmdIdx) {
 		refs := make([]sync.SubcommandReference, 0)
 		subgroups := make([]api.SubCmdIdx, 0)
 		lastSubpass := 0
@@ -224,7 +224,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 					cbo := st.CommandBuffers().Get(args.CommandBuffers().Get(uint32(j)))
 					subIdx := append(api.SubCmdIdx{}, idx...)
 					subIdx = append(subIdx, uint64(i), j)
-					newRefs, newSubgroups := walkCommandBuffer(cbo, subIdx)
+					newRefs, newSubgroups := walkCommandBuffer(cbo, subIdx, id, order)
 					refs = append(refs, newRefs...)
 					subgroups = append(subgroups, newSubgroups...)
 					if cbo.CommandReferences().Len() > 0 {
@@ -233,6 +233,15 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 				}
 			case VkCmdBeginRenderPassArgsʳ:
 				rp := st.RenderPasses().Get(args.RenderPass())
+				if id.IsReal() {
+					key := api.CmdSubmissionKey{order, uint64(cb.VulkanHandle()), uint64(rp.VulkanHandle()), uint64(args.Framebuffer())}
+					if _, ok := d.SubmissionIndices[key]; ok {
+						d.SubmissionIndices[key] = append(d.SubmissionIndices[key], append(idx, uint64(i)))
+					} else {
+						d.SubmissionIndices[key] = []api.SubCmdIdx{append(idx, uint64(i))}
+					}
+				}
+
 				name := fmt.Sprintf("RenderPass: %v", rp.VulkanHandle())
 				if !rp.DebugInfo().IsNil() && len(rp.DebugInfo().ObjectName()) > 0 {
 					name = rp.DebugInfo().ObjectName()
@@ -309,6 +318,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 		return refs, subgroups
 	}
 
+	order := uint64(0)
 	err = api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error {
 		i = id
 		if err := cmd.Mutate(ctx, id, s, nil, nil); err != nil {
@@ -328,7 +338,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 					cmdBuff := st.CommandBuffers().Get(buff)
 					// If a submitted command-buffer is empty, we shouldn't show it
 					if cmdBuff.CommandReferences().Len() > 0 {
-						additionalRefs, additionalSubgroups := walkCommandBuffer(cmdBuff, api.SubCmdIdx{uint64(i), uint64(submitIdx), uint64(j)})
+						additionalRefs, additionalSubgroups := walkCommandBuffer(cmdBuff, api.SubCmdIdx{uint64(i), uint64(submitIdx), uint64(j)}, i, order)
 						for _, sg := range additionalSubgroups {
 							d.SubcommandGroups[i] = append(d.SubcommandGroups[i], sg[1:])
 						}
@@ -338,6 +348,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap
 					}
 				}
 			}
+			order++
 			d.SubcommandReferences[i] = refs
 		}
 		return nil
diff --git a/gapis/trace/BUILD.bazel b/gapis/trace/BUILD.bazel
index 35adb17332..119df88ea6 100644
--- a/gapis/trace/BUILD.bazel
+++ b/gapis/trace/BUILD.bazel
@@ -33,7 +33,7 @@ go_library(
         "//core/os/device:go_default_library",
         "//core/os/device/bind:go_default_library",
         "//gapii/client:go_default_library",
-        "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/config:go_default_library",
         "//gapis/service:go_default_library",
         "//gapis/service/path:go_default_library",
diff --git a/gapis/trace/android/BUILD.bazel b/gapis/trace/android/BUILD.bazel
index dce1c75b64..a8c2da4da9 100644
--- a/gapis/trace/android/BUILD.bazel
+++ b/gapis/trace/android/BUILD.bazel
@@ -33,7 +33,7 @@ go_library(
         "//gapidapk:go_default_library",
         "//gapidapk/pkginfo:go_default_library",
         "//gapii/client:go_default_library",
-        "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/perfetto:go_default_library",
         "//gapis/perfetto/android:go_default_library",
         "//gapis/service:go_default_library",
diff --git a/gapis/trace/android/adreno/BUILD.bazel b/gapis/trace/android/adreno/BUILD.bazel
index 0c2ae7a287..923da27f47 100644
--- a/gapis/trace/android/adreno/BUILD.bazel
+++ b/gapis/trace/android/adreno/BUILD.bazel
@@ -12,6 +12,7 @@ go_library(
         "//core/log:go_default_library",
         "//core/os/device:go_default_library",
         "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/perfetto:go_default_library",
         "//gapis/perfetto/service:go_default_library",
         "//gapis/service:go_default_library",
diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go
index d93d35f994..3e26d5de8a 100644
--- a/gapis/trace/android/adreno/profiling_data.go
+++ b/gapis/trace/android/adreno/profiling_data.go
@@ -21,6 +21,7 @@ import (
 	"github.com/google/gapid/core/log"
 	"github.com/google/gapid/core/os/device"
 	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
 	"github.com/google/gapid/gapis/perfetto"
 	perfetto_service "github.com/google/gapid/gapis/perfetto/service"
 	"github.com/google/gapid/gapis/service"
@@ -29,9 +30,9 @@ import (
 
 var (
 	slicesQuery = "" +
-		"SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " +
+		"SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " +
 		"FROM gpu_track t LEFT JOIN gpu_slice s " +
-		"ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage'"
+		"ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage' ORDER BY s.ts"
 	argsQueryFmt = "" +
 		"SELECT key, string_value FROM args WHERE args.arg_set_id = %d"
 	queueSubmitQuery = "" +
@@ -40,10 +41,11 @@ var (
 		"SELECT id, name, unit, description FROM gpu_counter_track ORDER BY id"
 	countersQueryFmt = "" +
 		"SELECT ts, value FROM counter c WHERE c.track_id = %d ORDER BY ts"
+	renderPassSliceName = "Surface"
 )
 
-func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) {
-	slices, err := processGpuSlices(ctx, processor, capture, handleMapping, submissionIds)
+func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error) {
+	slices, err := processGpuSlices(ctx, processor, capture, handleMapping, syncData)
 	if err != nil {
 		log.Err(ctx, err, "Failed to get GPU slices")
 	}
@@ -77,7 +79,7 @@ func extractTraceHandles(ctx context.Context, replayHandles *[]int64, replayHand
 	}
 }
 
-func processGpuSlices(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, subCommandIndicesMap *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData_GpuSlices, error) {
+func processGpuSlices(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData_GpuSlices, error) {
 	slicesQueryResult, err := processor.Query(slicesQuery)
 	if err != nil {
 		return nil, log.Errf(ctx, err, "SQL query failed: %v", slicesQuery)
@@ -114,27 +116,42 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur
 	commandBuffers := slicesColumns[5].GetLongValues()
 	extractTraceHandles(ctx, &commandBuffers, "VkCommandBuffer", handleMapping)
 
+	renderPasses := slicesColumns[6].GetLongValues()
+	extractTraceHandles(ctx, &renderPasses, "VkRenderPass", handleMapping)
+
+	frameIds := slicesColumns[2].GetLongValues()
 	submissionIds := slicesColumns[3].GetLongValues()
-	currentSubId := int64(-1)
-	subCommandGroupMap := make(map[api.CommandSubmissionKey]bool)
+	hwQueueIds := slicesColumns[4].GetLongValues()
+	timestamps := slicesColumns[7].GetLongValues()
+	durations := slicesColumns[8].GetLongValues()
+	names := slicesColumns[9].GetStringValues()
+	depths := slicesColumns[10].GetLongValues()
+	argSetIds := slicesColumns[11].GetLongValues()
+	trackIds := slicesColumns[12].GetLongValues()
+	trackNames := slicesColumns[13].GetStringValues()
+
+	subCommandGroupMap := make(map[api.CmdSubmissionKey]int)
 	for i, v := range submissionIds {
-		if v != currentSubId {
-			currentSubId = v
-			// We'll never need the previous keys again
-			subCommandGroupMap = make(map[api.CommandSubmissionKey]bool)
-		}
 		subOrder, ok := submissionOrdering[v]
 		if ok {
-			cb := commandBuffers[i]
-			key := api.CommandSubmissionKey{SubmissionOrder: subOrder, CommandBuffer: cb}
-			if _, ok := subCommandGroupMap[key]; !ok {
-				if indices, ok := (*subCommandIndicesMap)[key]; ok {
+			cb := uint64(commandBuffers[i])
+			key := api.CmdSubmissionKey{subOrder, cb, uint64(renderPasses[i]), uint64(renderTargets[i])}
+			if indices, ok := syncData.SubmissionIndices[key]; ok {
+				if names[i] == renderPassSliceName {
+					var idx []uint64
+					if c, ok := subCommandGroupMap[key]; ok {
+						idx = indices[c]
+					} else {
+						idx = indices[0]
+						subCommandGroupMap[key] = 0
+					}
+
 					group := &service.ProfilingData_GpuSlices_Group{
 						Id:   int32(len(groups)),
-						Link: &path.Command{Capture: capture, Indices: indices},
+						Link: &path.Command{Capture: capture, Indices: idx},
 					}
 					groups = append(groups, group)
-					subCommandGroupMap[key] = true
+					subCommandGroupMap[key]++
 				}
 			}
 		} else {
@@ -144,16 +161,6 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur
 		groupIds[i] = int32(len(groups)) - 1
 	}
 
-	frameIds := slicesColumns[2].GetLongValues()
-	hwQueueIds := slicesColumns[4].GetLongValues()
-	timestamps := slicesColumns[6].GetLongValues()
-	durations := slicesColumns[7].GetLongValues()
-	names := slicesColumns[8].GetStringValues()
-	depths := slicesColumns[9].GetLongValues()
-	argSetIds := slicesColumns[10].GetLongValues()
-	trackIds := slicesColumns[11].GetLongValues()
-	trackNames := slicesColumns[12].GetStringValues()
-
 	for i := uint64(0); i < numSliceRows; i++ {
 		var argsQueryResult *perfetto_service.QueryResult
 		var ok bool
@@ -188,6 +195,10 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur
 			Name:  "commandBuffer",
 			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(commandBuffers[i])},
 		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "renderPass",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(renderPasses[i])},
+		})
 		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
 			Name:  "frameId",
 			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(frameIds[i])},
@@ -201,7 +212,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur
 			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])},
 		})
 
-		if names[i] == "Surface" && groupIds[i] != -1 {
+		if names[i] == renderPassSliceName && groupIds[i] != -1 {
 			names[i] = fmt.Sprintf("%v", groups[groupIds[i]].Link.Indices)
 		}
 
diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go
index 890f04bfcd..593cdf3ab0 100644
--- a/gapis/trace/android/trace.go
+++ b/gapis/trace/android/trace.go
@@ -28,7 +28,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
 	"github.com/google/gapid/gapis/service/path"
 	perfetto_pb "protos/perfetto/config"
 
@@ -123,7 +123,7 @@ func (t *androidTracer) GetDevice() bind.Device {
 	return t.b
 }
 
-func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMappings *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) {
+func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMappings *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error) {
 	// Load Perfetto trace and create trace processor.
 	rawData := make([]byte, buffer.Len())
 	_, err := buffer.Read(rawData)
@@ -140,7 +140,7 @@ func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.
 	desc := conf.GetPerfettoCapability().GetGpuProfiling().GetGpuCounterDescriptor()
 	gpuName := gpu.GetName()
 	if strings.Contains(gpuName, "Adreno") {
-		return adreno.ProcessProfilingData(ctx, processor, capture, desc, handleMappings, submissionIds)
+		return adreno.ProcessProfilingData(ctx, processor, capture, desc, handleMappings, syncData)
 	}
 	return nil, log.Errf(ctx, nil, "Failed to process Perfetto trace for device %v", gpuName)
 }
diff --git a/gapis/trace/desktop/BUILD.bazel b/gapis/trace/desktop/BUILD.bazel
index a74f8f9758..1f65d36e94 100644
--- a/gapis/trace/desktop/BUILD.bazel
+++ b/gapis/trace/desktop/BUILD.bazel
@@ -35,7 +35,7 @@ go_library(
         "//core/text:go_default_library",
         "//core/vulkan/loader:go_default_library",
         "//gapii/client:go_default_library",
-        "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/perfetto/desktop:go_default_library",
         "//gapis/service:go_default_library",
         "//gapis/service/path:go_default_library",
diff --git a/gapis/trace/desktop/trace.go b/gapis/trace/desktop/trace.go
index 4d09b85058..df79827160 100644
--- a/gapis/trace/desktop/trace.go
+++ b/gapis/trace/desktop/trace.go
@@ -31,7 +31,7 @@ import (
 	"github.com/google/gapid/core/os/process"
 	"github.com/google/gapid/core/vulkan/loader"
 	gapii "github.com/google/gapid/gapii/client"
-	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
 	perfetto "github.com/google/gapid/gapis/perfetto/desktop"
 	"github.com/google/gapid/gapis/service"
 	gapis_path "github.com/google/gapid/gapis/service/path"
@@ -50,7 +50,7 @@ func (t *DesktopTracer) GetDevice() bind.Device {
 	return t.b
 }
 
-func (t *DesktopTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *gapis_path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) {
+func (t *DesktopTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *gapis_path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error) {
 	return nil, log.Err(ctx, nil, "Desktop replay profiling is unsupported.")
 }
 
diff --git a/gapis/trace/trace.go b/gapis/trace/trace.go
index cc60b21405..3d72abb6ba 100644
--- a/gapis/trace/trace.go
+++ b/gapis/trace/trace.go
@@ -26,7 +26,7 @@ import (
 	"github.com/google/gapid/core/event/task"
 	"github.com/google/gapid/core/log"
 	gapii "github.com/google/gapid/gapii/client"
-	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
 	"github.com/google/gapid/gapis/config"
 	"github.com/google/gapid/gapis/service"
 	"github.com/google/gapid/gapis/service/path"
@@ -107,12 +107,12 @@ func TraceConfiguration(ctx context.Context, device *path.Device) (*service.Devi
 	return t.TraceConfiguration(ctx)
 }
 
-func ProcessProfilingData(ctx context.Context, device *path.Device, capture *path.Capture, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error) {
+func ProcessProfilingData(ctx context.Context, device *path.Device, capture *path.Capture, buffer *bytes.Buffer, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error) {
 	t, err := GetTracer(ctx, device)
 	if err != nil {
 		return nil, err
 	}
-	return t.ProcessProfilingData(ctx, buffer, capture, handleMapping, submissionIds)
+	return t.ProcessProfilingData(ctx, buffer, capture, handleMapping, syncData)
 }
 
 func Validate(ctx context.Context, device *path.Device) error {
diff --git a/gapis/trace/tracer/BUILD.bazel b/gapis/trace/tracer/BUILD.bazel
index 5b1ad5b31f..d94743b50e 100644
--- a/gapis/trace/tracer/BUILD.bazel
+++ b/gapis/trace/tracer/BUILD.bazel
@@ -28,7 +28,7 @@ go_library(
         "//core/event/task:go_default_library",
         "//core/os/device/bind:go_default_library",
         "//gapii/client:go_default_library",
-        "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/service:go_default_library",
         "//gapis/service/path:go_default_library",
     ],
diff --git a/gapis/trace/tracer/tracer.go b/gapis/trace/tracer/tracer.go
index 9b21930a1a..0a1636d184 100644
--- a/gapis/trace/tracer/tracer.go
+++ b/gapis/trace/tracer/tracer.go
@@ -24,7 +24,7 @@ import (
 	"github.com/google/gapid/core/event/task"
 	"github.com/google/gapid/core/os/device/bind"
 	gapii "github.com/google/gapid/gapii/client"
-	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
 	"github.com/google/gapid/gapis/service"
 	"github.com/google/gapid/gapis/service/path"
 )
@@ -74,7 +74,7 @@ type Tracer interface {
 	GetDevice() bind.Device
 	// ProcessProfilingData takes a buffer for a Perfetto trace and translates it into
 	// a ProfilingData
-	ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, submissionIds *map[api.CommandSubmissionKey][]uint64) (*service.ProfilingData, error)
+	ProcessProfilingData(ctx context.Context, buffer *bytes.Buffer, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error)
 	// Validate validates the GPU profiling capabilities of the given device and returns
 	// an error if validation failed or the GPU profiling data is invalid.
 	Validate(ctx context.Context) error

From 7f2260c8514bb46a5e9060cb6be11303fd601d22 Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Fri, 6 Mar 2020 10:54:24 +0000
Subject: [PATCH 0125/1218] Fixes the pipeline barrier for getting framebuffer
 during trace (#115)

---
 gapii/cc/vulkan_extras.cpp | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/gapii/cc/vulkan_extras.cpp b/gapii/cc/vulkan_extras.cpp
index 0d576e2c7c..ececce2787 100644
--- a/gapii/cc/vulkan_extras.cpp
+++ b/gapii/cc/vulkan_extras.cpp
@@ -263,8 +263,7 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
   VkImageMemoryBarrier barriers[2] = {
       {VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,  // sType
        nullptr,                                                  // pNext
-       (VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT << 1) -
-           1,                                          // srcAccessMask
+       VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT,   // srcAccessMask
        VkAccessFlagBits::VK_ACCESS_TRANSFER_READ_BIT,  // dstAccessMask
        image->mAspects[VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT]
            ->mLayers[frame_buffer_img_layer]
@@ -284,8 +283,7 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
        }},
       {VkStructureType::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,  // sType
        nullptr,                                                  // pNext
-       (VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT << 1) -
-           1,                                                // srcAccessMask
+       VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT,         // srcAccessMask
        VkAccessFlagBits::VK_ACCESS_TRANSFER_WRITE_BIT,       // dstAccessMask
        VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED,             // srcLayout
        VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,  // dstLayout
@@ -304,7 +302,7 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
 
   fn.vkCmdPipelineBarrier(
       command_buffer,
-      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
       VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
       nullptr, 2, barriers);
   VkImageBlit blit = {
@@ -322,8 +320,8 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
                     &blit, VkFilter::VK_FILTER_NEAREST);
 
   barriers[0].msrcAccessMask = VkAccessFlagBits::VK_ACCESS_TRANSFER_READ_BIT;
-  barriers[0].mdstAccessMask =
-      (VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT << 1) - 1;
+  barriers[0].mdstAccessMask = VkAccessFlagBits::VK_ACCESS_MEMORY_WRITE_BIT |
+                               VkAccessFlagBits::VK_ACCESS_MEMORY_READ_BIT;
   barriers[0].moldLayout = VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
   barriers[0].mnewLayout =
       image->mAspects[VkImageAspectFlagBits::VK_IMAGE_ASPECT_COLOR_BIT]
@@ -337,7 +335,7 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
 
   fn.vkCmdPipelineBarrier(
       command_buffer, VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TRANSFER_BIT,
-      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, 0,
+      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0,
       nullptr, 0, nullptr, 2, barriers);
 
   VkBufferImageCopy copy_region = {
@@ -364,8 +362,8 @@ bool VulkanSpy::observeFramebuffer(CallObserver* observer, uint32_t* w,
   };
   fn.vkCmdPipelineBarrier(
       command_buffer, VkPipelineStageFlagBits::VK_PIPELINE_STAGE_TRANSFER_BIT,
-      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, 0,
-      nullptr, 1, &buffer_barrier, 0, nullptr);
+      VkPipelineStageFlagBits::VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 1,
+      &buffer_barrier, 0, nullptr);
 
   fn.vkEndCommandBuffer(command_buffer);
 

From f9919e679b7be1d2521f19c41e8c3405df6eb048 Mon Sep 17 00:00:00 2001
From: Peiyong Lin 
Date: Fri, 6 Mar 2020 14:27:37 -0800
Subject: [PATCH 0126/1218] Add proper support for Android 11. (#124)

Now that Android 11 Developer Preview is out, add proper support for it.

Minor: Fix missing break statement.

Bug: N/A
---
 core/os/device/android.go                      | 2 ++
 core/os/device/deviceinfo/cc/android/query.cpp | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/core/os/device/android.go b/core/os/device/android.go
index 871231a4da..44353076e6 100644
--- a/core/os/device/android.go
+++ b/core/os/device/android.go
@@ -27,6 +27,8 @@ func AndroidOS(major, minor, point int32) *OS {
 		PointVersion: point,
 	}
 	switch {
+	case major == 11:
+		os.Name = "Android 11"
 	case major == 10:
 		os.Name = "Android 10"
 	case major == 9:
diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp
index e944958221..08d911f5c9 100644
--- a/core/os/device/deviceinfo/cc/android/query.cpp
+++ b/core/os/device/deviceinfo/cc/android/query.cpp
@@ -345,9 +345,14 @@ bool createContext() {
   }
 
   switch (gContext.mOSVersion) {
+    case 30:  // Android 11
+      gContext.mOSVersionMajor = 11;
+      gContext.mOSVersionMinor = 0;
+      break;
     case 29:  // Android 10
       gContext.mOSVersionMajor = 10;
       gContext.mOSVersionMinor = 0;
+      break;
     case 28:  // Pie
       gContext.mOSVersionMajor = 9;
       gContext.mOSVersionMinor = 0;

From 14a1916a71de18efed3c37288cf1e32f8c79d65d Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Thu, 5 Mar 2020 14:47:15 -0800
Subject: [PATCH 0127/1218] Associate AGI with .perfetto files on Linux.

---
 kokoro/linux/gapid-mime.xml | 4 ++++
 kokoro/linux/gapid.desktop  | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/kokoro/linux/gapid-mime.xml b/kokoro/linux/gapid-mime.xml
index 8516c27dae..d4b9792717 100644
--- a/kokoro/linux/gapid-mime.xml
+++ b/kokoro/linux/gapid-mime.xml
@@ -19,4 +19,8 @@
      Graphics API Trace
      
    
+   
+     System Profile Trace
+     
+   
 
diff --git a/kokoro/linux/gapid.desktop b/kokoro/linux/gapid.desktop
index 9cff18e2cd..71da959b00 100644
--- a/kokoro/linux/gapid.desktop
+++ b/kokoro/linux/gapid.desktop
@@ -7,4 +7,4 @@ Categories=Development;Debugger;Graphics;3DGraphics
 Icon=/opt/agi/icon.png
 Exec=/opt/agi/agi %f
 Terminal=false
-MimeType=application/x-gfxtrace
+MimeType=application/x-gfxtrace;application/x-perfetto

From 1b2467300c318dbdde5c4afde71973ce9586c4f8 Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Thu, 5 Mar 2020 14:49:22 -0800
Subject: [PATCH 0128/1218] Associate AGI with .perfetto files on Windows.

---
 kokoro/windows/gapid.wxs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kokoro/windows/gapid.wxs b/kokoro/windows/gapid.wxs
index 0f4c708ae9..e57ed3d918 100644
--- a/kokoro/windows/gapid.wxs
+++ b/kokoro/windows/gapid.wxs
@@ -71,10 +71,13 @@
         
 
         
+        
         
 
         
+        
         
+        
       
     
 

From 3e3071d334bc50c4d670ef051331b7963d479f39 Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Thu, 5 Mar 2020 14:51:42 -0800
Subject: [PATCH 0129/1218] Associate AGI with .perfetto files on MacOS.

---
 kokoro/macos/Info.plist | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/kokoro/macos/Info.plist b/kokoro/macos/Info.plist
index 7066d10ed6..e1e8057453 100644
--- a/kokoro/macos/Info.plist
+++ b/kokoro/macos/Info.plist
@@ -38,6 +38,20 @@
     LSHandlerRank
     Owner
    
+    
+    CFBundleTypeExtensions
+    
+     perfetto
+    
+    CFBundleTypeIconFile
+    AGI.icns
+    CFBundleTypeName
+    System Profile Trace
+    CFBundleTypeRole
+    Editor
+    LSHandlerRank
+    Owner
+   
   
  
 

From c40b49585f00cd16ba59d6b911bd27af9a526524 Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Thu, 5 Mar 2020 14:41:18 -0800
Subject: [PATCH 0130/1218] Make sure we don't drop the DocumentOpen events.

Listen for the DocumentOpen event as soon as possible, so we don't miss
any. If one is received, while we are still starting up, simply remember
the file to open and open it as soon as we are ready.
---
 gapic/src/main/com/google/gapid/Main.java     |  6 +++++
 .../com/google/gapid/util/MacApplication.java | 26 +++++++++++++++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/Main.java b/gapic/src/main/com/google/gapid/Main.java
index e179051f25..102cc31fa0 100644
--- a/gapic/src/main/com/google/gapid/Main.java
+++ b/gapic/src/main/com/google/gapid/Main.java
@@ -35,7 +35,9 @@
 import com.google.gapid.util.Flags;
 import com.google.gapid.util.Flags.Flag;
 import com.google.gapid.util.Logging;
+import com.google.gapid.util.MacApplication;
 import com.google.gapid.util.Messages;
+import com.google.gapid.util.OS;
 import com.google.gapid.util.Scheduler;
 import com.google.gapid.views.TracerDialog;
 import com.google.gapid.widgets.Theme;
@@ -66,6 +68,10 @@ public static void main(String[] args) throws Exception {
     Theme theme = Theme.load(Display.getDefault());
     ExceptionHandler handler = Crash2ExceptionHandler.register(settings);
 
+    if (OS.isMac) {
+      MacApplication.listenForOpenDocument(Display.getDefault());
+    }
+
     try {
       new UI(settings, theme, handler, args).show();
     } finally {
diff --git a/gapic/src/main/com/google/gapid/util/MacApplication.java b/gapic/src/main/com/google/gapid/util/MacApplication.java
index c21333ecc7..190034cd25 100644
--- a/gapic/src/main/com/google/gapid/util/MacApplication.java
+++ b/gapic/src/main/com/google/gapid/util/MacApplication.java
@@ -15,25 +15,44 @@
  */
 package com.google.gapid.util;
 
+import static java.util.logging.Level.INFO;
+
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.swt.widgets.MenuItem;
 
 import java.util.function.Consumer;
+import java.util.logging.Logger;
 
 /**
  * Special handling for OSX application menus.
  */
 public class MacApplication {
+  private static final Logger LOG = Logger.getLogger(MacApplication.class.getName());
+
+  private static Consumer onOpen = null;
+  private static String documentToOpen;
+
   private MacApplication() {
   }
 
+  public static void listenForOpenDocument(Display display) {
+    display.addListener(SWT.OpenDocument, e -> {
+      LOG.log(INFO, "OpenDocument Event: " + e);
+      if (onOpen != null) {
+        onOpen.accept(e.text);
+      } else {
+        documentToOpen = e.text;
+      }
+    });
+  }
+
   /**
    * Initializes the OSX application menus.
    */
   public static void init(
-      Display display, Runnable onAbout, Runnable onSettings, Consumer onOpen) {
+      Display display, Runnable onAbout, Runnable onSettings, Consumer newOnOpen) {
     Menu menu = display.getSystemMenu();
     if (menu == null) {
       return;
@@ -50,6 +69,9 @@ public static void init(
       }
     }
 
-    display.addListener(SWT.OpenDocument, e -> onOpen.accept(e.text));
+    onOpen = newOnOpen;
+    if (documentToOpen != null) {
+      onOpen.accept(documentToOpen);
+    }
   }
 }

From 6db5a755712b7a5417610fcb432201980d3645e3 Mon Sep 17 00:00:00 2001
From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com>
Date: Sun, 8 Mar 2020 23:29:17 -0700
Subject: [PATCH 0131/1218] Update frame lifecycle capability based on sdk and
 preview_sdk versions (#113)

* Update frame lifecycle capability based on sdk and preview_sdk versions

The name property has been updated to Android 10, for R builds. This is
same as Q and hence cannot be used to distinguish between the two
dessert releases. For now, we depend on sdk and preview_sdk versions to
distinguish them.
---
 core/os/android/adb/commands.go                | 3 +--
 core/os/android/adb/device.go                  | 7 +++++++
 core/os/device/deviceinfo/cc/android/query.cpp | 6 ++++++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/core/os/android/adb/commands.go b/core/os/android/adb/commands.go
index 2ab9269c88..5b35a7cb9a 100644
--- a/core/os/android/adb/commands.go
+++ b/core/os/android/adb/commands.go
@@ -331,8 +331,7 @@ func (b *binding) QueryPerfettoServiceState(ctx context.Context) (*device.Perfet
 		result.GpuProfiling = gpu
 	}
 
-	if b.Instance().GetConfiguration().GetOS().GetName() == "R" {
-		// TODO(b/146384733): Change this to API version when it releases
+	if b.Instance().GetConfiguration().GetOS().GetAPIVersion() >= 30 {
 		gpu.HasFrameLifecycle = true
 	}
 
diff --git a/core/os/android/adb/device.go b/core/os/android/adb/device.go
index 701c67e1f6..c5f4c00997 100644
--- a/core/os/android/adb/device.go
+++ b/core/os/android/adb/device.go
@@ -160,6 +160,13 @@ func newDevice(ctx context.Context, serial string, status bind.Status) (*binding
 	// Collect the API version
 	if version, err := d.SystemProperty(ctx, "ro.build.version.sdk"); err == nil {
 		v, _ := strconv.Atoi(version)
+		// preview_sdk is used to determine the version for the next OS release
+		// Until the official release, new OS releases will use the same sdk
+		// version as the previous OS while setting the preview_sdk
+		if preview, err := d.SystemProperty(ctx, "ro.build.version.preview_sdk"); err == nil {
+			p, _ := strconv.Atoi(preview)
+			v += p
+		}
 		d.To.Configuration.OS.APIVersion = int32(v)
 	}
 
diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp
index 08d911f5c9..f7e00415ad 100644
--- a/core/os/device/deviceinfo/cc/android/query.cpp
+++ b/core/os/device/deviceinfo/cc/android/query.cpp
@@ -328,6 +328,12 @@ bool createContext() {
 
   GET_STRING_PROP("ro.build.version.release", gContext.mOSName);
   GET_INT_PROP("ro.build.version.sdk", gContext.mOSVersion);
+  // preview_sdk is used to determine the version for the next OS release
+  // Until the official release, the new OS releases will use the same sdk
+  // version as the previous OS while setting the preview_sdk
+  int previewSdk = 0;
+  GET_INT_PROP("ro.build.version.preview_sdk", previewSdk);
+  gContext.mOSVersion += previewSdk;
 
   if (gContext.mSupportedABIs.size() > 0) {
     auto primaryABI = gContext.mSupportedABIs[0];

From 76fbf77485e5a529654a9db80b121299cec96ce9 Mon Sep 17 00:00:00 2001
From: "Melih Y. Yalcin" 
Date: Mon, 9 Mar 2020 13:40:43 +0000
Subject: [PATCH 0132/1218] Converts "~" character to user home while saving
 trace file (#122)

b/146355739
---
 gapic/src/main/com/google/gapid/widgets/FileTextbox.java | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gapic/src/main/com/google/gapid/widgets/FileTextbox.java b/gapic/src/main/com/google/gapid/widgets/FileTextbox.java
index cbc4706494..261be2979e 100644
--- a/gapic/src/main/com/google/gapid/widgets/FileTextbox.java
+++ b/gapic/src/main/com/google/gapid/widgets/FileTextbox.java
@@ -86,5 +86,10 @@ protected String createAndShowDialog(String current) {
     protected void configureDialog(DirectoryDialog dialog) {
       // Empty.
     }
+
+    @Override
+    public String getText() {
+      return super.getText().replaceFirst("^~", System.getProperty("user.home"));
+    }
   }
 }

From fd82127f16cf1981becbb8a3f16297d8fda45531 Mon Sep 17 00:00:00 2001
From: Peiyong Lin 
Date: Mon, 9 Mar 2020 10:34:46 -0700
Subject: [PATCH 0133/1218] Add Mali counters for validation. (#126)

Add several Mali counters into validation. Provide counter information when
validation fails.

Bug: b/149346641
Test: bazel run gapit -- validate_gpu_profiling --os android
---
 gapis/trace/android/mali/validate.go     | 11 ++++++++++-
 gapis/trace/android/validate/validate.go |  2 +-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/gapis/trace/android/mali/validate.go b/gapis/trace/android/mali/validate.go
index ef8d27877a..7e825f0bea 100644
--- a/gapis/trace/android/mali/validate.go
+++ b/gapis/trace/android/mali/validate.go
@@ -23,7 +23,16 @@ import (
 
 var (
 	// All counters must be inside this array.
-	counters = []validate.GpuCounter{}
+	counters = []validate.GpuCounter{
+		{6, "GPU active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{8, "Fragment jobs", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{196, "Fragment active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{233, "Compressed texture line fetch requests", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))},
+		{65536, "GPU utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{65538, "Fragment queue utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{65579, "Execution core utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)},
+		{65585, "Texture data fetches form compressed lines", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))},
+	}
 )
 
 type MaliValidator struct {
diff --git a/gapis/trace/android/validate/validate.go b/gapis/trace/android/validate/validate.go
index 3327e92667..31d1029e6a 100644
--- a/gapis/trace/android/validate/validate.go
+++ b/gapis/trace/android/validate/validate.go
@@ -156,7 +156,7 @@ func ValidateGpuCounters(ctx context.Context, processor *perfetto.Processor, cou
 			longValues := column.GetLongValues()
 			if len(longValues) != 1 {
 				// This should never happen, but sill have a check.
-				return log.Err(ctx, nil, "Query result is not 1.")
+				return log.Errf(ctx, nil, "Query result is not 1: %v", counter)
 			}
 			counterID = longValues[0]
 			break

From d8ad6093a1e92f3979030e540fd6846c2b31d69c Mon Sep 17 00:00:00 2001
From: hliatis <47799839+hliatis@users.noreply.github.com>
Date: Mon, 9 Mar 2020 17:42:51 -0700
Subject: [PATCH 0134/1218] Prevent repeated descriptors in PV shader stage
 tables (#103)

Bug: b/150420371
---
 gapis/api/vulkan/api/pipeline.api | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/gapis/api/vulkan/api/pipeline.api b/gapis/api/vulkan/api/pipeline.api
index a273ccd789..e77aabf1bf 100644
--- a/gapis/api/vulkan/api/pipeline.api
+++ b/gapis/api/vulkan/api/pipeline.api
@@ -227,6 +227,11 @@ class CreatedGraphicsPipelines {
   map!(u32, ref!GraphicsPipelineObject) Objects
 }
 
+
+@internal class MutableSet {
+  map!(u64, bool) Set
+}
+
 @indirect("VkDevice")
 @threadsafe
 cmd VkResult vkCreateGraphicsPipelines(
@@ -274,6 +279,8 @@ cmd VkResult vkCreateGraphicsPipelines(
     }
     obj.Flags = create_info.flags
 
+    seenDescs := MutableSet()
+
     pipeline_shader_stage_create_infos :=
     create_info.pStages[0:create_info.stageCount]
     for j in (0 .. create_info.stageCount) {
@@ -305,24 +312,31 @@ cmd VkResult vkCreateGraphicsPipelines(
         spec_data.Data = clone(as!u8*(spec_info.pData)[0:spec_info.dataSize])
         stage_data.Specialization = spec_data
       }
-      
+
       if stage_data.Module.Descriptors != null {
         moduleDescriptors := stage_data.Module.Descriptors.Descriptors[as!string(stage_create_info.pName)]
         for _, _, d in moduleDescriptors {
-          obj.UsedDescriptors[len(obj.UsedDescriptors)] = d
-        }
+          if !seenDescs.Set[(as!u64(d.Set)<<32) | as!u64(d.Binding)] {
+            obj.UsedDescriptors[len(obj.UsedDescriptors)] = d
+            seenDescs.Set[(as!u64(d.Set)<<32) | as!u64(d.Binding)] = true
+          }
+        } 
       } else {
         nSets := len(obj.Layout.SetLayouts)
         for ii in (0 .. nSets) {
           set := obj.Layout.SetLayouts[as!u32(ii)]
           for _, k, v in set.Bindings {
-            obj.UsedDescriptors[len(obj.UsedDescriptors)] =
-              DescriptorUsage(Set: as!u32(ii),
-                Binding: k,
-                DescriptorCount: v.Count)
+            if !seenDescs.Set[(as!u64(ii)<<32) | as!u64(k)] {
+              obj.UsedDescriptors[len(obj.UsedDescriptors)] = 
+                DescriptorUsage(Set: as!u32(ii),
+                  Binding: k, 
+                  DescriptorCount: v.Count) 
+              seenDescs.Set[(as!u64(ii)<<32) | as!u64(k)] = true
+            }
           }
         }
       }
+
       obj.Stages[j] = stage_data
     }
 

From 5717a156d515254a72440948e9cf26dd1248a5cf Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Wed, 11 Mar 2020 10:02:34 +0000
Subject: [PATCH 0135/1218] vkUnmap memory of gapii staging buffer (#132)

---
 gapii/cc/vulkan_mid_execution.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/gapii/cc/vulkan_mid_execution.cpp b/gapii/cc/vulkan_mid_execution.cpp
index cea5705708..8a25bb2911 100644
--- a/gapii/cc/vulkan_mid_execution.cpp
+++ b/gapii/cc/vulkan_mid_execution.cpp
@@ -193,6 +193,16 @@ class StagingBuffer {
       device_functions_.vkDestroyBuffer(device_, staging_buffer_, nullptr);
     }
     if (staging_memory_) {
+      // TODO(b/151157266): Remove this workaround once b/151157266 is fixed.
+      // Driver bug workaround: explicitely unmap memory before vkFreeMemory().
+      // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkFreeMemory.html
+      // The vkFreeMemory spec says "If a memory object is mapped at the time
+      // it is freed, it is implicitly unmapped". Yet some drivers seem to
+      // leak the memory, unless it is explicitely unmapped. Hence our call
+      // to vkUnmapMemory() here.
+      if (bound_memory_) {
+        device_functions_.vkUnmapMemory(device_, staging_memory_);
+      }
       device_functions_.vkFreeMemory(device_, staging_memory_, nullptr);
     }
   }

From 12c4505f9fd49b7b2e04da934f4428ef1145be1a Mon Sep 17 00:00:00 2001
From: stellama0208 <49965489+stellama0208@users.noreply.github.com>
Date: Wed, 11 Mar 2020 20:21:33 -0700
Subject: [PATCH 0136/1218] Fix two bugs related to drag selection. (#121)

 - Add drag-selection to the Process Panel.
 - Change CPU slices' color after drag-selecting in Thread Panel.
 - Bug: http://b/147922469. #2 and #3.
---
 .../perfetto/models/ProcessSummaryTrack.java    | 17 +++++++++++++++++
 .../perfetto/views/ProcessSummaryPanel.java     | 11 ++++++++++-
 .../gapid/perfetto/views/ThreadPanel.java       |  6 ++++--
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
index 00f6a58360..01318a019a 100644
--- a/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
+++ b/gapic/src/main/com/google/gapid/perfetto/models/ProcessSummaryTrack.java
@@ -27,6 +27,7 @@
 
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.gapid.perfetto.TimeSpan;
 import com.google.gapid.perfetto.models.CpuTrack.Slice;
 import java.util.Arrays;
 import java.util.List;
@@ -41,6 +42,10 @@ public class ProcessSummaryTrack extends Track.WithQueryEngine= %d";
   private static final String SLICE_RANGE_FOR_IDS_SQL =
       "select sched.id, ts, dur, cpu, utid, upid, end_state, priority " +
       "from sched left join thread using(utid) " +
@@ -120,6 +125,18 @@ private String slicesSql() {
     return format(SLICES_SQL, tableName("span"));
   }
 
+  public ListenableFuture> getSlices(TimeSpan ts) {
+    return transform(qe.query(sliceRangeSql(ts)), result -> {
+      List slices = Lists.newArrayList();
+      result.forEachRow((i, r) -> slices.add(new Slice(r)));
+      return slices;
+    });
+  }
+
+  private String sliceRangeSql(TimeSpan ts) {
+    return format(SLICE_RANGE_SQL, process.upid, ts.end, ts.start);
+  }
+
   public ListenableFuture> getSlices(String ids) {
     return transform(qe.query(sliceRangeForIdsSql(ids)), result -> {
       List slices = Lists.newArrayList();
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
index 191ca67c60..5944d14fa8 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java
@@ -33,6 +33,7 @@
 import com.google.gapid.perfetto.models.CpuTrack;
 import com.google.gapid.perfetto.models.ProcessSummaryTrack;
 import com.google.gapid.perfetto.models.Selection;
+import com.google.gapid.perfetto.models.Selection.CombiningBuilder;
 import com.google.gapid.perfetto.models.ThreadInfo;
 
 import org.eclipse.swt.SWT;
@@ -45,7 +46,7 @@
 /**
  * Displays the CPU usage summary of a process, aggregating all threads.
  */
-public class ProcessSummaryPanel extends TrackPanel {
+public class ProcessSummaryPanel extends TrackPanel implements Selectable {
   private static final double HEIGHT = 50;
   private static final double HOVER_MARGIN = 10;
   private static final double HOVER_PADDING = 4;
@@ -332,6 +333,14 @@ public boolean click() {
     };
   }
 
+  @Override
+  public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) {
+    builder.add(Selection.Kind.Cpu, transform(track.getSlices(ts), r -> {
+      r.forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+      return new CpuTrack.SlicesBuilder(r);
+    }));
+  }
+
   private static class HoverCard {
     public final int bucket;
     public final double utilization;
diff --git a/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java
index 5367bd99a0..1814bff302 100644
--- a/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java
+++ b/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java
@@ -394,8 +394,10 @@ public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) {
     if (startDepth == 0) {
       builder.add(Selection.Kind.ThreadState,
           transform(track.getStates(ts), ThreadTrack.StateSlicesBuilder::new));
-      builder.add(Selection.Kind.Cpu, transform(
-          track.getCpuSlices(ts), r -> new CpuTrack.SlicesBuilder(r)));
+      builder.add(Selection.Kind.Cpu, transform(track.getCpuSlices(ts), r -> {
+        r.forEach(s -> state.addSelectedThread(state.getThreadInfo(s.utid)));
+        return new CpuTrack.SlicesBuilder(r);
+      }));
     }
 
     startDepth = Math.max(0, startDepth - 1);

From c8f764014bdc5469f28866da5b34a098313b3b9b Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Thu, 12 Mar 2020 15:20:09 +0000
Subject: [PATCH 0137/1218] Create only one staging buffer per device (#135)

When retrieving the Vulkan state at the start of a mid-execution
capture, we create a new staging buffer for each of the buffers in the
state.

This change creates only one staging buffer per device, and reuses it
to retrieve all buffers of that device.

To enable using the make_unique definition found in
memory_tracker_layer_impl.cpp everywhere, we move it into
core/cc/make_unique.h

Bug: none
Test: capture a few Vulkan apps
---
 core/cc/make_unique.h                         | 30 +++++++++++++++++++
 .../cc/memory_tracker_layer_impl.cpp          |  6 +---
 gapii/cc/vulkan_mid_execution.cpp             | 28 +++++++++++------
 3 files changed, 50 insertions(+), 14 deletions(-)
 create mode 100644 core/cc/make_unique.h

diff --git a/core/cc/make_unique.h b/core/cc/make_unique.h
new file mode 100644
index 0000000000..f10f1be0d9
--- /dev/null
+++ b/core/cc/make_unique.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// std::make_unique is only available from C++14. As we stick to C++11 for now,
+// we define our own make_unique here.
+
+#ifndef CORE_MAKE_UNIQUE_H
+#define CORE_MAKE_UNIQUE_H
+
+#include 
+
+template 
+std::unique_ptr make_unique(Args&&... args) {
+  return std::unique_ptr(new T(std::forward(args)...));
+}
+
+#endif  // CORE_MAKE_UNIQUE_H
diff --git a/core/vulkan/vk_memory_tracker_layer/cc/memory_tracker_layer_impl.cpp b/core/vulkan/vk_memory_tracker_layer/cc/memory_tracker_layer_impl.cpp
index 8f61840078..ad8d924b2e 100644
--- a/core/vulkan/vk_memory_tracker_layer/cc/memory_tracker_layer_impl.cpp
+++ b/core/vulkan/vk_memory_tracker_layer/cc/memory_tracker_layer_impl.cpp
@@ -24,6 +24,7 @@
 #include 
 #endif
 
+#include "core/cc/make_unique.h"
 #include "core/vulkan/vk_memory_tracker_layer/cc/tracing_helpers.h"
 #include "perfetto/base/time.h"
 
@@ -40,11 +41,6 @@ MemoryTracker memory_tracker_instance;
 rwlock rwl_global_unique_handles;
 std::unordered_map global_unique_handles;
 
-template 
-std::unique_ptr make_unique(Args&&... args) {
-  return std::unique_ptr(new T(std::forward(args)...));
-}
-
 // --------------------------- UniqueHandleGenerator ---------------------------
 
 uint64_t UniqueHandleGenerator::Hash64(uint64_t handle, uint64_t counter) {
diff --git a/gapii/cc/vulkan_mid_execution.cpp b/gapii/cc/vulkan_mid_execution.cpp
index 8a25bb2911..4e100ce8b1 100644
--- a/gapii/cc/vulkan_mid_execution.cpp
+++ b/gapii/cc/vulkan_mid_execution.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "core/cc/make_unique.h"
+
 #include "gapii/cc/state_serializer.h"
 #include "gapii/cc/vulkan_exports.h"
 #include "gapii/cc/vulkan_spy.h"
@@ -344,6 +346,18 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer* serializer) {
     }
   }
 
+  // Retrieve buffers, one by one, chunk by chunk, to prevent OOM.
+  // Prepare one staging buffer of size kChunkSizeLimit per device.
+  std::unordered_map> staging_buffers;
+  for (auto it = mState.Devices.begin(); it != mState.Devices.end(); it++) {
+    VkDevice device = it->first;
+    staging_buffers[device] = make_unique(
+        arena(), mImports.mVkDeviceFunctions[device], device,
+        mState.PhysicalDevices[mState.Devices[device]->mPhysicalDevice]
+            ->mMemoryProperties,
+        kChunkSizeLimit);
+  }
+
   for (auto& buffer : mState.Buffers) {
     VkBuffer buf_handle = buffer.first;
     auto buf = buffer.second;
@@ -400,18 +414,14 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer* serializer) {
       }
       auto& deviceMemory = mState.DeviceMemories[bind.mmemory];
 
-      StagingBuffer stage(
-          arena(), device_functions, buf->mDevice,
-          mState.PhysicalDevices[mState.Devices[buf->mDevice]->mPhysicalDevice]
-              ->mMemoryProperties,
-          kChunkSizeLimit);
-
       for (uint64_t offset = 0; offset < bind.msize;
            offset += kChunkSizeLimit) {
         uint64_t chunkSize = bind.msize - offset < kChunkSizeLimit
                                  ? bind.msize - offset
                                  : kChunkSizeLimit;
 
+        auto stage = staging_buffers[buf->mDevice].get();
+
         StagingCommandBuffer commandBuffer(
             device_functions, buf->mDevice,
             GetQueue(mState.Queues, buf->mDevice, buf)->mFamily);
@@ -419,7 +429,7 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer* serializer) {
         VkBufferCopy region{bind.mresourceOffset + offset, 0, chunkSize};
 
         device_functions.vkCmdCopyBuffer(commandBuffer.GetBuffer(), buf_handle,
-                                         stage.GetBuffer(), 1, ®ion);
+                                         stage->GetBuffer(), 1, ®ion);
 
         VkBufferMemoryBarrier barrier{
             VkStructureType::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
@@ -428,7 +438,7 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer* serializer) {
             VkAccessFlagBits::VK_ACCESS_HOST_READ_BIT,
             0xFFFFFFFF,
             0xFFFFFFFF,
-            stage.GetBuffer(),
+            stage->GetBuffer(),
             0,
             chunkSize};
 
@@ -446,7 +456,7 @@ void VulkanSpy::serializeGPUBuffers(StateSerializer* serializer) {
         memory::Observation observation;
         observation.set_pool(deviceMemory->mData.pool_id());
         observation.set_base(bind.mmemoryOffset + offset);
-        serializer->sendData(&observation, true, stage.GetMappedMemory(),
+        serializer->sendData(&observation, true, stage->GetMappedMemory(),
                              chunkSize);
       }
     }

From 9d36fb42990296496545e51f1c1b7b9475399a79 Mon Sep 17 00:00:00 2001
From: Hugues Evrard 
Date: Thu, 12 Mar 2020 17:24:22 +0000
Subject: [PATCH 0138/1218] Make SXS video work with PNG output. (#131)

This adds sxs-frames which will output to PNG.
It also blackens out the historgram background,
since unlike video, PNG respects alpha.

Co-authored-by: AWoloszyn 
---
 cmd/gapit/flags.go     |  2 ++
 cmd/gapit/sxs_video.go | 10 +++++++++-
 cmd/gapit/video.go     |  8 +++++++-
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go
index 63dec010cd..151b7890a2 100644
--- a/cmd/gapit/flags.go
+++ b/cmd/gapit/flags.go
@@ -26,6 +26,7 @@ const (
 	SxsVideo
 	RegularVideo
 	IndividualFrames
+	SxsFrames
 )
 
 const (
@@ -62,6 +63,7 @@ var videoTypeNames = map[VideoType]string{
 	SxsVideo:         "sxs",
 	RegularVideo:     "regular",
 	IndividualFrames: "frames",
+	SxsFrames:        "sxs-frames",
 }
 
 func (v *VideoType) Choose(c interface{}) {
diff --git a/cmd/gapit/sxs_video.go b/cmd/gapit/sxs_video.go
index 874c2c8190..4e58ee2ede 100644
--- a/cmd/gapit/sxs_video.go
+++ b/cmd/gapit/sxs_video.go
@@ -224,7 +224,7 @@ func (verb *videoVerb) sxsVideoSource(
 		//    ┃                ┃   Histogram   ┃
 		//    ┃                ┣━━━━━━━━━━━━━━━┫ p7
 		//    ┗━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┛
-		//                     p6
+		//                     p6                p8
 		var histogramHeight int
 		if histogram != nil {
 			histogramHeight = histogram.Bounds().Dy()
@@ -234,8 +234,10 @@ func (verb *videoVerb) sxsVideoSource(
 		p5 := image.Pt(w+2, h+200)
 		p6 := image.Pt(w, h*2)
 		p7 := image.Pt(w*2, p5.Y+histogramHeight)
+		p8 := image.Pt(w*2, h*2)
 
 		white := &image.Uniform{C: color.White}
+		black := &image.Uniform{C: color.Black}
 		rect := func(min, max image.Point) image.Rectangle {
 			return image.Rectangle{Min: min, Max: max}
 		}
@@ -262,6 +264,7 @@ func (verb *videoVerb) sxsVideoSource(
 				draw.Draw(sxs, rect(p2, p6), d, image.ZP, draw.Src)
 			}
 
+			draw.Draw(sxs, rect(p3, p8), black, image.ZP, draw.Src)
 			// Histogram
 			if h := histogram; h != nil {
 				draw.Draw(sxs, rect(p5, p7), histogram, image.ZP, draw.Src)
@@ -347,6 +350,11 @@ func getHistogram(videoFrames []*videoFrame) *image.NRGBA {
 
 	pixels := make([]byte, w*h*4)
 	out := &image.NRGBA{Pix: pixels, Stride: w * 4, Rect: image.Rect(0, 0, w, h)}
+	for i := range pixels {
+		if i%4 == 3 {
+			pixels[i] = 255
+		}
+	}
 
 	// Layout into RGBA32 bitmap.
 	f32s := make([]float32, bins*w)
diff --git a/cmd/gapit/video.go b/cmd/gapit/video.go
index 2905e581da..df22ccdc4e 100644
--- a/cmd/gapit/video.go
+++ b/cmd/gapit/video.go
@@ -228,12 +228,18 @@ func (verb *videoVerb) Run(ctx context.Context, flags flag.FlagSet) error {
 	case RegularVideo:
 		vidSrc = verb.regularVideoSource
 		vidOut = verb.encodeVideo
+	case SxsFrames:
+		fallthrough
 	case SxsVideo:
 		if len(fboEvents) == 0 {
 			return fmt.Errorf("Capture does not contain framebuffer observations")
 		}
 		vidSrc = verb.sxsVideoSource
-		vidOut = verb.encodeVideo
+		if verb.Type == SxsFrames {
+			vidOut = verb.writeFrames
+		} else {
+			vidOut = verb.encodeVideo
+		}
 	case AutoVideo:
 		if len(fboEvents) > 0 {
 			vidSrc = verb.sxsVideoSource

From 66c9922d32edc42a26e318bfd05368bd8b096e4f Mon Sep 17 00:00:00 2001
From: Chris Forbes 
Date: Thu, 5 Mar 2020 08:49:12 -0800
Subject: [PATCH 0139/1218] Replay profiler support for Mali

This builds on top of Adam's changes to support renderpass-level
linking. Mali is more troublesome in that we don't have a single
toplevel slice for each renderpass -- instead, we may have many slices
for the same renderpass instance scattered across the timeline.

To be completely robust, we need some additional identifier which
increments as we progress through a command buffer, and to have that
identifier included in all the slices originating from that command
buffer. This is the same thing we need in order to accurately attribute
compute slices to CmdDispatch in Adreno.
---
 gapis/api/vulkan/replay.go                 |   4 +-
 gapis/trace/android/mali/BUILD.bazel       |  12 +-
 gapis/trace/android/mali/profiling_data.go | 281 +++++++++++++++++++++
 gapis/trace/android/trace.go               |   2 +
 4 files changed, 297 insertions(+), 2 deletions(-)
 create mode 100644 gapis/trace/android/mali/profiling_data.go

diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go
index fb33bd5350..19bb91df21 100644
--- a/gapis/api/vulkan/replay.go
+++ b/gapis/api/vulkan/replay.go
@@ -1050,7 +1050,9 @@ func (a API) Replay(
 			makeReadable.imagesOnly = true
 			optimize = false
 			transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer))
-			transforms.Add(&profilingLayers{})
+			if strings.Contains(device.GetConfiguration().GetHardware().GetGPU().GetName(), "Adreno") {
+				transforms.Add(&profilingLayers{})
+			}
 			transforms.Add(replay.NewMappingExporter(ctx, req.handleMappings))
 		}
 	}
diff --git a/gapis/trace/android/mali/BUILD.bazel b/gapis/trace/android/mali/BUILD.bazel
index 1dd8da1cb7..be7b596e42 100644
--- a/gapis/trace/android/mali/BUILD.bazel
+++ b/gapis/trace/android/mali/BUILD.bazel
@@ -16,11 +16,21 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
 
 go_library(
     name = "go_default_library",
-    srcs = ["validate.go"],
+    srcs = [
+        "profiling_data.go",
+        "validate.go",
+    ],
     importpath = "github.com/google/gapid/gapis/trace/android/mali",
     visibility = ["//visibility:public"],
     deps = [
+        "//core/log:go_default_library",
+        "//core/os/device:go_default_library",
+        "//gapis/api:go_default_library",
+        "//gapis/api/sync:go_default_library",
         "//gapis/perfetto:go_default_library",
+        "//gapis/perfetto/service:go_default_library",
+        "//gapis/service:go_default_library",
+        "//gapis/service/path:go_default_library",
         "//gapis/trace/android/validate:go_default_library",
     ],
 )
diff --git a/gapis/trace/android/mali/profiling_data.go b/gapis/trace/android/mali/profiling_data.go
new file mode 100644
index 0000000000..ff10347a11
--- /dev/null
+++ b/gapis/trace/android/mali/profiling_data.go
@@ -0,0 +1,281 @@
+// Copyright (C) 2020 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mali
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/google/gapid/core/log"
+	"github.com/google/gapid/core/os/device"
+	"github.com/google/gapid/gapis/api"
+	"github.com/google/gapid/gapis/api/sync"
+	"github.com/google/gapid/gapis/perfetto"
+	perfetto_service "github.com/google/gapid/gapis/perfetto/service"
+	"github.com/google/gapid/gapis/service"
+	"github.com/google/gapid/gapis/service/path"
+)
+
+var (
+	slicesQuery = "" +
+		"SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " +
+		"FROM gpu_track t LEFT JOIN gpu_slice s " +
+		"ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage' ORDER BY s.ts"
+	argsQueryFmt = "" +
+		"SELECT key, string_value FROM args WHERE args.arg_set_id = %d"
+	queueSubmitQuery = "" +
+		"SELECT submission_id, command_buffer FROM gpu_slice s JOIN track t ON s.track_id = t.id WHERE s.name = 'vkQueueSubmit' AND t.name = 'Vulkan Events' ORDER BY submission_id"
+	counterTracksQuery = "" +
+		"SELECT id, name, unit, description FROM gpu_counter_track ORDER BY id"
+	countersQueryFmt = "" +
+		"SELECT ts, value FROM counter c WHERE c.track_id = %d ORDER BY ts"
+)
+
+func ProcessProfilingData(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, desc *device.GpuCounterDescriptor, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData, error) {
+	slices, err := processGpuSlices(ctx, processor, capture, handleMapping, syncData)
+	if err != nil {
+		log.Err(ctx, err, "Failed to get GPU slices")
+	}
+	counters, err := processCounters(ctx, processor, desc)
+	if err != nil {
+		log.Err(ctx, err, "Failed to get GPU counters")
+	}
+	return &service.ProfilingData{Slices: slices, Counters: counters}, nil
+}
+
+func extractTraceHandles(ctx context.Context, replayHandles *[]int64, replayHandleType string, handleMapping *map[uint64][]service.VulkanHandleMappingItem) {
+	for i, v := range *replayHandles {
+		handles, ok := (*handleMapping)[uint64(v)]
+		if !ok {
+			log.E(ctx, "%v not found in replay: %v", replayHandleType, v)
+			continue
+		}
+
+		found := false
+		for _, handle := range handles {
+			if handle.HandleType == replayHandleType {
+				(*replayHandles)[i] = int64(handle.TraceValue)
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			log.E(ctx, "Incorrect Handle type for %v: %v", replayHandleType, v)
+		}
+	}
+}
+
+func processGpuSlices(ctx context.Context, processor *perfetto.Processor, capture *path.Capture, handleMapping *map[uint64][]service.VulkanHandleMappingItem, syncData *sync.Data) (*service.ProfilingData_GpuSlices, error) {
+	slicesQueryResult, err := processor.Query(slicesQuery)
+	if err != nil {
+		return nil, log.Errf(ctx, err, "SQL query failed: %v", slicesQuery)
+	}
+
+	queueSubmitQueryResult, err := processor.Query(queueSubmitQuery)
+	if err != nil {
+		return nil, log.Errf(ctx, err, "SQL query failed: %v", queueSubmitQuery)
+	}
+	queueSubmitColumns := queueSubmitQueryResult.GetColumns()
+	queueSubmitIds := queueSubmitColumns[0].GetLongValues()
+	queueSubmitCommandBuffers := queueSubmitColumns[1].GetLongValues()
+	submissionOrdering := make(map[int64]uint64)
+
+	order := 0
+	for i, v := range queueSubmitIds {
+		if queueSubmitCommandBuffers[i] == 0 {
+			// This is a spurious submission. See b/150854367
+			log.W(ctx, "Spurious vkQueueSubmit slice with submission id %v", v)
+			continue
+		}
+		submissionOrdering[v] = uint64(order)
+		order++
+	}
+
+	trackIdCache := make(map[int64]bool)
+	argsQueryCache := make(map[int64]*perfetto_service.QueryResult)
+	slicesColumns := slicesQueryResult.GetColumns()
+	numSliceRows := slicesQueryResult.GetNumRecords()
+	slices := make([]*service.ProfilingData_GpuSlices_Slice, numSliceRows)
+	groups := make([]*service.ProfilingData_GpuSlices_Group, 0)
+	groupIds := make([]int32, numSliceRows)
+	var tracks []*service.ProfilingData_GpuSlices_Track
+	// Grab all the column values. Depends on the order of columns selected in slicesQuery
+
+	contextIds := slicesColumns[0].GetLongValues()
+	extractTraceHandles(ctx, &contextIds, "VkDevice", handleMapping)
+
+	renderTargets := slicesColumns[1].GetLongValues()
+	extractTraceHandles(ctx, &renderTargets, "VkFramebuffer", handleMapping)
+
+	commandBuffers := slicesColumns[5].GetLongValues()
+	extractTraceHandles(ctx, &commandBuffers, "VkCommandBuffer", handleMapping)
+
+	renderPasses := slicesColumns[6].GetLongValues()
+	extractTraceHandles(ctx, &renderPasses, "VkRenderPass", handleMapping)
+
+	frameIds := slicesColumns[2].GetLongValues()
+	submissionIds := slicesColumns[3].GetLongValues()
+	hwQueueIds := slicesColumns[4].GetLongValues()
+	timestamps := slicesColumns[7].GetLongValues()
+	durations := slicesColumns[8].GetLongValues()
+	names := slicesColumns[9].GetStringValues()
+	depths := slicesColumns[10].GetLongValues()
+	argSetIds := slicesColumns[11].GetLongValues()
+	trackIds := slicesColumns[12].GetLongValues()
+	trackNames := slicesColumns[13].GetStringValues()
+
+	for i, v := range submissionIds {
+		subOrder, ok := submissionOrdering[v]
+		if ok {
+			cb := uint64(commandBuffers[i])
+			key := api.CmdSubmissionKey{subOrder, cb, uint64(renderPasses[i]), uint64(renderTargets[i])}
+			if indices, ok := syncData.SubmissionIndices[key]; ok {
+				if names[i] == "vertex" || names[i] == "fragment" {
+					group := &service.ProfilingData_GpuSlices_Group{
+						Id:   int32(len(groups)),
+						Link: &path.Command{Capture: capture, Indices: indices[0]},
+					}
+					groups = append(groups, group)
+				}
+			}
+		} else {
+			log.W(ctx, "Encountered submission ID mismatch %v", v)
+		}
+
+		groupIds[i] = int32(len(groups)) - 1
+	}
+
+	for i := uint64(0); i < numSliceRows; i++ {
+		var argsQueryResult *perfetto_service.QueryResult
+		var ok bool
+		if argsQueryResult, ok = argsQueryCache[argSetIds[i]]; !ok {
+			argsQuery := fmt.Sprintf(argsQueryFmt, argSetIds[i])
+			argsQueryResult, err = processor.Query(argsQuery)
+			if err != nil {
+				log.W(ctx, "SQL query failed: %v", argsQuery)
+			}
+			argsQueryCache[argSetIds[i]] = argsQueryResult
+		}
+		argsColumns := argsQueryResult.GetColumns()
+		numArgsRows := argsQueryResult.GetNumRecords()
+		var extras []*service.ProfilingData_GpuSlices_Slice_Extra
+		for j := uint64(0); j < numArgsRows; j++ {
+			keys := argsColumns[0].GetStringValues()
+			values := argsColumns[1].GetStringValues()
+			extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+				Name:  keys[j],
+				Value: &service.ProfilingData_GpuSlices_Slice_Extra_StringValue{StringValue: values[j]},
+			})
+		}
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "contextId",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(contextIds[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "renderTarget",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(renderTargets[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "commandBuffer",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(commandBuffers[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "renderPass",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(renderPasses[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "frameId",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(frameIds[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "submissionId",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(submissionIds[i])},
+		})
+		extras = append(extras, &service.ProfilingData_GpuSlices_Slice_Extra{
+			Name:  "hwQueueId",
+			Value: &service.ProfilingData_GpuSlices_Slice_Extra_IntValue{IntValue: uint64(hwQueueIds[i])},
+		})
+
+		if (names[i] == "vertex" || names[i] == "fragment") && groupIds[i] != -1 {
+			names[i] = fmt.Sprintf("%v %v", groups[groupIds[i]].Link.Indices, names[i])
+		}
+
+		slices[i] = &service.ProfilingData_GpuSlices_Slice{
+			Ts:      uint64(timestamps[i]),
+			Dur:     uint64(durations[i]),
+			Label:   names[i],
+			Depth:   int32(depths[i]),
+			Extras:  extras,
+			TrackId: int32(trackIds[i]),
+			GroupId: groupIds[i],
+		}
+
+		if _, ok := trackIdCache[trackIds[i]]; !ok {
+			trackIdCache[trackIds[i]] = true
+			tracks = append(tracks, &service.ProfilingData_GpuSlices_Track{
+				Id:   int32(trackIds[i]),
+				Name: trackNames[i],
+			})
+		}
+	}
+
+	return &service.ProfilingData_GpuSlices{
+		Slices: slices,
+		Tracks: tracks,
+		Groups: groups,
+	}, nil
+}
+
+func processCounters(ctx context.Context, processor *perfetto.Processor, desc *device.GpuCounterDescriptor) ([]*service.ProfilingData_Counter, error) {
+	counterTracksQueryResult, err := processor.Query(counterTracksQuery)
+	if err != nil {
+		return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
+	}
+	// t.id, name, unit, description, ts, value
+	tracksColumns := counterTracksQueryResult.GetColumns()
+	numTracksRows := counterTracksQueryResult.GetNumRecords()
+	counters := make([]*service.ProfilingData_Counter, numTracksRows)
+	// Grab all the column values. Depends on the order of columns selected in countersQuery
+	trackIds := tracksColumns[0].GetLongValues()
+	names := tracksColumns[1].GetStringValues()
+	units := tracksColumns[2].GetStringValues()
+	descriptions := tracksColumns[3].GetStringValues()
+
+	for i := uint64(0); i < numTracksRows; i++ {
+		countersQuery := fmt.Sprintf(countersQueryFmt, trackIds[i])
+		countersQueryResult, err := processor.Query(countersQuery)
+		countersColumns := countersQueryResult.GetColumns()
+		if err != nil {
+			return nil, log.Errf(ctx, err, "SQL query failed: %v", counterTracksQuery)
+		}
+		timestampsLong := countersColumns[0].GetLongValues()
+		timestamps := make([]uint64, len(timestampsLong))
+		for i, t := range timestampsLong {
+			timestamps[i] = uint64(t)
+		}
+		values := countersColumns[1].GetDoubleValues()
+		// TODO(apbodnar) Populate the `default` field once the trace processor supports it (b/147432390)
+		counters[i] = &service.ProfilingData_Counter{
+			Id:          uint32(trackIds[i]),
+			Name:        names[i],
+			Unit:        units[i],
+			Description: descriptions[i],
+			Timestamps:  timestamps,
+			Values:      values,
+		}
+	}
+	return counters, nil
+}
diff --git a/gapis/trace/android/trace.go b/gapis/trace/android/trace.go
index 593cdf3ab0..75d2f859cb 100644
--- a/gapis/trace/android/trace.go
+++ b/gapis/trace/android/trace.go
@@ -141,6 +141,8 @@ func (t *androidTracer) ProcessProfilingData(ctx context.Context, buffer *bytes.
 	gpuName := gpu.GetName()
 	if strings.Contains(gpuName, "Adreno") {
 		return adreno.ProcessProfilingData(ctx, processor, capture, desc, handleMappings, syncData)
+	} else if strings.Contains(gpuName, "Mali") {
+		return mali.ProcessProfilingData(ctx, processor, capture, desc, handleMappings, syncData)
 	}
 	return nil, log.Errf(ctx, nil, "Failed to process Perfetto trace for device %v", gpuName)
 }

From 105d9d884e329ece544d1316eec5fdef6130933a Mon Sep 17 00:00:00 2001
From: Pascal Muetschard 
Date: Mon, 9 Mar 2020 20:00:14 -0700
Subject: [PATCH 0140/1218] Move the logo files out of gapic into a shared
 location.

---
 gapic/res/BUILD.bazel                         |  24 ++++++++++++++++--
 gapic/res/icons/logo_128@2x.png               | Bin 27405 -> 0 bytes
 kokoro/linux/package.sh                       |   2 +-
 kokoro/macos/package.sh                       |   4 +--
 tools/logo/BUILD.bazel                        |  15 +++++++++++
 {gapic/res/icons => tools/logo}/logo_1024.png | Bin
 {gapic/res/icons => tools/logo}/logo_128.png  | Bin
 {gapic/res/icons => tools/logo}/logo_16.png   | Bin
 {gapic/res/icons => tools/logo}/logo_256.png  | Bin
 {gapic/res/icons => tools/logo}/logo_32.png   | Bin
 {gapic/res/icons => tools/logo}/logo_48.png   | Bin
 {gapic/res/icons => tools/logo}/logo_512.png  | Bin
 {gapic/res/icons => tools/logo}/logo_64.png   | Bin
 13 files changed, 40 insertions(+), 5 deletions(-)
 delete mode 100644 gapic/res/icons/logo_128@2x.png
 create mode 100644 tools/logo/BUILD.bazel
 rename {gapic/res/icons => tools/logo}/logo_1024.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_128.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_16.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_256.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_32.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_48.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_512.png (100%)
 rename {gapic/res/icons => tools/logo}/logo_64.png (100%)

diff --git a/gapic/res/BUILD.bazel b/gapic/res/BUILD.bazel
index 7277f65f17..cb4bbb1a76 100644
--- a/gapic/res/BUILD.bazel
+++ b/gapic/res/BUILD.bazel
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("//tools/build:rules.bzl", "copy_tree")
+load("//tools/build:rules.bzl", "copy_to", "copy_tree")
 
 # This is an ugly ugly hack
 # The bazel resource rules expect a specific directory structure, so we copy_resources
@@ -24,8 +24,28 @@ copy_tree(
     to = "java",
 )
 
+copy_to(
+    name = "copy_logo",
+    # buildifier: leave-alone
+    srcs = [
+        "//tools/logo:logo_16.png",
+        "//tools/logo:logo_32.png",
+        "//tools/logo:logo_48.png",
+        "//tools/logo:logo_64.png",
+        "//tools/logo:logo_128.png",
+        "//tools/logo:logo_256.png",
+    ],
+    rename = {
+        "logo_256.png": "logo_128@2x.png",
+    },
+    to = "java/icons",
+)
+
 java_library(
     name = "res",
-    resources = [":copy_resources"],
+    resources = [
+        ":copy_logo",
+        ":copy_resources",
+    ],
     visibility = ["//visibility:public"],
 )
diff --git a/gapic/res/icons/logo_128@2x.png b/gapic/res/icons/logo_128@2x.png
deleted file mode 100644
index 81dbed512d289afb4114ba3a89e3eed21bc84e04..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 27405
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 diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh index 6228dce558..fe853391c1 100755 --- a/kokoro/linux/package.sh +++ b/kokoro/linux/package.sh @@ -46,7 +46,7 @@ VERSION=$(awk -F= 'BEGIN {major=0; minor=0; micro=0} # Combine package contents. mkdir -p agi/DEBIAN agi/opt/agi agi/usr/share/applications agi/usr/share/menu agi/usr/share/mime/packages cp -r $BIN/pkg/* agi/opt/agi -cp "$SRC/../../gapic/res/icons/logo_256.png" agi/opt/agi/icon.png +cp "$SRC/../../tools/logo/logo_256.png" agi/opt/agi/icon.png cp "$SRC/gapid.desktop" agi/usr/share/applications/google-agi.desktop cp "$SRC/gapid.menu" agi/usr/share/menu/google-agi.menu cp "$SRC/gapid-mime.xml" agi/usr/share/mime/packages/agi.xml diff --git a/kokoro/macos/package.sh b/kokoro/macos/package.sh index 872d07edb8..d41923a793 100755 --- a/kokoro/macos/package.sh +++ b/kokoro/macos/package.sh @@ -58,8 +58,8 @@ cp "$SRC/Info.plist" AGI.app/Contents/ mkdir -p AGI.iconset AGI.app/Contents/Resources for i in 512 256 128 64 32 16; do - cp "$SRC/../../gapic/res/icons/logo_${i}.png" AGI.iconset/icon_${i}x${i}.png - cp "$SRC/../../gapic/res/icons/logo_$((i*2)).png" AGI.iconset/icon_${i}x${i}\@2x.png + cp "$SRC/../../tools/logo/logo_${i}.png" AGI.iconset/icon_${i}x${i}.png + cp "$SRC/../../tools/logo/logo_$((i*2)).png" AGI.iconset/icon_${i}x${i}\@2x.png done iconutil -c icns -o AGI.app/Contents/Resources/AGI.icns AGI.iconset diff --git a/tools/logo/BUILD.bazel b/tools/logo/BUILD.bazel new file mode 100644 index 0000000000..b6ae81d5ac --- /dev/null +++ b/tools/logo/BUILD.bazel @@ -0,0 +1,15 @@ +# Copyright (C) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +exports_files(glob(["*.png"])) diff --git a/gapic/res/icons/logo_1024.png b/tools/logo/logo_1024.png similarity index 100% rename from gapic/res/icons/logo_1024.png rename to tools/logo/logo_1024.png diff --git a/gapic/res/icons/logo_128.png b/tools/logo/logo_128.png similarity index 100% rename from gapic/res/icons/logo_128.png rename to tools/logo/logo_128.png diff --git a/gapic/res/icons/logo_16.png b/tools/logo/logo_16.png similarity index 100% rename from gapic/res/icons/logo_16.png rename to tools/logo/logo_16.png diff --git a/gapic/res/icons/logo_256.png b/tools/logo/logo_256.png similarity index 100% rename from gapic/res/icons/logo_256.png rename to tools/logo/logo_256.png diff --git a/gapic/res/icons/logo_32.png b/tools/logo/logo_32.png similarity index 100% rename from gapic/res/icons/logo_32.png rename to tools/logo/logo_32.png diff --git a/gapic/res/icons/logo_48.png b/tools/logo/logo_48.png similarity index 100% rename from gapic/res/icons/logo_48.png rename to tools/logo/logo_48.png diff --git a/gapic/res/icons/logo_512.png b/tools/logo/logo_512.png similarity index 100% rename from gapic/res/icons/logo_512.png rename to tools/logo/logo_512.png diff --git a/gapic/res/icons/logo_64.png b/tools/logo/logo_64.png similarity index 100% rename from gapic/res/icons/logo_64.png rename to tools/logo/logo_64.png From 4b5201a4d87562990b4f652ada0b050b7b90da23 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 3 Mar 2020 14:46:24 -0800 Subject: [PATCH 0141/1218] Adds a new img2h rule that generates C++ headers from images. --- cmd/img2h/BUILD.bazel | 33 ++++++++++++ cmd/img2h/main.go | 102 +++++++++++++++++++++++++++++++++++ tools/build/rules.bzl | 4 ++ tools/build/rules/images.bzl | 47 ++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 cmd/img2h/BUILD.bazel create mode 100644 cmd/img2h/main.go create mode 100644 tools/build/rules/images.bzl diff --git a/cmd/img2h/BUILD.bazel b/cmd/img2h/BUILD.bazel new file mode 100644 index 0000000000..69996a5134 --- /dev/null +++ b/cmd/img2h/BUILD.bazel @@ -0,0 +1,33 @@ +# Copyright (C) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//tools/build:rules.bzl", "go_stripped_binary") +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["main.go"], + importpath = "github.com/google/gapid/cmd/img2h", + visibility = ["//visibility:private"], + deps = [ + "//core/app:go_default_library", + "//core/log:go_default_library", + ], +) + +go_stripped_binary( + name = "img2h", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) diff --git a/cmd/img2h/main.go b/cmd/img2h/main.go new file mode 100644 index 0000000000..8af7e5bee8 --- /dev/null +++ b/cmd/img2h/main.go @@ -0,0 +1,102 @@ +// Copyright (C) 2020 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// img2h is a utility program that creates C++ headers containing image data. +// It is usefull to embed texture data within a binary to simplify loading. +package main + +import ( + "context" + "flag" + "fmt" + "image" + "image/color" + "os" + + "github.com/google/gapid/core/app" + "github.com/google/gapid/core/log" + + // Import to register image formats. + _ "image/gif" + _ "image/jpeg" + _ "image/png" +) + +var ( + out = flag.String("out", "-", "Output file, '-' for stdout") +) + +func main() { + app.ShortHelp = "img2h generates C++ headers containing image data" + app.Name = "img2h" + app.Run(run) +} + +func run(ctx context.Context) error { + if flag.NArg() != 1 { + app.Usage(ctx, "Exactly one image file expected, got %d", flag.NArg()) + return nil + } + + in, err := os.Open(flag.Arg(0)) + if err != nil { + return log.Errf(ctx, err, "Failed to open %s", flag.Arg(0)) + } + defer in.Close() + + img, _, err := image.Decode(in) + if err != nil { + return log.Errf(ctx, err, "Failed to decode image") + } + + width, height := img.Bounds().Dx(), img.Bounds().Dy() + model := color.RGBAModel + + o := os.Stdout + if *out != "-" { + o, err = os.Create(*out) + if err != nil { + return log.Errf(ctx, err, "Failed to create %s", *out) + } + defer o.Close() + } + + fmt.Fprintf(o, "const struct {\n") + fmt.Fprintf(o, " VkFormat format;\n") + fmt.Fprintf(o, " size_t width;\n") + fmt.Fprintf(o, " size_t height;\n") + fmt.Fprintf(o, " struct {\n") + fmt.Fprintf(o, " uint8_t r;\n") + fmt.Fprintf(o, " uint8_t g;\n") + fmt.Fprintf(o, " uint8_t b;\n") + fmt.Fprintf(o, " uint8_t a;\n") + fmt.Fprintf(o, " } data[%d];\n", width*height) + fmt.Fprintf(o, "} texture = {\n") + fmt.Fprintf(o, " VK_FORMAT_R8G8B8A8_UNORM,\n") + fmt.Fprintf(o, " %d,\n", width) + fmt.Fprintf(o, " %d,\n", height) + fmt.Fprintf(o, " {\n") + + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + p := model.Convert(img.At(x, y)).(color.RGBA) + fmt.Fprintf(o, "{%d, %d, %d, %d}, ", p.R, p.G, p.B, 255) + } + fmt.Fprintf(o, "\n") + } + + fmt.Fprintf(o, " }\n") + fmt.Fprintf(o, "};\n") + return nil +} diff --git a/tools/build/rules.bzl b/tools/build/rules.bzl index 3778831586..f7f90d4b7e 100644 --- a/tools/build/rules.bzl +++ b/tools/build/rules.bzl @@ -42,6 +42,9 @@ load("//tools/build/rules:embed.bzl", load("//tools/build/rules:filehash.bzl", _filehash = "filehash", ) +load("//tools/build/rules:images.bzl", + _img2h = "img2h", +) load("//tools/build/rules:jni.bzl", _jni_library = "jni_library", ) @@ -89,6 +92,7 @@ android_dynamic_library = _android_dynamic_library cc_dynamic_library = _cc_dynamic_library embed = _embed filehash = _filehash +img2h = _img2h jni_library = _jni_library api_library = _api_library api_template = _api_template diff --git a/tools/build/rules/images.bzl b/tools/build/rules/images.bzl new file mode 100644 index 0000000000..9d9ac63da8 --- /dev/null +++ b/tools/build/rules/images.bzl @@ -0,0 +1,47 @@ +# Copyright (C) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +def _img2h_impl(ctx): + outs = [] + for img in ctx.files.srcs: + n = img.basename + out = ctx.actions.declare_file(n[0:len(n) - len(img.extension)] + "h") + ctx.actions.run( + inputs = [img], + outputs = [out], + arguments = ["-out", out.path, img.path], + executable = ctx.executable._img2h, + use_default_shell_env = True, + ) + outs += [out] + return [ + DefaultInfo(files = depset(outs)), + ] + +img2h = rule( + _img2h_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + ), + "_img2h": attr.label( + cfg = "host", + executable = True, + allow_files = True, + default = Label("//cmd/img2h"), + ), + }, + output_to_genfiles = True, +) From b0351d689e55f7a4a09e72e97881ac19a79cc844 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 11 Mar 2020 12:23:12 -0700 Subject: [PATCH 0142/1218] Generate the texture for the sample app from the logo image. This avoids having a duplicate copy of the image checked in. --- cmd/vulkan_sample/BUILD.bazel | 3 +- cmd/vulkan_sample/icon.h | 286 ---------------------------------- cmd/vulkan_sample/main.cpp | 2 +- tools/logo/BUILD.bazel | 8 + 4 files changed, 10 insertions(+), 289 deletions(-) delete mode 100644 cmd/vulkan_sample/icon.h diff --git a/cmd/vulkan_sample/BUILD.bazel b/cmd/vulkan_sample/BUILD.bazel index e38b4b3acd..b7d001d03d 100644 --- a/cmd/vulkan_sample/BUILD.bazel +++ b/cmd/vulkan_sample/BUILD.bazel @@ -19,10 +19,9 @@ cc_library( srcs = [ "cube.h", "frag.h", - "icon.h", "main.cpp", "vert.h", - ], + ] + ["//tools/logo:logo_256_h"], copts = cc_copts(), linkopts = select({ "//tools/build:linux": [ diff --git a/cmd/vulkan_sample/icon.h b/cmd/vulkan_sample/icon.h deleted file mode 100644 index 5b267e78f9..0000000000 --- a/cmd/vulkan_sample/icon.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2019 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// You can use convert_img_to_c in github.com/google/vulkan_test_applications -// to regenerate this file. -// clang-format off - -const struct { - VkFormat format; - size_t width; size_t height; struct {uint8_t r; uint8_t g; uint8_t b; uint8_t a;} data[65536]; -} texture = { - VK_FORMAT_R8G8B8A8_UNORM, - 256, - 256, - { - {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {255, 255, 255, 1}, {73, 73, 109, 7}, {73, 91, 109, 14}, {71, 85, 99, 18}, {85, 97, 109, 21}, {70, 81, 93, 22}, {78, 88, 98, 26}, {73, 91, 100, 28}, {77, 85, 94, 30}, {77, 85, 94, 30}, {76, 94, 94, 27}, {82, 92, 102, 25}, {70, 81, 93, 22}, {77, 89, 89, 20}, {71, 85, 99, 18}, {73, 91, 91, 14}, {85, 85, 85, 6}, {255, 255, 255, 1}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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}, {57, 85, 85, 9}, {74, 91, 96, 45}, {74, 90, 97, 79}, {75, 89, 96, 112}, {76, 90, 98, 145}, {74, 88, 96, 176}, {76, 90, 98, 201}, {75, 90, 97, 219}, {75, 89, 98, 237}, {75, 90, 97, 253}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {74, 89, 96, 252}, {74, 89, 95, 235}, {74, 88, 95, 218}, {73, 88, 94, 200}, {73, 88, 95, 174}, {74, 88, 95, 142}, {73, 84, 94, 109}, {74, 87, 94, 76}, {73, 85, 97, 42}, {64, 96, 96, 8}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {85, 85, 85, 3}, {74, 91, 96, 45}, {75, 91, 97, 92}, {75, 90, 97, 139}, {75, 89, 98, 183}, {76, 90, 97, 226}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 254}, {74, 89, 96, 223}, {85, 105, 112, 180}, {87, 104, 113, 135}, {86, 106, 112, 89}, {87, 106, 112, 41}, {128, 128, 128, 2}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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}, {77, 89, 89, 20}, {76, 91, 98, 81}, {75, 88, 97, 142}, {76, 90, 97, 199}, {75, 90, 97, 247}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {79, 96, 105, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {86, 105, 114, 245}, {84, 103, 112, 195}, {84, 102, 112, 137}, {86, 106, 116, 77}, {90, 105, 120, 17}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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}, {73, 91, 109, 14}, {77, 92, 98, 86}, {74, 89, 97, 158}, {75, 89, 98, 217}, {74, 89, 96, 254}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {74, 89, 96, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {86, 105, 114, 253}, {84, 104, 114, 213}, {85, 105, 113, 153}, {86, 105, 115, 80}, {77, 102, 102, 10}, {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, 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, 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, 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}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {71, 87, 97, 50}, {76, 90, 99, 124}, {75, 89, 97, 195}, {75, 90, 98, 250}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {82, 100, 108, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 104, 113, 248}, {85, 103, 113, 190}, {84, 105, 114, 119}, {87, 104, 116, 44}, {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, 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, 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, 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}, - {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, 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, 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, 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}, {74, 88, 93, 52}, {75, 89, 97, 140}, {74, 89, 97, 223}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {75, 92, 99, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {85, 102, 113, 217}, {84, 105, 113, 133}, {85, 102, 113, 45}, {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, 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, 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, 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}, {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, 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, 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, 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}, {74, 91, 96, 45}, {76, 89, 97, 137}, {74, 89, 97, 220}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 87, 95, 255}, {83, 102, 111, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {85, 104, 113, 213}, {82, 104, 114, 130}, {81, 101, 114, 38}, {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, 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, 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, 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}, {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, 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, 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, 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}, {93, 93, 116, 11}, {75, 88, 95, 102}, {75, 89, 98, 201}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {78, 95, 103, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 254}, {83, 104, 112, 193}, {85, 104, 112, 93}, {73, 109, 109, 7}, {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, 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, 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, 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}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 87, 96, 53}, {75, 90, 98, 156}, {75, 91, 97, 242}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {74, 89, 96, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 111, 238}, {83, 102, 112, 148}, {85, 102, 113, 45}, {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, 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, 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, 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}, {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, 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, 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}, {255, 255, 255, 1}, {75, 90, 96, 82}, {74, 88, 96, 196}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {80, 98, 106, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {85, 104, 112, 189}, {84, 105, 115, 73}, {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, 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, 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, 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}, {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, 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, 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}, {64, 96, 96, 8}, {76, 91, 98, 107}, {75, 89, 97, 218}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {74, 90, 97, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 103, 111, 211}, {84, 103, 110, 97}, {102, 102, 102, 5}, {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, 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, 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, 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}, {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, 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, 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}, {57, 85, 85, 9}, {75, 90, 96, 122}, {76, 89, 98, 235}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {83, 100, 109, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 112, 229}, {83, 101, 110, 111}, {85, 128, 128, 6}, {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, 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, 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, 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}, {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, 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, 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}, {73, 73, 109, 7}, {73, 88, 97, 116}, {76, 90, 97, 233}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {77, 93, 102, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {83, 101, 111, 227}, {85, 102, 112, 105}, {102, 102, 102, 5}, {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, 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, 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, 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}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 128, 128, 4}, {77, 88, 97, 110}, {75, 90, 97, 229}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 95, 255}, {83, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 223}, {84, 102, 112, 100}, {128, 128, 128, 2}, {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, 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, 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, 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}, {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, 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, 0, 0}, {0, 0, 0, 0}, {75, 90, 98, 65}, {75, 90, 97, 213}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {78, 95, 104, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 206}, {83, 102, 111, 55}, {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, 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, 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, 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}, {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, 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}, {78, 89, 100, 23}, {75, 91, 97, 166}, {75, 89, 96, 254}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {74, 89, 97, 255}, {85, 103, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {83, 102, 111, 253}, {83, 101, 111, 154}, {90, 105, 120, 17}, {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, 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, 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, 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}, {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, 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}, {128, 128, 128, 2}, {76, 90, 96, 111}, {76, 91, 97, 239}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {82, 99, 108, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {83, 102, 111, 234}, {82, 103, 111, 99}, {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, 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, 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, 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}, {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, 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}, {77, 91, 100, 56}, {75, 90, 96, 207}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {76, 92, 100, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {83, 102, 111, 197}, {78, 100, 111, 46}, {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, 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, 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, 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}, {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, 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}, {71, 85, 99, 18}, {75, 88, 96, 156}, {75, 90, 97, 253}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {83, 100, 110, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 112, 251}, {81, 103, 110, 144}, {85, 106, 106, 12}, {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, 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, 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, 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}, {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, 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}, {77, 88, 95, 99}, {76, 90, 98, 235}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {78, 94, 103, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 111, 229}, {83, 101, 113, 86}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {78, 98, 98, 13}, {75, 89, 96, 170}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 96, 255}, {84, 103, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 102, 112, 155}, {96, 96, 128, 8}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {71, 87, 97, 50}, {75, 90, 97, 219}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {80, 97, 105, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 111, 210}, {83, 102, 108, 40}, {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, 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, 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, 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}, {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, 0, 0, 0}, {76, 90, 97, 108}, {76, 90, 98, 247}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {75, 91, 98, 255}, {85, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 102, 111, 243}, {83, 103, 111, 92}, {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, 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, 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, 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}, {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}, {73, 91, 109, 14}, {75, 89, 97, 171}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {82, 100, 108, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 157}, {85, 113, 113, 9}, {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, 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, 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, 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}, {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}, {74, 88, 93, 52}, {75, 89, 97, 221}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {77, 93, 101, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 111, 212}, {81, 100, 112, 41}, {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, 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, 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, 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}, {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}, {77, 88, 97, 110}, {75, 90, 97, 247}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 95, 255}, {83, 102, 111, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 243}, {81, 102, 113, 95}, {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, 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, 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, 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}, {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}, {73, 73, 109, 7}, {75, 89, 97, 171}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {80, 96, 104, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 99, 109, 157}, {128, 128, 128, 4}, {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, 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, 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, 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}, {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}, {85, 85, 102, 15}, {75, 90, 98, 196}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {74, 90, 97, 255}, {85, 103, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 111, 182}, {85, 113, 113, 9}, {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, 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, 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, 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}, {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}, {71, 92, 102, 25}, {75, 90, 97, 210}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {81, 98, 107, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {82, 101, 111, 199}, {75, 90, 105, 17}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {74, 87, 94, 38}, {74, 89, 97, 223}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {75, 91, 99, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 100, 111, 214}, {82, 100, 109, 28}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 87, 96, 53}, {76, 89, 97, 234}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {83, 101, 110, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {81, 102, 111, 226}, {79, 103, 109, 42}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 90, 97, 71}, {76, 90, 97, 243}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {78, 94, 103, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 237}, {79, 101, 110, 58}, {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, 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, 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, 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}, {77, 91, 99, 90}, {76, 90, 98, 248}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {82, 100, 110, 244}, {82, 102, 112, 75}, {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, 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, 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, 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}, {75, 89, 96, 112}, {75, 90, 97, 253}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {81, 97, 106, 255}, {85, 104, 113, 255}, {86, 105, 114, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {85, 104, 113, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {84, 103, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {83, 102, 112, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {81, 100, 110, 250}, {81, 102, 113, 95}, {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, 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, 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, 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}, {75, 89, 96, 112}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 90, 97, 255}, {90, 134, 140, 255}, {95, 160, 166, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {96, 163, 168, 255}, {95, 162, 168, 255}, {96, 163, 168, 255}, {95, 162, 168, 255}, {96, 163, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {94, 162, 167, 255}, {95, 162, 168, 255}, {95, 162, 168, 255}, {95, 163, 168, 255}, {100, 169, 175, 255}, {100, 169, 175, 255}, {100, 169, 175, 255}, {100, 169, 175, 255}, {100, 169, 175, 255}, {99, 169, 175, 255}, {100, 169, 175, 255}, {100, 169, 175, 255}, {99, 169, 175, 255}, {99, 169, 175, 255}, {99, 169, 175, 255}, {100, 169, 175, 255}, {99, 169, 175, 255}, {99, 169, 175, 255}, {99, 169, 175, 255}, {99, 169, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 169, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {99, 168, 175, 255}, {98, 168, 174, 255}, {98, 168, 174, 255}, {99, 168, 175, 255}, {98, 168, 174, 255}, {98, 168, 174, 255}, {98, 168, 174, 255}, {98, 168, 174, 255}, {97, 168, 174, 255}, {98, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {98, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {97, 168, 174, 255}, {96, 163, 170, 255}, {87, 133, 141, 255}, {78, 97, 106, 255}, {81, 100, 110, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 254}, {82, 101, 112, 93}, {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, 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, 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, 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}, {77, 91, 99, 90}, {75, 90, 97, 253}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {122, 184, 189, 255}, {143, 252, 255, 255}, {72, 237, 253, 255}, {46, 214, 232, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {82, 166, 176, 255}, {77, 95, 104, 255}, {82, 100, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {81, 100, 110, 250}, {83, 103, 110, 74}, {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, 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, 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, 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}, {75, 90, 97, 71}, {75, 90, 97, 248}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {95, 135, 140, 255}, {161, 231, 240, 255}, {166, 255, 255, 255}, {100, 244, 255, 255}, {44, 233, 255, 255}, {52, 233, 250, 255}, {38, 205, 225, 255}, {25, 194, 216, 255}, {26, 193, 215, 255}, {25, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {89, 129, 135, 255}, {79, 97, 106, 255}, {82, 102, 111, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {82, 100, 110, 244}, {77, 100, 109, 56}, {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, 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, 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, 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}, {72, 87, 96, 53}, {76, 90, 97, 243}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 91, 98, 255}, {146, 214, 221, 255}, {149, 228, 237, 255}, {165, 255, 255, 255}, {141, 254, 255, 255}, {70, 237, 255, 255}, {28, 231, 255, 255}, {29, 232, 255, 255}, {54, 228, 245, 255}, {31, 196, 218, 255}, {25, 192, 214, 255}, {26, 193, 214, 255}, {25, 193, 215, 255}, {26, 193, 215, 255}, {25, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {64, 189, 202, 255}, {76, 94, 102, 255}, {81, 100, 109, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 99, 109, 236}, {81, 100, 112, 41}, {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, 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, 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, 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}, {74, 87, 94, 38}, {75, 89, 96, 234}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {107, 161, 166, 255}, {158, 229, 238, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {115, 247, 255, 255}, {52, 234, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {36, 233, 254, 255}, {51, 219, 236, 255}, {26, 193, 213, 255}, {25, 192, 213, 255}, {26, 193, 213, 255}, {26, 193, 214, 255}, {26, 193, 215, 255}, {26, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {93, 151, 157, 255}, {77, 96, 104, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 101, 110, 225}, {82, 100, 109, 28}, {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, 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, 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, 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}, {71, 92, 102, 25}, {75, 90, 97, 224}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {81, 103, 110, 255}, {156, 226, 233, 255}, {144, 226, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {78, 238, 255, 255}, {34, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {45, 233, 252, 255}, {45, 210, 228, 255}, {25, 191, 213, 255}, {25, 191, 213, 255}, {26, 193, 213, 255}, {25, 192, 214, 255}, {25, 193, 215, 255}, {26, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {42, 192, 210, 255}, {80, 101, 110, 255}, {80, 99, 108, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {81, 101, 109, 213}, {75, 90, 105, 17}, {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, 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, 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, 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}, {85, 85, 102, 15}, {76, 89, 98, 211}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {121, 183, 188, 255}, {155, 228, 237, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {128, 250, 254, 255}, {60, 234, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 232, 255, 255}, {52, 230, 247, 255}, {36, 202, 221, 255}, {26, 190, 212, 255}, {26, 192, 213, 255}, {26, 193, 213, 255}, {25, 192, 214, 255}, {26, 193, 215, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {90, 171, 178, 255}, {77, 95, 103, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {80, 99, 108, 198}, {85, 113, 113, 9}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 73, 109, 7}, {75, 90, 98, 196}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {88, 122, 127, 255}, {160, 230, 239, 255}, {142, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {89, 241, 255, 255}, {41, 232, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {30, 233, 255, 255}, {55, 225, 241, 255}, {29, 194, 213, 255}, {27, 191, 212, 255}, {25, 191, 213, 255}, {26, 193, 213, 255}, {25, 192, 214, 255}, {26, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {22, 193, 213, 255}, {84, 116, 123, 255}, {79, 97, 107, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {80, 99, 108, 181}, {85, 170, 170, 3}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 89, 97, 171}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {135, 204, 210, 255}, {151, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {137, 253, 255, 255}, {65, 235, 255, 255}, {27, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {36, 233, 254, 255}, {52, 218, 234, 255}, {26, 190, 211, 255}, {25, 191, 213, 255}, {26, 192, 212, 255}, {25, 192, 214, 255}, {25, 193, 215, 255}, {26, 193, 215, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {77, 185, 195, 255}, {76, 94, 102, 255}, {81, 100, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {80, 100, 108, 153}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {77, 88, 97, 110}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {99, 146, 151, 255}, {160, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {106, 245, 253, 255}, {47, 233, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {45, 232, 250, 255}, {44, 208, 226, 255}, {26, 190, 211, 255}, {26, 192, 213, 255}, {26, 193, 213, 255}, {26, 193, 214, 255}, {25, 193, 215, 255}, {25, 193, 215, 255}, {25, 194, 216, 255}, {26, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {89, 136, 143, 255}, {77, 96, 104, 255}, {82, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 101, 109, 91}, {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, 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, 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, 0}, {0, 0, 0, 0}, {75, 90, 95, 51}, {75, 90, 97, 247}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {78, 96, 102, 255}, {149, 219, 227, 255}, {148, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {141, 254, 254, 255}, {73, 237, 255, 255}, {30, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 232, 255, 255}, {52, 229, 246, 255}, {36, 200, 219, 255}, {26, 190, 212, 255}, {25, 191, 213, 255}, {25, 192, 213, 255}, {26, 193, 214, 255}, {25, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {56, 192, 206, 255}, {77, 97, 105, 255}, {80, 100, 108, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {80, 100, 109, 242}, {85, 105, 111, 39}, {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, 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, 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}, {73, 91, 109, 14}, {75, 89, 97, 221}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {112, 170, 174, 255}, {157, 228, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {118, 247, 253, 255}, {55, 234, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {30, 232, 254, 255}, {53, 224, 240, 255}, {29, 193, 213, 255}, {26, 190, 212, 255}, {25, 191, 212, 255}, {25, 192, 213, 255}, {25, 192, 214, 255}, {25, 193, 215, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {91, 158, 165, 255}, {78, 95, 104, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {81, 100, 110, 209}, {73, 109, 109, 7}, {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, 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, 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}, {75, 89, 97, 171}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {84, 110, 116, 255}, {159, 228, 236, 255}, {144, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 254, 254, 255}, {82, 238, 254, 255}, {36, 232, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {37, 233, 253, 255}, {50, 215, 232, 255}, {27, 191, 211, 255}, {25, 191, 213, 255}, {25, 191, 212, 255}, {25, 192, 214, 255}, {25, 193, 215, 255}, {25, 193, 215, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {32, 193, 212, 255}, {80, 106, 114, 255}, {78, 98, 107, 255}, {81, 101, 110, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {80, 100, 108, 153}, {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, 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, 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}, {74, 88, 95, 107}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {127, 192, 197, 255}, {153, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {130, 249, 252, 255}, {61, 235, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {45, 232, 250, 255}, {43, 207, 225, 255}, {26, 190, 211, 255}, {25, 191, 213, 255}, {25, 192, 213, 255}, {25, 192, 214, 255}, {24, 193, 215, 255}, {24, 193, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {85, 176, 185, 255}, {76, 93, 101, 255}, {81, 100, 109, 255}, {82, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {80, 100, 109, 89}, {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, 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, 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}, {71, 87, 97, 50}, {75, 90, 97, 247}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {93, 131, 136, 255}, {161, 230, 238, 255}, {141, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {96, 241, 253, 255}, {43, 233, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 232, 255, 255}, {52, 227, 245, 255}, {34, 199, 218, 255}, {26, 190, 212, 255}, {24, 191, 213, 255}, {25, 192, 213, 255}, {25, 192, 214, 255}, {24, 193, 215, 255}, {25, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {86, 123, 131, 255}, {78, 97, 105, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 241}, {78, 99, 106, 36}, {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, 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, 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}, {78, 98, 98, 13}, {76, 91, 97, 219}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 90, 98, 255}, {140, 211, 218, 255}, {149, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {138, 252, 253, 255}, {67, 236, 255, 255}, {27, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {31, 232, 254, 255}, {52, 223, 239, 255}, {28, 192, 213, 255}, {25, 190, 212, 255}, {25, 191, 212, 255}, {24, 192, 213, 255}, {24, 192, 214, 255}, {24, 193, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {67, 188, 199, 255}, {75, 93, 101, 255}, {81, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 207}, {73, 109, 109, 7}, {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, 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, 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}, {75, 89, 96, 170}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {104, 154, 160, 255}, {158, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {110, 245, 252, 255}, {51, 233, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {39, 233, 253, 255}, {48, 214, 231, 255}, {25, 190, 211, 255}, {25, 191, 213, 255}, {24, 191, 212, 255}, {24, 192, 214, 255}, {24, 193, 215, 255}, {24, 193, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {91, 146, 152, 255}, {77, 95, 103, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 100, 110, 151}, {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, 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, 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}, {77, 88, 95, 99}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {79, 100, 106, 255}, {155, 223, 231, 255}, {145, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {142, 254, 254, 255}, {76, 237, 255, 255}, {33, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {45, 231, 249, 255}, {41, 205, 224, 255}, {26, 190, 211, 255}, {24, 191, 213, 255}, {24, 192, 213, 255}, {24, 192, 214, 255}, {24, 193, 215, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {45, 192, 209, 255}, {78, 99, 107, 255}, {80, 99, 107, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {77, 100, 110, 79}, {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, 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, 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}, {71, 85, 99, 18}, {76, 90, 98, 235}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {117, 179, 183, 255}, {156, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {125, 248, 253, 255}, {57, 234, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 232, 255, 255}, {52, 228, 245, 255}, {33, 197, 217, 255}, {25, 190, 212, 255}, {23, 191, 213, 255}, {24, 192, 213, 255}, {24, 192, 214, 255}, {23, 193, 214, 255}, {24, 194, 216, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {89, 166, 172, 255}, {76, 94, 103, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 100, 109, 225}, {77, 102, 102, 10}, {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, 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, 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}, {75, 88, 96, 156}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {87, 117, 122, 255}, {159, 229, 238, 255}, {143, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {86, 239, 254, 255}, {38, 232, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {30, 232, 254, 255}, {52, 221, 238, 255}, {26, 192, 211, 255}, {24, 190, 212, 255}, {24, 191, 212, 255}, {23, 192, 213, 255}, {24, 192, 214, 255}, {23, 193, 214, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {24, 193, 213, 255}, {83, 111, 119, 255}, {79, 98, 106, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 99, 108, 137}, {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, 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, 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}, {77, 91, 100, 56}, {76, 90, 97, 253}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {133, 200, 207, 255}, {152, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {135, 251, 253, 255}, {64, 235, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {39, 233, 253, 255}, {47, 213, 230, 255}, {24, 190, 211, 255}, {23, 191, 213, 255}, {24, 191, 212, 255}, {23, 192, 214, 255}, {24, 193, 215, 255}, {23, 193, 214, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {79, 181, 191, 255}, {76, 94, 102, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 98, 109, 249}, {79, 103, 109, 42}, {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, 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, 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}, {128, 128, 128, 2}, {75, 90, 96, 207}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {96, 140, 145, 255}, {160, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {101, 243, 253, 255}, {45, 233, 255, 255}, {25, 231, 255, 255}, {26, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {47, 230, 248, 255}, {40, 203, 222, 255}, {24, 190, 211, 255}, {23, 191, 213, 255}, {23, 192, 213, 255}, {23, 192, 214, 255}, {23, 193, 214, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {88, 131, 138, 255}, {76, 95, 104, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 109, 191}, {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, 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, 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}, {76, 90, 96, 111}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {76, 93, 99, 255}, {148, 216, 223, 255}, {148, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {141, 253, 254, 255}, {71, 237, 255, 255}, {29, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 232, 255, 255}, {51, 227, 244, 255}, {32, 197, 216, 255}, {24, 190, 212, 255}, {23, 191, 213, 255}, {23, 192, 213, 255}, {23, 192, 214, 255}, {22, 192, 214, 255}, {23, 194, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {58, 190, 205, 255}, {76, 95, 102, 255}, {80, 99, 108, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {80, 100, 108, 92}, {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, 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, 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}, {78, 89, 100, 23}, {76, 91, 97, 239}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {109, 165, 170, 255}, {157, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {117, 245, 252, 255}, {53, 234, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {30, 232, 254, 255}, {52, 222, 237, 255}, {23, 190, 211, 255}, {24, 190, 212, 255}, {23, 191, 212, 255}, {23, 192, 213, 255}, {22, 191, 213, 255}, {23, 193, 214, 255}, {22, 193, 215, 255}, {23, 194, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {91, 154, 162, 255}, {76, 95, 103, 255}, {80, 100, 109, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 231}, {73, 91, 109, 14}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 91, 97, 166}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {82, 105, 112, 255}, {157, 227, 234, 255}, {144, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {80, 238, 254, 255}, {34, 232, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {39, 232, 252, 255}, {46, 213, 230, 255}, {24, 190, 211, 255}, {23, 191, 213, 255}, {22, 191, 212, 255}, {22, 191, 213, 255}, {22, 192, 214, 255}, {22, 192, 214, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {34, 192, 211, 255}, {78, 103, 110, 255}, {78, 98, 106, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {76, 97, 108, 147}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 88, 96, 64}, {75, 89, 96, 254}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {124, 188, 193, 255}, {154, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {129, 249, 253, 255}, {60, 234, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {46, 231, 248, 255}, {37, 202, 222, 255}, {24, 190, 211, 255}, {23, 191, 213, 255}, {22, 191, 212, 255}, {23, 192, 214, 255}, {22, 192, 214, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {87, 173, 181, 255}, {75, 93, 102, 255}, {81, 101, 110, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 97, 107, 252}, {78, 99, 109, 49}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 128, 128, 4}, {77, 90, 98, 213}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {89, 126, 131, 255}, {161, 231, 239, 255}, {142, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {92, 240, 253, 255}, {41, 232, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {25, 232, 255, 255}, {50, 226, 243, 255}, {29, 195, 215, 255}, {23, 190, 212, 255}, {22, 191, 212, 255}, {22, 191, 212, 255}, {22, 191, 213, 255}, {22, 192, 214, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 191, 213, 255}, {84, 119, 125, 255}, {76, 95, 105, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {79, 99, 109, 199}, {255, 255, 255, 1}, {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, 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, 0, 0}, {0, 0, 0, 0}, {77, 89, 96, 109}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {140, 209, 215, 255}, {150, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {137, 252, 253, 255}, {66, 235, 255, 255}, {26, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {31, 233, 254, 255}, {51, 220, 236, 255}, {23, 190, 211, 255}, {22, 190, 212, 255}, {22, 191, 212, 255}, {22, 191, 212, 255}, {22, 191, 213, 255}, {22, 192, 214, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {73, 186, 198, 255}, {75, 92, 101, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {79, 99, 111, 90}, {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, 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, 0, 0}, {73, 73, 109, 7}, {76, 90, 98, 229}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {103, 150, 155, 255}, {159, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {107, 244, 253, 255}, {48, 233, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {39, 232, 252, 255}, {44, 211, 229, 255}, {23, 190, 211, 255}, {22, 191, 212, 255}, {21, 190, 211, 255}, {22, 191, 213, 255}, {22, 192, 214, 255}, {21, 192, 214, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {90, 141, 147, 255}, {76, 95, 104, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 98, 109, 216}, {85, 170, 170, 3}, {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, 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}, {73, 88, 97, 116}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {78, 97, 104, 255}, {152, 221, 229, 255}, {147, 226, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {140, 253, 254, 255}, {74, 238, 255, 255}, {31, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {46, 230, 247, 255}, {34, 200, 220, 255}, {23, 190, 211, 255}, {22, 191, 212, 255}, {22, 191, 212, 255}, {21, 191, 213, 255}, {21, 192, 214, 255}, {21, 193, 215, 255}, {22, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {47, 191, 208, 255}, {76, 96, 105, 255}, {78, 98, 107, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {79, 100, 108, 97}, {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, 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}, {57, 85, 85, 9}, {76, 90, 97, 233}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {115, 174, 180, 255}, {156, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {120, 247, 253, 255}, {56, 234, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {24, 232, 255, 255}, {50, 224, 242, 255}, {27, 194, 214, 255}, {22, 189, 211, 255}, {22, 191, 212, 255}, {22, 191, 212, 255}, {21, 191, 213, 255}, {21, 192, 214, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {90, 162, 169, 255}, {75, 94, 102, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 108, 221}, {128, 128, 128, 4}, {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, 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}, {75, 90, 96, 122}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {86, 113, 119, 255}, {159, 227, 236, 255}, {143, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {84, 239, 254, 255}, {35, 232, 255, 255}, {24, 231, 255, 255}, {25, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {31, 232, 253, 255}, {48, 218, 234, 255}, {21, 189, 210, 255}, {21, 189, 211, 255}, {21, 190, 211, 255}, {21, 191, 213, 255}, {21, 192, 214, 255}, {21, 192, 214, 255}, {21, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {27, 193, 212, 255}, {80, 108, 116, 255}, {78, 95, 105, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {79, 99, 109, 103}, {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, 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}, {64, 96, 96, 8}, {75, 89, 97, 234}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {130, 197, 202, 255}, {152, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {133, 251, 253, 255}, {62, 235, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {40, 232, 251, 255}, {42, 209, 227, 255}, {22, 189, 210, 255}, {21, 190, 212, 255}, {21, 191, 212, 255}, {20, 191, 213, 255}, {21, 192, 214, 255}, {21, 192, 214, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {82, 178, 189, 255}, {75, 93, 101, 255}, {80, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {79, 98, 109, 223}, {85, 170, 170, 3}, {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, 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}, {76, 91, 98, 107}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {94, 135, 140, 255}, {161, 230, 238, 255}, {141, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {98, 242, 253, 255}, {43, 233, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {46, 230, 247, 255}, {33, 199, 220, 255}, {22, 189, 210, 255}, {20, 190, 212, 255}, {21, 191, 212, 255}, {20, 191, 213, 255}, {21, 192, 214, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 193, 215, 255}, {86, 127, 134, 255}, {77, 95, 104, 255}, {80, 100, 109, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {76, 97, 108, 87}, {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, 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}, {255, 255, 255, 1}, {75, 89, 97, 218}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 91, 98, 255}, {144, 214, 220, 255}, {148, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {141, 253, 254, 255}, {68, 236, 255, 255}, {27, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {24, 232, 255, 255}, {49, 223, 241, 255}, {26, 193, 213, 255}, {21, 189, 211, 255}, {20, 190, 212, 255}, {20, 191, 212, 255}, {21, 191, 213, 255}, {21, 192, 214, 255}, {20, 193, 215, 255}, {21, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {62, 189, 202, 255}, {74, 92, 100, 255}, {79, 98, 107, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 202}, {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, 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}, {76, 91, 98, 81}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {107, 160, 164, 255}, {158, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {113, 245, 253, 255}, {51, 234, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {31, 232, 253, 255}, {47, 218, 235, 255}, {21, 189, 210, 255}, {21, 189, 211, 255}, {20, 190, 211, 255}, {20, 191, 213, 255}, {20, 192, 214, 255}, {20, 192, 214, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {91, 150, 156, 255}, {75, 94, 102, 255}, {80, 100, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 99, 107, 62}, {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, 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}, {74, 88, 96, 196}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {80, 103, 109, 255}, {157, 226, 233, 255}, {145, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {142, 254, 254, 255}, {77, 238, 255, 255}, {32, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {39, 231, 250, 255}, {40, 208, 226, 255}, {21, 189, 210, 255}, {20, 190, 212, 255}, {20, 191, 212, 255}, {20, 191, 213, 255}, {20, 192, 214, 255}, {20, 192, 214, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {39, 191, 209, 255}, {78, 99, 108, 255}, {78, 96, 106, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {79, 99, 109, 178}, {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, 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}, {74, 88, 93, 52}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {119, 183, 188, 255}, {154, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 237, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {126, 248, 253, 255}, {57, 234, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 232, 255, 255}, {46, 229, 246, 255}, {31, 199, 219, 255}, {20, 189, 211, 255}, {20, 190, 212, 255}, {20, 191, 212, 255}, {20, 191, 213, 255}, {19, 192, 214, 255}, {20, 193, 215, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {89, 170, 178, 255}, {75, 93, 101, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 253}, {80, 95, 109, 35}, {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, 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}, {75, 90, 98, 156}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {88, 122, 127, 255}, {160, 230, 239, 255}, {142, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {88, 240, 254, 255}, {38, 232, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {24, 231, 254, 255}, {50, 224, 241, 255}, {24, 193, 212, 255}, {21, 189, 211, 255}, {19, 190, 212, 255}, {19, 191, 212, 255}, {20, 191, 213, 255}, {19, 192, 214, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {19, 192, 212, 255}, {82, 114, 121, 255}, {77, 96, 105, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {79, 98, 107, 136}, {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, 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}, {93, 93, 116, 11}, {75, 90, 96, 242}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {135, 204, 210, 255}, {151, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {136, 252, 253, 255}, {63, 234, 255, 255}, {25, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {24, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {31, 232, 254, 255}, {46, 217, 233, 255}, {21, 188, 209, 255}, {20, 190, 212, 255}, {19, 190, 211, 255}, {20, 191, 213, 255}, {19, 192, 214, 255}, {19, 192, 214, 255}, {20, 193, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {75, 184, 194, 255}, {74, 92, 100, 255}, {79, 98, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {78, 98, 108, 231}, {128, 128, 128, 4}, {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, 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}, {75, 88, 95, 102}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {99, 144, 150, 255}, {160, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {103, 244, 252, 255}, {45, 233, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {39, 231, 250, 255}, {39, 207, 225, 255}, {20, 189, 210, 255}, {19, 190, 212, 255}, {19, 191, 212, 255}, {19, 191, 213, 255}, {19, 192, 214, 255}, {19, 192, 214, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {88, 135, 143, 255}, {76, 95, 103, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {79, 98, 107, 81}, {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, 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}, {76, 90, 98, 201}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {78, 96, 102, 255}, {149, 219, 227, 255}, {147, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {166, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {140, 254, 254, 255}, {72, 236, 255, 255}, {28, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 231, 255, 255}, {46, 228, 245, 255}, {31, 198, 218, 255}, {20, 189, 211, 255}, {19, 190, 212, 255}, {19, 191, 212, 255}, {19, 191, 213, 255}, {19, 192, 214, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {53, 191, 206, 255}, {75, 95, 103, 255}, {78, 98, 106, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 182}, {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, 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}, {74, 91, 96, 45}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {112, 170, 174, 255}, {156, 228, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {117, 246, 252, 255}, {53, 234, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {23, 231, 254, 255}, {49, 222, 240, 255}, {22, 192, 212, 255}, {20, 189, 211, 255}, {19, 190, 212, 255}, {18, 190, 212, 255}, {19, 191, 213, 255}, {18, 191, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {90, 158, 164, 255}, {76, 93, 102, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 97, 106, 252}, {82, 100, 109, 28}, {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, 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}, {77, 90, 98, 136}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {83, 108, 115, 255}, {159, 228, 236, 255}, {144, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 254, 254, 255}, {81, 238, 255, 255}, {33, 232, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {31, 232, 253, 255}, {44, 215, 232, 255}, {20, 189, 210, 255}, {19, 190, 212, 255}, {18, 189, 211, 255}, {19, 191, 213, 255}, {19, 192, 214, 255}, {19, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {31, 192, 212, 255}, {78, 104, 113, 255}, {77, 96, 106, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 99, 108, 116}, {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, 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}, {75, 90, 97, 220}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {128, 193, 197, 255}, {153, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {129, 250, 253, 255}, {60, 234, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {39, 231, 250, 255}, {37, 205, 224, 255}, {19, 189, 210, 255}, {19, 190, 212, 255}, {18, 190, 212, 255}, {18, 190, 213, 255}, {19, 192, 214, 255}, {18, 191, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {83, 175, 184, 255}, {75, 92, 100, 255}, {79, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {78, 97, 107, 202}, {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, 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}, {75, 90, 95, 51}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {93, 131, 136, 255}, {161, 230, 238, 255}, {141, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {93, 240, 253, 255}, {41, 233, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 231, 255, 255}, {46, 228, 244, 255}, {28, 197, 216, 255}, {20, 189, 211, 255}, {18, 189, 212, 255}, {18, 190, 212, 255}, {18, 190, 213, 255}, {18, 191, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {84, 122, 129, 255}, {76, 95, 103, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 100, 108, 33}, {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, 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}, {75, 89, 97, 140}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {76, 91, 98, 255}, {140, 211, 218, 255}, {149, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {137, 252, 253, 255}, {64, 235, 255, 255}, {25, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {25, 231, 254, 255}, {47, 222, 239, 255}, {21, 190, 212, 255}, {19, 189, 211, 255}, {18, 189, 211, 255}, {18, 190, 212, 255}, {17, 190, 213, 255}, {18, 191, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {65, 188, 199, 255}, {73, 91, 100, 255}, {79, 98, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {78, 99, 107, 121}, {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, 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}, {75, 90, 97, 223}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {104, 154, 159, 255}, {158, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {108, 244, 252, 255}, {47, 233, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {32, 232, 253, 255}, {43, 214, 230, 255}, {19, 189, 210, 255}, {18, 189, 212, 255}, {18, 189, 211, 255}, {17, 190, 213, 255}, {18, 191, 214, 255}, {17, 191, 213, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {89, 145, 151, 255}, {75, 93, 102, 255}, {79, 99, 109, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {78, 97, 107, 205}, {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, 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}, {71, 87, 97, 50}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {79, 99, 106, 255}, {155, 223, 231, 255}, {145, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {141, 254, 254, 255}, {74, 237, 255, 255}, {29, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {40, 230, 250, 255}, {35, 203, 223, 255}, {18, 188, 210, 255}, {18, 189, 212, 255}, {18, 190, 212, 255}, {17, 190, 213, 255}, {17, 191, 213, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {43, 191, 208, 255}, {76, 97, 105, 255}, {78, 97, 105, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {82, 99, 107, 31}, {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, 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}, {76, 90, 99, 124}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {118, 179, 184, 255}, {155, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {122, 247, 253, 255}, {55, 234, 255, 255}, {22, 231, 255, 255}, {23, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 231, 255, 255}, {46, 228, 244, 255}, {27, 196, 216, 255}, {18, 188, 211, 255}, {18, 189, 212, 255}, {18, 190, 212, 255}, {17, 190, 213, 255}, {17, 191, 213, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {88, 164, 171, 255}, {74, 92, 101, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 105, 104}, {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, 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}, {75, 89, 97, 195}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {86, 117, 122, 255}, {159, 229, 238, 255}, {143, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {84, 239, 254, 255}, {35, 232, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {24, 231, 254, 255}, {46, 221, 239, 255}, {19, 190, 210, 255}, {18, 188, 211, 255}, {17, 189, 211, 255}, {17, 190, 212, 255}, {17, 190, 213, 255}, {17, 191, 213, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {21, 192, 213, 255}, {81, 110, 117, 255}, {77, 96, 104, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {78, 98, 107, 177}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 91, 109, 14}, {75, 90, 98, 250}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {132, 200, 206, 255}, {152, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {133, 252, 254, 255}, {62, 234, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {33, 232, 253, 255}, {41, 212, 229, 255}, {18, 188, 210, 255}, {17, 189, 212, 255}, {17, 189, 211, 255}, {17, 190, 213, 255}, {17, 191, 213, 255}, {17, 191, 213, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {77, 181, 189, 255}, {74, 92, 100, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 242}, {102, 102, 102, 5}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 90, 96, 85}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {96, 140, 146, 255}, {160, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {144, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {98, 243, 253, 255}, {43, 233, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {41, 229, 248, 255}, {33, 201, 221, 255}, {18, 188, 210, 255}, {17, 189, 212, 255}, {17, 190, 212, 255}, {16, 190, 212, 255}, {17, 191, 213, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {87, 130, 137, 255}, {74, 93, 103, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 108, 66}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {74, 89, 97, 158}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {76, 93, 99, 255}, {147, 216, 223, 255}, {147, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {138, 253, 254, 255}, {68, 236, 255, 255}, {26, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 231, 255, 255}, {45, 227, 244, 255}, {24, 195, 215, 255}, {18, 188, 211, 255}, {17, 189, 212, 255}, {16, 190, 211, 255}, {16, 190, 212, 255}, {16, 191, 213, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {56, 189, 204, 255}, {74, 93, 100, 255}, {77, 96, 106, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {78, 96, 107, 138}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 89, 98, 217}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {109, 165, 170, 255}, {158, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {114, 245, 252, 255}, {50, 233, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {24, 231, 254, 255}, {46, 221, 237, 255}, {17, 188, 210, 255}, {18, 188, 211, 255}, {17, 189, 211, 255}, {16, 190, 211, 255}, {16, 190, 212, 255}, {16, 191, 213, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {89, 153, 158, 255}, {74, 93, 101, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {78, 97, 107, 200}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {67, 94, 94, 19}, {75, 89, 96, 254}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {81, 105, 111, 255}, {158, 228, 234, 255}, {144, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {78, 238, 254, 255}, {30, 232, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {32, 231, 252, 255}, {41, 212, 229, 255}, {17, 188, 210, 255}, {17, 189, 212, 255}, {16, 189, 210, 255}, {16, 190, 212, 255}, {16, 191, 213, 255}, {16, 191, 213, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {32, 192, 211, 255}, {77, 101, 109, 255}, {76, 96, 105, 255}, {79, 99, 108, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 96, 107, 249}, {96, 96, 128, 8}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {76, 91, 98, 81}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {124, 188, 191, 255}, {153, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {127, 249, 253, 255}, {57, 233, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {41, 230, 249, 255}, {31, 201, 221, 255}, {17, 188, 210, 255}, {16, 189, 211, 255}, {16, 190, 211, 255}, {16, 190, 212, 255}, {15, 191, 213, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {85, 172, 179, 255}, {73, 91, 100, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {78, 99, 107, 62}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {76, 89, 96, 141}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {90, 126, 131, 255}, {161, 231, 239, 255}, {142, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {89, 239, 252, 255}, {38, 232, 255, 255}, {22, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {18, 231, 255, 255}, {45, 225, 243, 255}, {23, 194, 214, 255}, {16, 188, 210, 255}, {16, 189, 211, 255}, {16, 190, 211, 255}, {16, 190, 212, 255}, {15, 191, 213, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 190, 213, 255}, {82, 117, 124, 255}, {75, 94, 104, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {78, 97, 107, 121}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 90, 98, 198}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {138, 207, 215, 255}, {150, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {135, 252, 253, 255}, {64, 234, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {25, 232, 254, 255}, {45, 219, 236, 255}, {17, 188, 210, 255}, {15, 188, 210, 255}, {16, 189, 210, 255}, {16, 190, 211, 255}, {15, 190, 212, 255}, {15, 191, 213, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {69, 185, 197, 255}, {72, 90, 99, 255}, {77, 97, 106, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 96, 106, 180}, {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, 0, 0, 0}, {0, 0, 0, 0}, {85, 85, 85, 3}, {76, 90, 98, 247}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {102, 150, 156, 255}, {159, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {105, 243, 253, 255}, {44, 232, 255, 255}, {22, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {32, 231, 252, 255}, {39, 210, 228, 255}, {17, 188, 210, 255}, {15, 189, 211, 255}, {15, 189, 210, 255}, {15, 190, 212, 255}, {15, 191, 213, 255}, {15, 191, 213, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {87, 139, 145, 255}, {74, 93, 102, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 234}, {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, 0, 0, 0}, {0, 0, 0, 0}, {74, 91, 96, 45}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {78, 97, 103, 255}, {151, 221, 228, 255}, {146, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 226, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {138, 253, 254, 255}, {72, 238, 255, 255}, {27, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {41, 230, 248, 255}, {29, 199, 219, 255}, {17, 188, 210, 255}, {15, 189, 211, 255}, {15, 190, 211, 255}, {15, 190, 212, 255}, {15, 191, 213, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {45, 190, 207, 255}, {74, 94, 103, 255}, {75, 95, 105, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {71, 92, 102, 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}, {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}, {75, 91, 97, 92}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {115, 173, 179, 255}, {156, 228, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {119, 247, 253, 255}, {53, 233, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {17, 231, 255, 255}, {45, 225, 241, 255}, {21, 192, 213, 255}, {16, 188, 210, 255}, {15, 189, 211, 255}, {15, 190, 211, 255}, {15, 190, 212, 255}, {15, 191, 213, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {88, 161, 168, 255}, {73, 92, 100, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 98, 105, 73}, {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, 0, 0, 0}, {76, 89, 96, 138}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {85, 112, 118, 255}, {159, 228, 236, 255}, {143, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 226, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {81, 240, 254, 255}, {32, 232, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {24, 231, 253, 255}, {44, 218, 236, 255}, {15, 188, 209, 255}, {14, 187, 210, 255}, {15, 189, 210, 255}, {15, 190, 212, 255}, {14, 190, 213, 255}, {15, 191, 213, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {24, 192, 212, 255}, {78, 106, 114, 255}, {75, 93, 104, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {78, 97, 108, 118}, {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, 0, 0, 0}, {75, 89, 98, 183}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {129, 196, 200, 255}, {152, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {165, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {130, 250, 253, 255}, {59, 234, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {33, 231, 251, 255}, {36, 207, 226, 255}, {15, 187, 209, 255}, {15, 189, 211, 255}, {14, 188, 210, 255}, {15, 190, 212, 255}, {14, 190, 213, 255}, {14, 190, 213, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {80, 177, 188, 255}, {73, 91, 100, 255}, {77, 96, 106, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 98, 107, 164}, {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, 0, 0, 0}, {74, 89, 96, 226}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {94, 135, 140, 255}, {161, 230, 238, 255}, {141, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {95, 242, 253, 255}, {40, 232, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {41, 229, 248, 255}, {27, 198, 219, 255}, {15, 187, 209, 255}, {15, 189, 211, 255}, {14, 189, 211, 255}, {14, 189, 212, 255}, {14, 190, 213, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 192, 215, 255}, {84, 125, 132, 255}, {74, 93, 102, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {77, 96, 106, 209}, {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}, {57, 85, 85, 9}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {76, 92, 99, 255}, {144, 214, 220, 255}, {148, 227, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 226, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {139, 253, 254, 255}, {65, 235, 255, 255}, {23, 231, 255, 255}, {21, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {17, 231, 255, 255}, {43, 222, 240, 255}, {19, 191, 212, 255}, {15, 187, 210, 255}, {14, 188, 211, 255}, {14, 189, 211, 255}, {14, 189, 212, 255}, {14, 190, 213, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {61, 188, 201, 255}, {72, 90, 99, 255}, {76, 96, 105, 255}, {77, 97, 107, 255}, {78, 98, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 97, 106, 247}, {255, 255, 255, 1}, {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}, {74, 91, 96, 45}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {106, 159, 164, 255}, {158, 229, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {111, 245, 253, 255}, {47, 233, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {24, 231, 253, 255}, {43, 216, 235, 255}, {14, 187, 209, 255}, {14, 187, 210, 255}, {14, 188, 210, 255}, {13, 189, 212, 255}, {14, 190, 213, 255}, {13, 190, 213, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {88, 148, 153, 255}, {72, 92, 100, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {71, 92, 102, 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}, {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}, {75, 92, 98, 78}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {80, 102, 108, 255}, {156, 226, 233, 255}, {144, 226, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 254, 254, 255}, {74, 238, 254, 255}, {29, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {33, 230, 250, 255}, {34, 206, 225, 255}, {15, 187, 209, 255}, {14, 188, 211, 255}, {14, 189, 211, 255}, {13, 189, 212, 255}, {14, 190, 213, 255}, {13, 190, 213, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {37, 191, 209, 255}, {75, 97, 106, 255}, {75, 94, 104, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {78, 99, 108, 59}, {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}, {75, 89, 96, 112}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {119, 183, 188, 255}, {154, 228, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {124, 248, 253, 255}, {55, 233, 255, 255}, {20, 231, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 231, 255, 255}, {41, 228, 247, 255}, {25, 198, 217, 255}, {15, 187, 210, 255}, {13, 188, 211, 255}, {14, 189, 211, 255}, {13, 189, 212, 255}, {14, 190, 213, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {86, 168, 175, 255}, {72, 91, 99, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {78, 97, 108, 92}, {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}, {74, 89, 96, 144}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {88, 120, 126, 255}, {160, 230, 239, 255}, {141, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {86, 240, 254, 255}, {34, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {18, 231, 254, 255}, {45, 223, 241, 255}, {17, 191, 211, 255}, {14, 187, 210, 255}, {13, 188, 211, 255}, {14, 189, 211, 255}, {13, 189, 212, 255}, {13, 190, 213, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {17, 191, 213, 255}, {80, 113, 119, 255}, {74, 93, 103, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {78, 99, 107, 124}, {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}, {74, 88, 96, 176}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {135, 204, 210, 255}, {151, 227, 237, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {134, 252, 253, 255}, {61, 234, 255, 255}, {21, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {26, 232, 254, 255}, {40, 216, 233, 255}, {14, 186, 208, 255}, {13, 188, 211, 255}, {13, 188, 210, 255}, {13, 189, 212, 255}, {13, 190, 213, 255}, {13, 190, 213, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {72, 181, 193, 255}, {72, 90, 98, 255}, {76, 96, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 157}, {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}, {76, 90, 98, 201}, {74, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {75, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {98, 144, 150, 255}, {160, 229, 238, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {100, 243, 253, 255}, {43, 232, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {34, 232, 251, 255}, {32, 205, 224, 255}, {14, 187, 209, 255}, {13, 188, 211, 255}, {12, 189, 211, 255}, {13, 189, 212, 255}, {12, 190, 213, 255}, {13, 190, 213, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {86, 134, 140, 255}, {73, 92, 100, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 96, 106, 183}, {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}, {75, 90, 97, 219}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {77, 95, 101, 255}, {149, 219, 227, 255}, {147, 226, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {138, 254, 254, 255}, {68, 236, 255, 255}, {25, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 231, 255, 255}, {40, 228, 246, 255}, {24, 197, 217, 255}, {13, 187, 210, 255}, {12, 188, 211, 255}, {13, 189, 211, 255}, {12, 189, 212, 255}, {12, 190, 213, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {51, 191, 206, 255}, {72, 93, 101, 255}, {76, 96, 105, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {77, 96, 107, 201}, {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}, {75, 89, 98, 237}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {111, 169, 174, 255}, {156, 228, 238, 255}, {140, 225, 236, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {116, 246, 253, 255}, {49, 233, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {17, 231, 254, 255}, {43, 221, 239, 255}, {16, 190, 211, 255}, {13, 187, 210, 255}, {12, 188, 211, 255}, {13, 189, 211, 255}, {12, 189, 212, 255}, {12, 190, 213, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {88, 156, 163, 255}, {73, 90, 99, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 96, 105, 220}, {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}, {255, 255, 255, 1}, {75, 90, 97, 253}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {82, 108, 114, 255}, {158, 228, 235, 255}, {144, 226, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 254, 254, 255}, {78, 238, 255, 255}, {31, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {25, 232, 253, 255}, {38, 214, 231, 255}, {14, 187, 209, 255}, {12, 188, 211, 255}, {12, 188, 210, 255}, {12, 189, 212, 255}, {12, 190, 213, 255}, {12, 190, 213, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {29, 191, 211, 255}, {76, 103, 111, 255}, {74, 94, 103, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 97, 106, 239}, {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}, {85, 85, 85, 6}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {126, 191, 197, 255}, {152, 227, 237, 255}, {139, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {129, 250, 253, 255}, {57, 234, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {20, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {33, 231, 250, 255}, {31, 204, 223, 255}, {13, 187, 209, 255}, {12, 188, 211, 255}, {12, 189, 211, 255}, {12, 189, 212, 255}, {12, 190, 213, 255}, {11, 189, 212, 255}, {12, 191, 214, 255}, {81, 173, 183, 255}, {72, 90, 98, 255}, {77, 96, 105, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 254}, {255, 255, 255, 1}, {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}, {73, 91, 109, 14}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {92, 130, 135, 255}, {160, 230, 238, 255}, {140, 225, 235, 255}, {140, 225, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {143, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {91, 240, 253, 255}, {38, 232, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 231, 255, 255}, {40, 228, 245, 255}, {22, 195, 215, 255}, {13, 187, 210, 255}, {12, 188, 211, 255}, {12, 189, 211, 255}, {11, 188, 211, 255}, {12, 190, 213, 255}, {12, 190, 213, 255}, {81, 120, 126, 255}, {74, 93, 102, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {64, 96, 96, 8}, {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}, {71, 85, 99, 18}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 90, 97, 255}, {139, 211, 217, 255}, {149, 226, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {135, 252, 253, 255}, {61, 235, 255, 255}, {21, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {17, 231, 254, 255}, {42, 222, 238, 255}, {14, 188, 210, 255}, {12, 187, 210, 255}, {12, 188, 210, 255}, {12, 189, 211, 255}, {11, 188, 211, 255}, {63, 187, 198, 255}, {71, 89, 98, 255}, {77, 96, 105, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {70, 93, 93, 11}, {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}, {85, 97, 109, 21}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {103, 154, 158, 255}, {158, 229, 238, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {106, 244, 252, 255}, {44, 232, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {27, 232, 253, 255}, {38, 214, 231, 255}, {12, 187, 209, 255}, {12, 188, 211, 255}, {11, 188, 210, 255}, {12, 189, 212, 255}, {87, 144, 148, 255}, {73, 91, 100, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {59, 78, 98, 13}, {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}, {70, 81, 93, 22}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {78, 99, 105, 255}, {154, 223, 231, 255}, {145, 226, 236, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {139, 254, 254, 255}, {71, 237, 255, 255}, {26, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {11, 230, 255, 255}, {34, 230, 250, 255}, {29, 202, 223, 255}, {12, 187, 209, 255}, {11, 188, 210, 255}, {41, 190, 206, 255}, {74, 95, 103, 255}, {76, 95, 103, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {64, 80, 96, 16}, {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}, {82, 92, 102, 25}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {115, 177, 183, 255}, {155, 228, 237, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {120, 247, 253, 255}, {52, 233, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {11, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {11, 230, 255, 255}, {11, 230, 255, 255}, {11, 231, 255, 255}, {41, 227, 245, 255}, {20, 194, 215, 255}, {12, 187, 210, 255}, {86, 163, 170, 255}, {72, 90, 99, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {57, 85, 85, 18}, {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}, {73, 91, 100, 28}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {83, 112, 119, 255}, {158, 229, 238, 255}, {142, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {139, 255, 255, 255}, {82, 239, 254, 255}, {32, 231, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {19, 230, 255, 255}, {18, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {18, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {17, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {16, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {15, 230, 255, 255}, {14, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {14, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {13, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {11, 230, 255, 255}, {12, 230, 255, 255}, {12, 230, 255, 255}, {11, 230, 255, 255}, {12, 230, 255, 255}, {17, 231, 254, 255}, {41, 221, 238, 255}, {22, 189, 208, 255}, {76, 104, 112, 255}, {75, 94, 102, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {64, 77, 89, 20}, {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}, {77, 85, 94, 30}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {110, 159, 165, 255}, {151, 227, 237, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {131, 251, 253, 255}, {67, 236, 254, 255}, {45, 233, 253, 255}, {44, 233, 253, 255}, {44, 232, 252, 255}, {44, 232, 252, 255}, {44, 231, 251, 255}, {44, 231, 251, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {43, 231, 252, 255}, {44, 231, 252, 255}, {44, 231, 252, 255}, {43, 231, 252, 255}, {44, 231, 252, 255}, {43, 231, 252, 255}, {43, 231, 252, 255}, {43, 231, 252, 255}, {42, 231, 252, 255}, {43, 231, 252, 255}, {42, 231, 252, 255}, {43, 231, 252, 255}, {42, 231, 252, 255}, {43, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {42, 231, 252, 255}, {41, 231, 252, 255}, {42, 231, 252, 255}, {41, 231, 252, 255}, {42, 231, 252, 255}, {41, 231, 252, 255}, {42, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {40, 231, 252, 255}, {41, 231, 252, 255}, {41, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {39, 231, 252, 255}, {40, 231, 252, 255}, {40, 231, 252, 255}, {39, 231, 252, 255}, {40, 231, 252, 255}, {39, 231, 252, 255}, {39, 231, 252, 255}, {39, 231, 252, 255}, {38, 231, 252, 255}, {39, 231, 252, 255}, {38, 231, 252, 255}, {39, 231, 252, 255}, {38, 231, 252, 255}, {39, 231, 252, 255}, {38, 231, 252, 255}, {38, 231, 252, 255}, {38, 231, 252, 255}, {38, 231, 252, 255}, {38, 231, 251, 255}, {38, 231, 251, 255}, {38, 231, 251, 255}, {38, 232, 252, 255}, {37, 232, 252, 255}, {38, 232, 252, 255}, {37, 232, 252, 255}, {37, 232, 252, 255}, {38, 232, 253, 255}, {39, 233, 253, 255}, {38, 232, 253, 255}, {39, 233, 254, 255}, {39, 233, 254, 255}, {49, 234, 252, 255}, {80, 144, 151, 255}, {72, 91, 100, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {58, 81, 93, 22}, {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}, {77, 85, 94, 30}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {74, 89, 96, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {109, 158, 162, 255}, {142, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {117, 234, 241, 255}, {55, 202, 221, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {30, 194, 212, 255}, {77, 133, 140, 255}, {72, 91, 98, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {58, 81, 93, 22}, {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}, {76, 94, 94, 27}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {82, 109, 115, 255}, {151, 226, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {139, 253, 253, 255}, {80, 211, 227, 255}, {21, 193, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {20, 193, 214, 255}, {44, 179, 193, 255}, {30, 140, 152, 255}, {71, 96, 104, 255}, {71, 89, 99, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {67, 81, 94, 19}, {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}, {82, 92, 102, 25}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {113, 173, 177, 255}, {144, 225, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {100, 226, 235, 255}, {43, 199, 218, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {13, 192, 214, 255}, {41, 187, 202, 255}, {25, 142, 154, 255}, {17, 133, 146, 255}, {85, 149, 156, 255}, {68, 84, 94, 255}, {70, 89, 98, 255}, {74, 93, 102, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {57, 85, 85, 18}, {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}, {70, 81, 93, 22}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {77, 96, 102, 255}, {148, 221, 228, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {133, 248, 250, 255}, {73, 206, 224, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {37, 194, 210, 255}, {33, 152, 166, 255}, {19, 133, 146, 255}, {17, 136, 149, 255}, {48, 156, 166, 255}, {68, 87, 95, 255}, {69, 88, 96, 255}, {71, 90, 99, 255}, {72, 91, 100, 255}, {76, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {68, 85, 102, 15}, {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}, {77, 89, 89, 20}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {100, 148, 153, 255}, {147, 226, 236, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {91, 217, 230, 255}, {32, 196, 217, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {29, 194, 214, 255}, {41, 168, 182, 255}, {19, 131, 146, 255}, {17, 134, 148, 255}, {17, 138, 150, 255}, {15, 139, 154, 255}, {84, 133, 140, 255}, {68, 86, 95, 255}, {71, 89, 99, 255}, {71, 90, 99, 255}, {71, 90, 98, 255}, {74, 93, 102, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {59, 78, 98, 13}, {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}, {71, 85, 99, 18}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {136, 207, 214, 255}, {140, 225, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {123, 240, 243, 255}, {60, 203, 222, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {19, 193, 214, 255}, {45, 180, 195, 255}, {19, 134, 145, 255}, {17, 134, 148, 255}, {17, 137, 152, 255}, {16, 141, 153, 255}, {16, 141, 155, 255}, {67, 163, 171, 255}, {65, 83, 92, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {76, 95, 105, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {70, 93, 93, 11}, {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}, {73, 91, 91, 14}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {88, 123, 128, 255}, {151, 228, 238, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {138, 254, 254, 255}, {83, 213, 227, 255}, {23, 193, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {13, 192, 214, 255}, {44, 189, 205, 255}, {26, 143, 156, 255}, {19, 134, 146, 255}, {18, 136, 149, 255}, {17, 139, 153, 255}, {15, 141, 153, 255}, {14, 143, 157, 255}, {16, 145, 160, 255}, {78, 111, 118, 255}, {68, 86, 95, 255}, {72, 90, 99, 255}, {71, 90, 99, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {72, 91, 100, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {73, 73, 109, 7}, {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}, {85, 85, 85, 6}, {73, 88, 95, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {121, 186, 191, 255}, {142, 225, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {109, 230, 237, 255}, {50, 200, 220, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {38, 194, 211, 255}, {34, 156, 169, 255}, {19, 133, 145, 255}, {17, 135, 148, 255}, {16, 138, 152, 255}, {15, 140, 153, 255}, {14, 143, 156, 255}, {14, 143, 157, 255}, {13, 145, 159, 255}, {82, 160, 166, 255}, {66, 83, 92, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {74, 94, 103, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 254}, {255, 255, 255, 1}, {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}, {255, 255, 255, 1}, {74, 88, 95, 252}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {79, 103, 110, 255}, {151, 224, 233, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {136, 252, 253, 255}, {78, 209, 224, 255}, {20, 193, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {29, 194, 214, 255}, {41, 169, 181, 255}, {19, 132, 145, 255}, {18, 134, 148, 255}, {18, 138, 151, 255}, {16, 139, 153, 255}, {16, 141, 155, 255}, {14, 143, 157, 255}, {14, 144, 159, 255}, {14, 145, 161, 255}, {33, 156, 168, 255}, {72, 94, 102, 255}, {69, 88, 96, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {72, 90, 100, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {76, 96, 106, 238}, {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}, {74, 89, 95, 235}, {73, 87, 94, 255}, {73, 88, 95, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {107, 163, 168, 255}, {145, 225, 236, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {98, 221, 232, 255}, {37, 197, 217, 255}, {18, 192, 215, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {11, 190, 213, 255}, {12, 191, 214, 255}, {19, 194, 214, 255}, {45, 181, 195, 255}, {19, 135, 147, 255}, {18, 133, 147, 255}, {18, 137, 151, 255}, {16, 140, 153, 255}, {15, 141, 155, 255}, {15, 141, 157, 255}, {15, 144, 158, 255}, {14, 145, 160, 255}, {13, 145, 160, 255}, {12, 148, 162, 255}, {86, 145, 151, 255}, {66, 83, 93, 255}, {70, 88, 98, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {73, 92, 103, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 94, 105, 219}, {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}, {74, 88, 95, 218}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {74, 92, 98, 255}, {144, 214, 221, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {130, 245, 247, 255}, {68, 205, 222, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 193, 214, 255}, {43, 189, 205, 255}, {29, 144, 159, 255}, {19, 134, 146, 255}, {18, 136, 149, 255}, {16, 139, 152, 255}, {15, 141, 153, 255}, {14, 142, 157, 255}, {14, 144, 157, 255}, {14, 144, 159, 255}, {14, 145, 161, 255}, {12, 147, 161, 255}, {12, 148, 163, 255}, {55, 165, 175, 255}, {67, 84, 93, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 90, 100, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 97, 106, 200}, {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}, {73, 88, 95, 199}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {94, 138, 142, 255}, {149, 226, 236, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 225, 236, 255}, {164, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {87, 215, 228, 255}, {28, 194, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {36, 194, 211, 255}, {36, 157, 172, 255}, {20, 133, 146, 255}, {17, 135, 148, 255}, {17, 138, 152, 255}, {16, 140, 153, 255}, {14, 142, 155, 255}, {14, 143, 157, 255}, {14, 144, 159, 255}, {15, 146, 161, 255}, {14, 147, 162, 255}, {13, 147, 163, 255}, {13, 148, 163, 255}, {13, 149, 165, 255}, {82, 123, 130, 255}, {68, 85, 95, 255}, {70, 89, 98, 255}, {72, 90, 99, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 90, 98, 255}, {71, 91, 100, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {76, 97, 107, 181}, {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}, {73, 88, 95, 174}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {129, 199, 204, 255}, {140, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {118, 236, 241, 255}, {56, 202, 221, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {27, 194, 214, 255}, {42, 171, 185, 255}, {20, 132, 145, 255}, {18, 133, 149, 255}, {18, 136, 151, 255}, {16, 139, 153, 255}, {15, 141, 155, 255}, {15, 143, 157, 255}, {14, 144, 158, 255}, {14, 146, 160, 255}, {13, 145, 161, 255}, {13, 148, 163, 255}, {13, 148, 163, 255}, {12, 149, 165, 255}, {13, 150, 165, 255}, {75, 166, 173, 255}, {67, 83, 92, 255}, {70, 87, 97, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 98, 255}, {70, 90, 98, 255}, {74, 93, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {76, 94, 104, 155}, {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}, {74, 88, 95, 142}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {83, 114, 119, 255}, {149, 227, 236, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 253, 254, 255}, {81, 212, 228, 255}, {21, 193, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {18, 193, 214, 255}, {46, 183, 196, 255}, {22, 136, 149, 255}, {19, 133, 148, 255}, {18, 135, 150, 255}, {16, 139, 152, 255}, {17, 141, 155, 255}, {15, 141, 156, 255}, {15, 144, 158, 255}, {14, 144, 160, 255}, {14, 145, 161, 255}, {13, 147, 163, 255}, {12, 147, 163, 255}, {13, 148, 164, 255}, {13, 149, 165, 255}, {13, 150, 165, 255}, {22, 155, 169, 255}, {73, 102, 109, 255}, {68, 85, 95, 255}, {72, 90, 99, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {72, 91, 100, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 96, 107, 122}, {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}, {75, 87, 96, 109}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {114, 176, 181, 255}, {142, 225, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {104, 226, 235, 255}, {44, 199, 219, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 193, 214, 255}, {43, 189, 205, 255}, {31, 147, 160, 255}, {20, 134, 147, 255}, {18, 135, 149, 255}, {17, 138, 152, 255}, {17, 140, 154, 255}, {14, 142, 156, 255}, {15, 143, 158, 255}, {13, 144, 159, 255}, {15, 146, 161, 255}, {13, 147, 162, 255}, {13, 148, 163, 255}, {13, 148, 164, 255}, {12, 149, 165, 255}, {12, 150, 165, 255}, {12, 150, 165, 255}, {12, 151, 166, 255}, {85, 156, 161, 255}, {68, 85, 94, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {71, 89, 99, 255}, {70, 90, 99, 255}, {73, 92, 103, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 97, 106, 89}, {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}, {74, 87, 94, 76}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {76, 96, 104, 255}, {148, 222, 230, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {164, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {142, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {136, 250, 252, 255}, {74, 208, 224, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {35, 194, 211, 255}, {36, 158, 172, 255}, {20, 133, 145, 255}, {19, 134, 149, 255}, {17, 137, 151, 255}, {16, 139, 153, 255}, {16, 142, 155, 255}, {14, 143, 157, 255}, {14, 145, 159, 255}, {13, 145, 160, 255}, {13, 145, 161, 255}, {14, 147, 163, 255}, {13, 148, 163, 255}, {13, 149, 165, 255}, {12, 150, 165, 255}, {12, 150, 166, 255}, {12, 151, 166, 255}, {11, 151, 166, 255}, {39, 162, 175, 255}, {69, 89, 96, 255}, {70, 87, 96, 255}, {70, 88, 98, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {70, 91, 99, 255}, {75, 94, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {73, 96, 105, 56}, {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}, {73, 85, 97, 42}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {101, 152, 158, 255}, {146, 226, 236, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {93, 218, 230, 255}, {33, 197, 217, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {25, 194, 214, 255}, {44, 174, 187, 255}, {22, 132, 144, 255}, {19, 134, 148, 255}, {18, 136, 151, 255}, {17, 139, 153, 255}, {17, 141, 154, 255}, {16, 142, 156, 255}, {15, 144, 157, 255}, {14, 144, 159, 255}, {14, 145, 161, 255}, {14, 147, 163, 255}, {14, 149, 163, 255}, {14, 150, 164, 255}, {12, 149, 165, 255}, {12, 150, 165, 255}, {12, 150, 166, 255}, {11, 150, 166, 255}, {12, 152, 166, 255}, {11, 151, 167, 255}, {85, 138, 144, 255}, {68, 84, 94, 255}, {71, 89, 99, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {70, 90, 98, 255}, {71, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {73, 91, 101, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {78, 100, 111, 23}, {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}, {64, 96, 96, 8}, {73, 87, 94, 254}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 87, 94, 255}, {138, 211, 217, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {126, 241, 245, 255}, {63, 203, 222, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {18, 194, 215, 255}, {45, 184, 197, 255}, {24, 138, 149, 255}, {20, 133, 147, 255}, {18, 135, 150, 255}, {18, 138, 152, 255}, {17, 140, 154, 255}, {15, 141, 156, 255}, {15, 143, 157, 255}, {14, 144, 160, 255}, {15, 146, 161, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {13, 149, 164, 255}, {13, 149, 165, 255}, {12, 150, 165, 255}, {12, 150, 166, 255}, {12, 151, 166, 255}, {12, 151, 166, 255}, {11, 151, 166, 255}, {11, 153, 167, 255}, {63, 167, 176, 255}, {66, 83, 92, 255}, {70, 87, 97, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {74, 94, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 96, 105, 245}, {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, 0, 0, 0}, {73, 88, 95, 223}, {72, 86, 94, 255}, {72, 86, 94, 255}, {73, 87, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {89, 127, 133, 255}, {149, 227, 237, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {85, 213, 228, 255}, {25, 194, 216, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 192, 214, 255}, {43, 191, 206, 255}, {31, 146, 160, 255}, {20, 133, 146, 255}, {19, 135, 149, 255}, {18, 138, 151, 255}, {17, 140, 153, 255}, {15, 142, 155, 255}, {15, 143, 157, 255}, {15, 145, 159, 255}, {14, 146, 160, 255}, {14, 146, 162, 255}, {14, 149, 163, 255}, {13, 148, 163, 255}, {14, 150, 165, 255}, {12, 149, 165, 255}, {12, 150, 165, 255}, {13, 152, 167, 255}, {12, 151, 167, 255}, {11, 151, 166, 255}, {10, 152, 167, 255}, {10, 153, 167, 255}, {12, 153, 168, 255}, {79, 116, 121, 255}, {69, 86, 94, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {70, 89, 99, 255}, {71, 90, 100, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {70, 89, 98, 255}, {71, 91, 100, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {76, 95, 105, 206}, {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, 0, 0, 0}, {72, 86, 95, 180}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {122, 189, 195, 255}, {141, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {113, 233, 240, 255}, {50, 201, 220, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {35, 195, 213, 255}, {39, 161, 175, 255}, {20, 132, 145, 255}, {19, 135, 148, 255}, {18, 137, 150, 255}, {17, 139, 153, 255}, {15, 142, 154, 255}, {16, 142, 156, 255}, {14, 144, 158, 255}, {15, 145, 160, 255}, {14, 146, 160, 255}, {14, 147, 163, 255}, {14, 149, 163, 255}, {14, 150, 164, 255}, {13, 149, 166, 255}, {12, 150, 166, 255}, {13, 151, 166, 255}, {12, 151, 166, 255}, {11, 151, 166, 255}, {12, 152, 167, 255}, {11, 152, 167, 255}, {11, 152, 168, 255}, {11, 152, 168, 255}, {81, 166, 171, 255}, {66, 83, 91, 255}, {70, 88, 97, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {72, 90, 99, 255}, {70, 89, 98, 255}, {71, 90, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 97, 255}, {71, 90, 99, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {74, 94, 103, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {77, 96, 105, 160}, {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, 0, 0, 0}, {72, 88, 95, 134}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {80, 106, 112, 255}, {149, 225, 232, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {137, 253, 253, 255}, {79, 210, 225, 255}, {19, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {12, 191, 214, 255}, {12, 191, 214, 255}, {25, 194, 213, 255}, {45, 175, 188, 255}, {20, 131, 143, 255}, {20, 134, 147, 255}, {19, 136, 151, 255}, {18, 140, 153, 255}, {17, 140, 155, 255}, {15, 142, 155, 255}, {15, 143, 158, 255}, {15, 145, 159, 255}, {15, 146, 161, 255}, {15, 147, 162, 255}, {14, 149, 163, 255}, {14, 149, 164, 255}, {13, 149, 165, 255}, {12, 150, 166, 255}, {13, 151, 166, 255}, {11, 151, 166, 255}, {12, 151, 166, 255}, {12, 152, 167, 255}, {12, 152, 167, 255}, {11, 152, 167, 255}, {11, 153, 168, 255}, {11, 153, 168, 255}, {28, 161, 174, 255}, {71, 95, 104, 255}, {70, 87, 96, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 90, 97, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {72, 91, 99, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 106, 115}, {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, 0, 0, 0}, {74, 89, 97, 89}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {110, 168, 172, 255}, {143, 225, 236, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {99, 223, 234, 255}, {40, 198, 217, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {17, 193, 215, 255}, {46, 184, 199, 255}, {24, 139, 149, 255}, {21, 134, 147, 255}, {19, 136, 150, 255}, {17, 138, 151, 255}, {17, 140, 154, 255}, {15, 141, 156, 255}, {15, 143, 157, 255}, {15, 145, 158, 255}, {15, 146, 160, 255}, {15, 147, 162, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {13, 149, 164, 255}, {12, 149, 165, 255}, {12, 151, 166, 255}, {12, 151, 166, 255}, {12, 151, 166, 255}, {12, 152, 168, 255}, {12, 152, 168, 255}, {11, 153, 167, 255}, {11, 153, 168, 255}, {11, 153, 168, 255}, {11, 154, 169, 255}, {11, 153, 168, 255}, {85, 149, 156, 255}, {68, 84, 93, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {73, 93, 102, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 92, 103, 69}, {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, 0, 0, 0}, {75, 87, 93, 41}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {74, 92, 99, 255}, {144, 218, 224, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {132, 247, 249, 255}, {70, 207, 223, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 192, 215, 255}, {43, 192, 207, 255}, {32, 148, 162, 255}, {21, 132, 144, 255}, {19, 135, 149, 255}, {17, 137, 151, 255}, {18, 141, 154, 255}, {16, 143, 156, 255}, {16, 142, 157, 255}, {16, 145, 160, 255}, {15, 146, 160, 255}, {15, 147, 162, 255}, {14, 148, 163, 255}, {13, 148, 163, 255}, {13, 148, 163, 255}, {12, 149, 165, 255}, {14, 151, 165, 255}, {13, 151, 166, 255}, {12, 151, 166, 255}, {12, 153, 167, 255}, {12, 151, 167, 255}, {11, 152, 167, 255}, {11, 153, 168, 255}, {11, 153, 168, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {10, 155, 169, 255}, {51, 166, 178, 255}, {68, 86, 94, 255}, {70, 87, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 90, 99, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 97, 255}, {69, 89, 99, 255}, {70, 90, 99, 255}, {73, 94, 103, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {70, 93, 104, 22}, {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, 0, 0, 0}, {128, 128, 128, 2}, {72, 87, 94, 245}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {96, 142, 147, 255}, {147, 226, 236, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {89, 216, 230, 255}, {29, 195, 216, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {33, 195, 212, 255}, {38, 162, 174, 255}, {21, 132, 145, 255}, {20, 135, 147, 255}, {18, 136, 150, 255}, {18, 139, 154, 255}, {17, 142, 155, 255}, {16, 142, 155, 255}, {15, 144, 158, 255}, {15, 145, 159, 255}, {14, 146, 160, 255}, {15, 147, 162, 255}, {14, 149, 163, 255}, {13, 148, 163, 255}, {14, 150, 165, 255}, {13, 150, 165, 255}, {13, 151, 165, 255}, {11, 151, 166, 255}, {11, 151, 166, 255}, {13, 153, 168, 255}, {12, 152, 168, 255}, {11, 152, 167, 255}, {12, 153, 169, 255}, {11, 153, 168, 255}, {11, 154, 169, 255}, {10, 154, 169, 255}, {11, 153, 169, 255}, {10, 154, 169, 255}, {82, 128, 134, 255}, {67, 85, 93, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {71, 90, 98, 255}, {70, 90, 99, 255}, {72, 92, 100, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {76, 96, 106, 231}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 88, 95, 195}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {133, 202, 208, 255}, {139, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {121, 239, 243, 255}, {58, 202, 222, 255}, {18, 192, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {23, 194, 214, 255}, {46, 176, 190, 255}, {21, 131, 144, 255}, {20, 133, 147, 255}, {20, 137, 151, 255}, {17, 139, 152, 255}, {17, 140, 155, 255}, {15, 142, 155, 255}, {17, 143, 158, 255}, {15, 145, 158, 255}, {15, 145, 160, 255}, {15, 147, 162, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {14, 150, 164, 255}, {13, 151, 165, 255}, {13, 151, 166, 255}, {12, 150, 166, 255}, {12, 151, 166, 255}, {12, 152, 167, 255}, {13, 153, 169, 255}, {11, 153, 167, 255}, {11, 153, 168, 255}, {11, 152, 168, 255}, {11, 154, 169, 255}, {11, 153, 168, 255}, {10, 154, 169, 255}, {11, 155, 169, 255}, {11, 155, 169, 255}, {72, 169, 177, 255}, {65, 83, 91, 255}, {69, 88, 97, 255}, {71, 89, 99, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 90, 98, 255}, {71, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {73, 94, 103, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {76, 96, 106, 175}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 87, 95, 137}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {85, 118, 123, 255}, {149, 227, 237, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {138, 254, 254, 255}, {83, 213, 228, 255}, {22, 193, 215, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {16, 192, 214, 255}, {46, 185, 201, 255}, {23, 138, 150, 255}, {22, 133, 146, 255}, {20, 136, 149, 255}, {19, 138, 151, 255}, {18, 141, 154, 255}, {16, 141, 155, 255}, {17, 143, 158, 255}, {15, 144, 159, 255}, {15, 145, 160, 255}, {16, 147, 162, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {14, 149, 164, 255}, {14, 150, 165, 255}, {13, 151, 166, 255}, {13, 152, 166, 255}, {11, 150, 166, 255}, {13, 153, 167, 255}, {12, 153, 168, 255}, {12, 152, 167, 255}, {11, 152, 167, 255}, {11, 153, 168, 255}, {12, 153, 170, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {11, 154, 170, 255}, {11, 154, 169, 255}, {11, 155, 169, 255}, {16, 157, 171, 255}, {76, 107, 114, 255}, {69, 87, 96, 255}, {72, 90, 99, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 90, 97, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {71, 90, 99, 255}, {70, 90, 100, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {76, 96, 107, 117}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 89, 96, 77}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {117, 181, 186, 255}, {142, 225, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {107, 228, 238, 255}, {45, 199, 219, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 192, 215, 255}, {41, 191, 208, 255}, {32, 148, 162, 255}, {21, 132, 144, 255}, {20, 136, 148, 255}, {18, 137, 151, 255}, {18, 141, 153, 255}, {16, 141, 154, 255}, {15, 142, 156, 255}, {16, 145, 159, 255}, {16, 145, 160, 255}, {15, 146, 161, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {14, 149, 163, 255}, {14, 150, 165, 255}, {13, 150, 165, 255}, {12, 151, 166, 255}, {12, 152, 166, 255}, {12, 151, 166, 255}, {11, 151, 166, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {11, 153, 168, 255}, {11, 153, 168, 255}, {11, 154, 169, 255}, {12, 154, 170, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {10, 155, 170, 255}, {83, 160, 166, 255}, {66, 83, 92, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 90, 99, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {69, 89, 99, 255}, {72, 93, 102, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {76, 94, 103, 57}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 90, 90, 17}, {72, 87, 94, 253}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {72, 86, 94, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {76, 99, 106, 255}, {148, 223, 231, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {136, 251, 251, 255}, {76, 209, 226, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {33, 194, 214, 255}, {41, 163, 177, 255}, {21, 132, 145, 255}, {20, 134, 146, 255}, {19, 137, 149, 255}, {19, 139, 153, 255}, {16, 141, 154, 255}, {15, 141, 155, 255}, {16, 143, 159, 255}, {16, 145, 160, 255}, {15, 145, 160, 255}, {15, 147, 161, 255}, {14, 148, 162, 255}, {14, 149, 164, 255}, {14, 150, 165, 255}, {13, 150, 165, 255}, {13, 152, 166, 255}, {13, 152, 166, 255}, {12, 151, 166, 255}, {13, 153, 167, 255}, {13, 152, 168, 255}, {12, 153, 168, 255}, {11, 153, 168, 255}, {11, 153, 168, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {35, 165, 176, 255}, {70, 92, 99, 255}, {70, 87, 96, 255}, {72, 90, 99, 255}, {70, 88, 98, 255}, {72, 90, 99, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 90, 97, 255}, {71, 90, 99, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 91, 99, 255}, {74, 95, 104, 255}, {74, 95, 104, 247}, {85, 128, 128, 6}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 86, 95, 213}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {104, 157, 162, 255}, {145, 226, 236, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {94, 220, 231, 255}, {35, 197, 217, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {24, 194, 214, 255}, {45, 177, 191, 255}, {21, 130, 143, 255}, {20, 133, 147, 255}, {20, 137, 150, 255}, {18, 139, 152, 255}, {18, 141, 154, 255}, {16, 143, 156, 255}, {16, 143, 157, 255}, {15, 145, 158, 255}, {16, 145, 161, 255}, {14, 147, 161, 255}, {14, 148, 162, 255}, {14, 149, 163, 255}, {14, 149, 164, 255}, {13, 149, 165, 255}, {13, 151, 166, 255}, {13, 152, 166, 255}, {11, 150, 166, 255}, {13, 153, 167, 255}, {13, 153, 168, 255}, {12, 153, 168, 255}, {11, 152, 167, 255}, {11, 153, 168, 255}, {12, 153, 169, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {11, 155, 169, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {10, 155, 171, 255}, {84, 143, 149, 255}, {67, 85, 92, 255}, {70, 88, 98, 255}, {72, 90, 99, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 99, 255}, {70, 89, 99, 255}, {69, 90, 98, 255}, {69, 90, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {72, 93, 101, 255}, {76, 97, 106, 195}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 87, 93, 153}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {72, 87, 94, 255}, {139, 213, 219, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {129, 243, 247, 255}, {64, 204, 222, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {13, 191, 214, 255}, {17, 192, 214, 255}, {46, 185, 200, 255}, {28, 141, 153, 255}, {21, 133, 145, 255}, {20, 136, 149, 255}, {19, 137, 151, 255}, {18, 139, 152, 255}, {17, 142, 156, 255}, {15, 142, 156, 255}, {17, 144, 160, 255}, {15, 145, 159, 255}, {15, 147, 161, 255}, {15, 148, 162, 255}, {14, 149, 163, 255}, {14, 149, 164, 255}, {13, 150, 165, 255}, {14, 150, 165, 255}, {13, 152, 166, 255}, {13, 152, 167, 255}, {12, 152, 167, 255}, {12, 152, 168, 255}, {11, 152, 167, 255}, {11, 153, 167, 255}, {12, 153, 169, 255}, {11, 153, 168, 255}, {11, 154, 169, 255}, {11, 154, 168, 255}, {11, 154, 169, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 169, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {59, 169, 179, 255}, {66, 83, 91, 255}, {70, 88, 97, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {70, 89, 99, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 90, 98, 255}, {69, 90, 99, 255}, {70, 89, 98, 255}, {73, 95, 104, 132}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 89, 96, 80}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {90, 132, 137, 255}, {149, 227, 237, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {86, 213, 229, 255}, {26, 194, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {40, 191, 208, 255}, {35, 151, 165, 255}, {21, 132, 144, 255}, {20, 134, 147, 255}, {18, 137, 150, 255}, {19, 140, 152, 255}, {17, 142, 155, 255}, {16, 143, 156, 255}, {17, 143, 159, 255}, {16, 145, 159, 255}, {15, 146, 161, 255}, {15, 147, 161, 255}, {15, 148, 163, 255}, {14, 149, 164, 255}, {14, 150, 164, 255}, {14, 150, 165, 255}, {13, 151, 166, 255}, {13, 152, 166, 255}, {12, 151, 166, 255}, {13, 153, 167, 255}, {11, 152, 167, 255}, {12, 153, 168, 255}, {11, 153, 168, 255}, {12, 153, 168, 255}, {11, 154, 169, 255}, {12, 153, 169, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 156, 171, 255}, {80, 119, 125, 255}, {69, 86, 95, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 99, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {71, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 90, 99, 255}, {69, 88, 97, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {72, 89, 98, 60}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {77, 77, 102, 10}, {71, 86, 93, 248}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {125, 194, 200, 255}, {140, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {115, 234, 241, 255}, {53, 201, 221, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {18, 192, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {31, 195, 214, 255}, {42, 164, 180, 255}, {22, 130, 143, 255}, {20, 134, 146, 255}, {19, 136, 149, 255}, {18, 138, 153, 255}, {17, 142, 154, 255}, {17, 142, 156, 255}, {17, 143, 159, 255}, {16, 145, 159, 255}, {15, 145, 160, 255}, {16, 147, 162, 255}, {14, 148, 162, 255}, {14, 149, 164, 255}, {13, 149, 164, 255}, {13, 150, 165, 255}, {13, 151, 165, 255}, {13, 151, 165, 255}, {13, 152, 167, 255}, {13, 153, 167, 255}, {12, 153, 168, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {11, 153, 168, 255}, {12, 154, 170, 255}, {12, 154, 169, 255}, {11, 154, 169, 255}, {12, 154, 170, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {10, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 154, 169, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {77, 167, 172, 255}, {67, 84, 93, 255}, {70, 88, 96, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {70, 89, 99, 255}, {69, 90, 98, 255}, {69, 90, 99, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {71, 90, 100, 239}, {85, 85, 170, 3}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {72, 86, 94, 190}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {80, 108, 114, 255}, {149, 225, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {138, 253, 253, 255}, {79, 210, 226, 255}, {20, 193, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {23, 194, 215, 255}, {46, 179, 193, 255}, {22, 132, 145, 255}, {21, 133, 147, 255}, {20, 136, 149, 255}, {19, 138, 152, 255}, {19, 140, 153, 255}, {17, 142, 156, 255}, {16, 143, 157, 255}, {16, 144, 160, 255}, {16, 145, 160, 255}, {15, 146, 161, 255}, {16, 147, 162, 255}, {14, 149, 163, 255}, {15, 149, 164, 255}, {14, 150, 164, 255}, {14, 150, 165, 255}, {13, 151, 166, 255}, {13, 152, 166, 255}, {13, 152, 167, 255}, {12, 152, 167, 255}, {11, 152, 167, 255}, {12, 153, 168, 255}, {11, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {11, 154, 170, 255}, {12, 154, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 154, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {22, 160, 174, 255}, {73, 100, 107, 255}, {70, 86, 95, 255}, {72, 90, 99, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 89, 99, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 97, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {69, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 90, 99, 255}, {72, 89, 100, 171}, {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, 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}, {71, 84, 93, 118}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {111, 172, 176, 255}, {142, 225, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {101, 225, 235, 255}, {41, 199, 218, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 193, 215, 255}, {45, 187, 201, 255}, {29, 141, 153, 255}, {22, 132, 145, 255}, {21, 135, 148, 255}, {19, 137, 151, 255}, {20, 140, 152, 255}, {17, 142, 156, 255}, {17, 143, 156, 255}, {16, 144, 159, 255}, {16, 145, 160, 255}, {14, 147, 161, 255}, {15, 147, 162, 255}, {15, 148, 162, 255}, {15, 149, 164, 255}, {14, 150, 164, 255}, {13, 150, 165, 255}, {13, 152, 166, 255}, {13, 151, 165, 255}, {13, 152, 167, 255}, {12, 152, 167, 255}, {12, 153, 168, 255}, {13, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {12, 154, 170, 255}, {11, 155, 169, 255}, {12, 154, 171, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 154, 169, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {86, 154, 160, 255}, {67, 84, 93, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {70, 89, 99, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {72, 93, 103, 99}, {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, 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}, {70, 87, 93, 44}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {73, 93, 99, 255}, {147, 220, 228, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {132, 248, 250, 255}, {72, 206, 224, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {39, 193, 209, 255}, {36, 152, 166, 255}, {22, 133, 145, 255}, {20, 134, 146, 255}, {19, 138, 150, 255}, {18, 139, 152, 255}, {17, 142, 154, 255}, {16, 142, 156, 255}, {16, 143, 158, 255}, {16, 144, 160, 255}, {15, 146, 160, 255}, {15, 147, 161, 255}, {15, 148, 163, 255}, {14, 149, 164, 255}, {13, 150, 164, 255}, {13, 150, 165, 255}, {13, 151, 165, 255}, {14, 151, 166, 255}, {14, 152, 167, 255}, {12, 152, 166, 255}, {13, 152, 168, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {11, 153, 168, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {11, 154, 169, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {43, 167, 178, 255}, {68, 86, 94, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {72, 90, 99, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {71, 89, 99, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {71, 90, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 89, 98, 255}, {70, 88, 98, 255}, {70, 90, 99, 254}, {71, 92, 102, 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}, {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, 0, 0, 0}, {71, 86, 93, 217}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {98, 147, 152, 255}, {145, 226, 236, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 225, 236, 255}, {163, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {90, 217, 230, 255}, {31, 196, 216, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {31, 195, 215, 255}, {42, 166, 180, 255}, {22, 131, 144, 255}, {21, 134, 147, 255}, {20, 136, 148, 255}, {19, 138, 153, 255}, {18, 142, 154, 255}, {17, 142, 156, 255}, {16, 143, 158, 255}, {16, 144, 160, 255}, {16, 146, 160, 255}, {15, 147, 161, 255}, {16, 147, 162, 255}, {15, 148, 163, 255}, {14, 149, 163, 255}, {15, 150, 165, 255}, {14, 150, 164, 255}, {13, 151, 166, 255}, {12, 152, 166, 255}, {13, 152, 167, 255}, {12, 152, 167, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {11, 155, 169, 255}, {11, 154, 170, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {11, 154, 169, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {83, 133, 139, 255}, {68, 84, 93, 255}, {71, 89, 98, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {71, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 90, 98, 255}, {69, 90, 99, 255}, {69, 89, 97, 255}, {69, 90, 99, 255}, {70, 89, 99, 255}, {70, 91, 99, 200}, {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, 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}, {71, 86, 94, 133}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {135, 207, 213, 255}, {138, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 225, 236, 255}, {163, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {122, 240, 243, 255}, {60, 202, 222, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {21, 194, 214, 255}, {47, 180, 194, 255}, {22, 132, 144, 255}, {21, 134, 147, 255}, {20, 135, 149, 255}, {18, 138, 152, 255}, {19, 140, 153, 255}, {17, 141, 156, 255}, {16, 143, 156, 255}, {17, 144, 159, 255}, {16, 145, 160, 255}, {15, 147, 161, 255}, {16, 147, 162, 255}, {15, 149, 163, 255}, {14, 149, 163, 255}, {14, 149, 164, 255}, {14, 150, 165, 255}, {14, 151, 166, 255}, {13, 151, 166, 255}, {14, 152, 167, 255}, {13, 153, 167, 255}, {12, 153, 168, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 168, 255}, {12, 154, 170, 255}, {11, 154, 169, 255}, {11, 154, 170, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {11, 155, 170, 255}, {12, 154, 170, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {66, 169, 178, 255}, {66, 84, 92, 255}, {69, 88, 96, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 90, 99, 255}, {70, 89, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {72, 92, 101, 114}, {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, 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}, {74, 85, 96, 45}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {71, 86, 93, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {85, 121, 127, 255}, {149, 228, 238, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {141, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {138, 254, 254, 255}, {84, 213, 227, 255}, {23, 194, 215, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 192, 215, 255}, {47, 188, 204, 255}, {29, 141, 154, 255}, {21, 132, 145, 255}, {21, 135, 148, 255}, {19, 137, 149, 255}, {19, 139, 152, 255}, {18, 142, 156, 255}, {17, 143, 156, 255}, {16, 143, 158, 255}, {16, 144, 160, 255}, {16, 146, 161, 255}, {16, 147, 162, 255}, {15, 148, 162, 255}, {15, 149, 164, 255}, {15, 150, 164, 255}, {14, 150, 165, 255}, {13, 151, 166, 255}, {13, 151, 166, 255}, {12, 152, 167, 255}, {13, 153, 167, 255}, {12, 152, 167, 255}, {13, 153, 169, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {11, 154, 169, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {12, 157, 172, 255}, {77, 111, 117, 255}, {67, 84, 94, 255}, {72, 90, 99, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 90, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {70, 89, 99, 255}, {70, 90, 99, 255}, {70, 89, 98, 255}, {70, 88, 98, 254}, {66, 85, 94, 27}, {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, 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}, {71, 86, 93, 213}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {119, 186, 191, 255}, {140, 225, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 225, 236, 255}, {163, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {108, 230, 237, 255}, {48, 199, 220, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {13, 191, 214, 255}, {40, 193, 210, 255}, {38, 155, 168, 255}, {22, 132, 144, 255}, {22, 134, 148, 255}, {20, 137, 151, 255}, {19, 138, 152, 255}, {17, 141, 153, 255}, {18, 142, 156, 255}, {16, 143, 158, 255}, {16, 144, 160, 255}, {16, 146, 161, 255}, {16, 147, 161, 255}, {15, 147, 162, 255}, {15, 149, 163, 255}, {15, 149, 163, 255}, {14, 150, 164, 255}, {13, 150, 165, 255}, {14, 152, 166, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {13, 152, 168, 255}, {13, 153, 169, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {11, 154, 169, 255}, {12, 154, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {11, 154, 170, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {12, 154, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {82, 162, 168, 255}, {66, 83, 91, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {70, 89, 98, 255}, {70, 90, 99, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {71, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 90, 99, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {72, 91, 100, 196}, {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, 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}, {69, 84, 92, 130}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {76, 101, 107, 255}, {149, 224, 232, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {136, 252, 253, 255}, {77, 209, 224, 255}, {17, 193, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {30, 195, 215, 255}, {45, 168, 182, 255}, {23, 131, 143, 255}, {21, 134, 146, 255}, {20, 135, 147, 255}, {19, 137, 152, 255}, {18, 139, 153, 255}, {17, 142, 156, 255}, {17, 144, 157, 255}, {16, 143, 158, 255}, {16, 145, 160, 255}, {15, 147, 161, 255}, {15, 147, 161, 255}, {15, 149, 163, 255}, {15, 149, 163, 255}, {15, 150, 164, 255}, {14, 150, 165, 255}, {14, 151, 165, 255}, {14, 151, 166, 255}, {13, 152, 167, 255}, {12, 152, 167, 255}, {12, 153, 168, 255}, {12, 153, 168, 255}, {12, 153, 169, 255}, {12, 153, 168, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 154, 170, 255}, {11, 154, 170, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {30, 162, 176, 255}, {71, 94, 101, 255}, {68, 87, 95, 255}, {70, 89, 98, 255}, {72, 90, 99, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {70, 90, 97, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {69, 90, 98, 255}, {69, 90, 98, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {70, 89, 99, 255}, {70, 89, 98, 255}, {70, 88, 100, 110}, {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, 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}, {67, 87, 94, 38}, {70, 85, 92, 254}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {105, 161, 167, 255}, {143, 225, 236, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {97, 221, 232, 255}, {36, 198, 217, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {21, 194, 215, 255}, {48, 181, 196, 255}, {23, 134, 145, 255}, {21, 133, 145, 255}, {22, 135, 149, 255}, {20, 138, 151, 255}, {19, 139, 153, 255}, {18, 141, 155, 255}, {17, 143, 156, 255}, {17, 144, 158, 255}, {16, 144, 160, 255}, {16, 146, 161, 255}, {15, 147, 161, 255}, {15, 148, 163, 255}, {15, 149, 164, 255}, {15, 150, 164, 255}, {15, 150, 165, 255}, {13, 150, 165, 255}, {14, 151, 165, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {12, 152, 167, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 169, 255}, {11, 155, 170, 255}, {11, 154, 169, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {85, 146, 152, 255}, {66, 84, 93, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {70, 88, 99, 255}, {70, 89, 98, 255}, {71, 90, 99, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {69, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 88, 99, 251}, {67, 89, 100, 23}, {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, 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}, {70, 85, 92, 193}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {71, 89, 95, 255}, {142, 214, 220, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {130, 245, 249, 255}, {67, 204, 222, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 193, 215, 255}, {46, 189, 205, 255}, {31, 144, 157, 255}, {22, 132, 144, 255}, {22, 135, 148, 255}, {19, 137, 149, 255}, {19, 139, 152, 255}, {19, 141, 154, 255}, {16, 141, 156, 255}, {17, 144, 158, 255}, {17, 144, 159, 255}, {16, 146, 161, 255}, {15, 147, 161, 255}, {16, 148, 162, 255}, {15, 149, 163, 255}, {15, 149, 164, 255}, {14, 149, 165, 255}, {15, 150, 165, 255}, {14, 151, 165, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {13, 153, 167, 255}, {12, 153, 168, 255}, {13, 154, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 169, 255}, {12, 154, 169, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 156, 170, 255}, {12, 155, 171, 255}, {11, 154, 169, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {53, 168, 179, 255}, {66, 84, 92, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {71, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {71, 90, 101, 175}, {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, 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}, {71, 85, 93, 93}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {92, 137, 142, 255}, {147, 226, 236, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {87, 216, 227, 255}, {26, 195, 215, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {38, 194, 210, 255}, {38, 155, 169, 255}, {22, 130, 143, 255}, {20, 133, 146, 255}, {21, 137, 150, 255}, {20, 137, 152, 255}, {19, 141, 153, 255}, {17, 141, 156, 255}, {17, 143, 157, 255}, {16, 143, 159, 255}, {16, 146, 161, 255}, {16, 146, 161, 255}, {16, 147, 162, 255}, {15, 148, 162, 255}, {15, 149, 163, 255}, {14, 150, 164, 255}, {14, 149, 165, 255}, {14, 152, 166, 255}, {13, 151, 165, 255}, {12, 151, 167, 255}, {13, 153, 167, 255}, {13, 153, 168, 255}, {14, 154, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 154, 170, 255}, {11, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 154, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {81, 123, 130, 255}, {66, 84, 94, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 90, 98, 255}, {70, 90, 100, 255}, {70, 88, 98, 255}, {71, 92, 99, 75}, {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, 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}, {73, 73, 109, 7}, {72, 86, 93, 238}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {128, 198, 204, 255}, {139, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {117, 236, 241, 255}, {55, 202, 221, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {29, 195, 214, 255}, {46, 171, 185, 255}, {23, 130, 143, 255}, {21, 134, 147, 255}, {21, 135, 149, 255}, {20, 138, 151, 255}, {19, 139, 153, 255}, {18, 141, 155, 255}, {17, 143, 156, 255}, {18, 144, 159, 255}, {17, 145, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {15, 148, 162, 255}, {15, 149, 163, 255}, {15, 149, 163, 255}, {15, 150, 165, 255}, {14, 151, 165, 255}, {13, 152, 166, 255}, {13, 151, 167, 255}, {14, 153, 167, 255}, {14, 153, 168, 255}, {12, 153, 168, 255}, {13, 153, 168, 255}, {12, 153, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 155, 172, 255}, {12, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {75, 168, 175, 255}, {65, 83, 91, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 88, 98, 255}, {71, 89, 98, 255}, {71, 89, 99, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 90, 97, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {70, 90, 97, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 99, 255}, {69, 89, 98, 255}, {69, 90, 98, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 88, 98, 255}, {71, 90, 100, 225}, {128, 128, 128, 2}, {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, 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}, {69, 85, 94, 147}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {81, 112, 118, 255}, {148, 227, 236, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {138, 253, 254, 255}, {79, 211, 227, 255}, {20, 193, 215, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {20, 193, 215, 255}, {48, 182, 197, 255}, {24, 134, 146, 255}, {21, 132, 145, 255}, {21, 134, 148, 255}, {19, 137, 149, 255}, {20, 139, 153, 255}, {17, 140, 155, 255}, {18, 142, 156, 255}, {17, 143, 157, 255}, {17, 144, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {16, 147, 162, 255}, {15, 149, 163, 255}, {15, 149, 164, 255}, {15, 150, 165, 255}, {14, 150, 165, 255}, {14, 151, 166, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {12, 152, 167, 255}, {14, 153, 169, 255}, {12, 153, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {20, 159, 173, 255}, {73, 103, 109, 255}, {68, 86, 95, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 89, 99, 255}, {70, 89, 98, 255}, {70, 89, 99, 255}, {71, 89, 99, 129}, {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, 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}, {74, 85, 96, 45}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {112, 176, 181, 255}, {141, 225, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {103, 226, 235, 255}, {44, 199, 218, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 193, 215, 255}, {44, 188, 205, 255}, {33, 145, 157, 255}, {23, 132, 144, 255}, {20, 134, 147, 255}, {21, 137, 150, 255}, {19, 139, 151, 255}, {19, 140, 155, 255}, {18, 142, 156, 255}, {17, 143, 157, 255}, {17, 143, 159, 255}, {16, 146, 160, 255}, {16, 147, 161, 255}, {16, 147, 162, 255}, {15, 148, 163, 255}, {15, 149, 163, 255}, {15, 150, 164, 255}, {14, 150, 165, 255}, {13, 152, 166, 255}, {14, 151, 166, 255}, {12, 151, 167, 255}, {14, 153, 167, 255}, {12, 152, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {12, 154, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 154, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {84, 157, 162, 255}, {65, 83, 92, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {69, 88, 97, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 90, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 99, 255}, {71, 90, 99, 252}, {70, 88, 97, 29}, {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, 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}, {70, 86, 93, 187}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {70, 85, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {73, 95, 101, 255}, {146, 221, 230, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {135, 250, 252, 255}, {73, 208, 224, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {37, 194, 211, 255}, {39, 156, 170, 255}, {23, 130, 144, 255}, {21, 134, 147, 255}, {21, 136, 149, 255}, {20, 137, 151, 255}, {19, 140, 153, 255}, {18, 141, 155, 255}, {18, 143, 157, 255}, {17, 143, 158, 255}, {17, 145, 160, 255}, {16, 147, 161, 255}, {16, 147, 162, 255}, {17, 149, 163, 255}, {15, 149, 163, 255}, {15, 149, 163, 255}, {14, 149, 165, 255}, {15, 151, 165, 255}, {14, 151, 165, 255}, {13, 152, 167, 255}, {14, 152, 167, 255}, {13, 152, 167, 255}, {12, 153, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {11, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {38, 165, 178, 255}, {68, 88, 95, 255}, {70, 88, 96, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 99, 255}, {69, 89, 99, 255}, {69, 90, 98, 255}, {69, 89, 98, 255}, {69, 90, 98, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {71, 89, 98, 169}, {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, 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}, {70, 87, 94, 73}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {98, 150, 156, 255}, {144, 226, 236, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {91, 218, 231, 255}, {31, 196, 217, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {27, 194, 214, 255}, {45, 171, 185, 255}, {23, 130, 143, 255}, {22, 132, 145, 255}, {22, 135, 149, 255}, {20, 137, 151, 255}, {19, 138, 153, 255}, {18, 141, 154, 255}, {18, 142, 156, 255}, {17, 143, 158, 255}, {17, 145, 159, 255}, {16, 146, 160, 255}, {15, 147, 161, 255}, {15, 147, 161, 255}, {15, 148, 163, 255}, {15, 149, 164, 255}, {14, 149, 165, 255}, {14, 150, 165, 255}, {14, 151, 166, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {13, 152, 167, 255}, {12, 153, 168, 255}, {13, 154, 168, 255}, {12, 153, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {84, 138, 144, 255}, {67, 83, 92, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 88, 97, 255}, {70, 89, 97, 255}, {71, 89, 98, 255}, {69, 88, 97, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {71, 89, 99, 255}, {70, 89, 97, 255}, {69, 88, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 90, 98, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 89, 99, 255}, {71, 90, 99, 54}, {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, 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}, {71, 86, 92, 211}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {70, 85, 93, 255}, {136, 210, 216, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {125, 241, 245, 255}, {62, 203, 222, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {19, 194, 215, 255}, {47, 183, 197, 255}, {26, 135, 147, 255}, {23, 133, 144, 255}, {21, 134, 148, 255}, {20, 136, 150, 255}, {20, 138, 153, 255}, {18, 140, 154, 255}, {18, 142, 155, 255}, {16, 143, 157, 255}, {18, 145, 159, 255}, {16, 146, 161, 255}, {17, 147, 161, 255}, {16, 147, 162, 255}, {16, 149, 164, 255}, {15, 149, 164, 255}, {14, 149, 164, 255}, {14, 150, 165, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {12, 153, 168, 255}, {13, 153, 169, 255}, {12, 153, 168, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {62, 169, 178, 255}, {65, 82, 90, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 90, 97, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 100, 194}, {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, 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}, {71, 84, 92, 97}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {86, 125, 131, 255}, {148, 227, 237, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {84, 212, 228, 255}, {23, 194, 216, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 192, 215, 255}, {44, 189, 205, 255}, {34, 145, 159, 255}, {23, 131, 143, 255}, {22, 134, 147, 255}, {20, 136, 149, 255}, {20, 139, 151, 255}, {17, 140, 154, 255}, {18, 142, 155, 255}, {18, 143, 157, 255}, {18, 144, 158, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {16, 147, 162, 255}, {15, 148, 162, 255}, {15, 148, 163, 255}, {15, 151, 165, 255}, {14, 150, 165, 255}, {16, 151, 166, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {13, 152, 167, 255}, {14, 153, 168, 255}, {12, 153, 168, 255}, {13, 153, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {78, 115, 121, 255}, {68, 85, 93, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {71, 89, 98, 255}, {69, 88, 96, 255}, {71, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {71, 90, 100, 79}, {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, 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}, {102, 102, 102, 5}, {70, 85, 92, 229}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {122, 189, 194, 255}, {139, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {111, 232, 238, 255}, {49, 201, 220, 255}, {16, 192, 214, 255}, {17, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {37, 195, 212, 255}, {40, 159, 173, 255}, {23, 130, 144, 255}, {21, 133, 145, 255}, {19, 135, 147, 255}, {20, 137, 151, 255}, {18, 139, 153, 255}, {18, 141, 155, 255}, {18, 143, 157, 255}, {17, 143, 158, 255}, {16, 144, 159, 255}, {16, 146, 161, 255}, {16, 146, 161, 255}, {16, 148, 163, 255}, {16, 150, 164, 255}, {14, 148, 163, 255}, {15, 150, 164, 255}, {14, 150, 165, 255}, {14, 151, 166, 255}, {13, 152, 166, 255}, {13, 152, 167, 255}, {14, 153, 167, 255}, {12, 153, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {12, 154, 170, 255}, {12, 154, 169, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {79, 164, 170, 255}, {66, 83, 90, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {71, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 90, 99, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {69, 89, 98, 255}, {70, 89, 100, 215}, {255, 255, 255, 1}, {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, 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}, {71, 85, 92, 111}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {78, 104, 110, 255}, {148, 225, 232, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {137, 252, 253, 255}, {77, 210, 225, 255}, {17, 192, 215, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {26, 194, 213, 255}, {46, 173, 186, 255}, {24, 129, 143, 255}, {22, 132, 145, 255}, {21, 135, 149, 255}, {20, 136, 151, 255}, {20, 139, 152, 255}, {18, 140, 154, 255}, {18, 142, 155, 255}, {18, 143, 158, 255}, {17, 144, 158, 255}, {17, 146, 161, 255}, {16, 148, 162, 255}, {16, 147, 162, 255}, {16, 149, 163, 255}, {15, 149, 164, 255}, {14, 150, 164, 255}, {14, 150, 165, 255}, {15, 151, 167, 255}, {14, 151, 166, 255}, {14, 152, 167, 255}, {14, 153, 167, 255}, {14, 153, 168, 255}, {13, 154, 168, 255}, {13, 153, 169, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {27, 162, 175, 255}, {71, 95, 103, 255}, {68, 85, 94, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {71, 89, 98, 255}, {69, 88, 97, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 88, 97, 255}, {70, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 97, 255}, {70, 88, 98, 255}, {70, 90, 99, 255}, {70, 88, 98, 255}, {72, 91, 100, 92}, {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, 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}, {85, 85, 85, 6}, {69, 84, 92, 227}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {108, 166, 171, 255}, {142, 225, 236, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {97, 224, 234, 255}, {39, 198, 218, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {18, 193, 215, 255}, {47, 184, 199, 255}, {26, 135, 145, 255}, {23, 133, 144, 255}, {21, 134, 147, 255}, {21, 137, 150, 255}, {19, 138, 152, 255}, {17, 139, 154, 255}, {18, 142, 155, 255}, {17, 143, 157, 255}, {18, 144, 158, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {16, 148, 162, 255}, {16, 147, 162, 255}, {16, 150, 164, 255}, {15, 149, 163, 255}, {14, 149, 165, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {12, 152, 168, 255}, {12, 153, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {85, 151, 156, 255}, {67, 83, 91, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {71, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {71, 89, 99, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {70, 91, 99, 214}, {128, 128, 128, 2}, {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, 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}, {70, 87, 92, 105}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {71, 89, 96, 255}, {143, 217, 224, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {131, 247, 249, 255}, {69, 207, 223, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 192, 215, 255}, {43, 190, 207, 255}, {34, 147, 160, 255}, {25, 132, 143, 255}, {22, 134, 147, 255}, {20, 136, 149, 255}, {20, 137, 151, 255}, {18, 139, 154, 255}, {19, 141, 154, 255}, {18, 143, 157, 255}, {18, 144, 158, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {17, 148, 162, 255}, {16, 147, 162, 255}, {15, 149, 163, 255}, {15, 149, 163, 255}, {14, 150, 165, 255}, {15, 150, 165, 255}, {15, 152, 167, 255}, {14, 152, 166, 255}, {13, 152, 167, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {12, 154, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {48, 167, 178, 255}, {66, 84, 92, 255}, {68, 88, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {70, 89, 99, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 90, 99, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {69, 88, 98, 255}, {70, 88, 100, 87}, {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, 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}, {102, 102, 102, 5}, {70, 85, 93, 223}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {94, 140, 147, 255}, {146, 226, 236, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {88, 216, 230, 255}, {27, 194, 216, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {35, 195, 212, 255}, {40, 160, 173, 255}, {24, 129, 143, 255}, {22, 133, 145, 255}, {20, 134, 148, 255}, {20, 136, 151, 255}, {19, 139, 152, 255}, {19, 140, 154, 255}, {18, 143, 156, 255}, {17, 143, 157, 255}, {17, 144, 158, 255}, {16, 145, 161, 255}, {15, 146, 161, 255}, {17, 148, 163, 255}, {16, 149, 163, 255}, {16, 150, 165, 255}, {16, 151, 165, 255}, {15, 150, 165, 255}, {14, 151, 165, 255}, {14, 151, 166, 255}, {13, 151, 167, 255}, {14, 153, 167, 255}, {13, 152, 167, 255}, {14, 153, 168, 255}, {13, 153, 169, 255}, {12, 153, 169, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 156, 170, 255}, {12, 155, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {83, 128, 134, 255}, {66, 85, 92, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {71, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 90, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {70, 90, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 99, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 90, 99, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {71, 89, 99, 209}, {255, 255, 255, 1}, {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, 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, 0, 0}, {70, 85, 93, 99}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 84, 92, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {131, 201, 208, 255}, {137, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {120, 239, 243, 255}, {57, 202, 222, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {24, 194, 214, 255}, {46, 175, 188, 255}, {23, 129, 142, 255}, {22, 132, 145, 255}, {21, 134, 148, 255}, {20, 136, 150, 255}, {20, 138, 151, 255}, {18, 140, 154, 255}, {18, 142, 155, 255}, {16, 143, 157, 255}, {17, 144, 158, 255}, {17, 146, 161, 255}, {16, 147, 161, 255}, {16, 148, 162, 255}, {16, 148, 163, 255}, {15, 149, 164, 255}, {15, 149, 163, 255}, {14, 150, 165, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {13, 152, 166, 255}, {13, 153, 167, 255}, {14, 153, 167, 255}, {13, 154, 168, 255}, {13, 153, 168, 255}, {12, 153, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 154, 170, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {70, 169, 176, 255}, {65, 83, 91, 255}, {69, 87, 96, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {71, 89, 98, 255}, {70, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {69, 90, 98, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {72, 91, 101, 81}, {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, 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, 0, 0}, {0, 0, 0, 0}, {128, 128, 128, 2}, {70, 85, 92, 205}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {82, 115, 121, 255}, {148, 227, 237, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {137, 254, 254, 255}, {81, 212, 227, 255}, {20, 194, 215, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {18, 192, 214, 255}, {47, 185, 198, 255}, {27, 137, 149, 255}, {24, 132, 144, 255}, {22, 134, 147, 255}, {21, 137, 150, 255}, {20, 137, 151, 255}, {19, 139, 154, 255}, {18, 141, 154, 255}, {18, 143, 157, 255}, {18, 144, 158, 255}, {17, 146, 160, 255}, {17, 147, 161, 255}, {16, 146, 161, 255}, {16, 148, 162, 255}, {15, 149, 163, 255}, {16, 150, 165, 255}, {14, 150, 164, 255}, {15, 150, 165, 255}, {15, 152, 167, 255}, {14, 152, 166, 255}, {14, 152, 168, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {14, 157, 172, 255}, {75, 107, 112, 255}, {68, 85, 94, 255}, {70, 88, 97, 255}, {68, 88, 96, 255}, {70, 89, 98, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {70, 89, 99, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {70, 88, 98, 255}, {70, 88, 98, 255}, {70, 90, 100, 189}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {70, 83, 93, 55}, {70, 84, 92, 253}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {115, 180, 185, 255}, {140, 225, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {105, 228, 237, 255}, {45, 200, 219, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 192, 215, 255}, {43, 190, 207, 255}, {35, 149, 160, 255}, {25, 130, 143, 255}, {22, 133, 145, 255}, {20, 136, 149, 255}, {21, 138, 151, 255}, {19, 139, 152, 255}, {18, 140, 154, 255}, {19, 143, 157, 255}, {16, 143, 157, 255}, {18, 145, 160, 255}, {17, 147, 160, 255}, {16, 147, 161, 255}, {16, 148, 162, 255}, {15, 148, 162, 255}, {16, 150, 165, 255}, {15, 149, 164, 255}, {14, 150, 165, 255}, {15, 151, 166, 255}, {14, 151, 165, 255}, {13, 152, 167, 255}, {14, 152, 167, 255}, {13, 152, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 155, 170, 255}, {13, 154, 169, 255}, {12, 155, 170, 255}, {13, 155, 170, 255}, {12, 155, 170, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {13, 156, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {83, 160, 166, 255}, {66, 83, 91, 255}, {68, 89, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {71, 89, 98, 255}, {70, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 87, 97, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {70, 89, 98, 249}, {70, 89, 102, 40}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {70, 84, 91, 154}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {73, 97, 103, 255}, {146, 223, 230, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {135, 251, 251, 255}, {75, 209, 225, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {33, 194, 214, 255}, {44, 163, 175, 255}, {24, 129, 143, 255}, {22, 132, 144, 255}, {21, 134, 147, 255}, {20, 136, 151, 255}, {19, 139, 152, 255}, {19, 139, 154, 255}, {18, 142, 156, 255}, {17, 143, 157, 255}, {17, 143, 158, 255}, {17, 146, 160, 255}, {17, 147, 161, 255}, {17, 148, 163, 255}, {15, 147, 161, 255}, {15, 149, 163, 255}, {15, 149, 164, 255}, {15, 151, 166, 255}, {15, 151, 165, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {14, 152, 168, 255}, {13, 153, 168, 255}, {12, 153, 168, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {34, 164, 176, 255}, {69, 90, 98, 255}, {68, 87, 96, 255}, {70, 88, 97, 255}, {69, 88, 96, 255}, {68, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 87, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {70, 88, 98, 255}, {72, 91, 100, 135}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {75, 90, 90, 17}, {70, 84, 93, 234}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {101, 156, 161, 255}, {143, 226, 236, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {140, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {93, 220, 231, 255}, {32, 196, 217, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {25, 194, 214, 255}, {47, 177, 191, 255}, {24, 128, 141, 255}, {22, 131, 144, 255}, {22, 134, 148, 255}, {21, 137, 150, 255}, {21, 138, 151, 255}, {18, 139, 154, 255}, {19, 141, 154, 255}, {18, 143, 157, 255}, {17, 144, 157, 255}, {17, 145, 160, 255}, {17, 147, 161, 255}, {17, 147, 162, 255}, {16, 148, 162, 255}, {15, 149, 163, 255}, {16, 150, 164, 255}, {16, 151, 166, 255}, {15, 150, 165, 255}, {15, 151, 166, 255}, {14, 152, 166, 255}, {15, 152, 168, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {84, 142, 148, 255}, {65, 84, 91, 255}, {70, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 88, 96, 255}, {71, 89, 98, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 89, 99, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {71, 90, 99, 224}, {77, 102, 102, 10}, {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, 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, 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}, {70, 85, 93, 99}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {70, 85, 92, 255}, {137, 212, 219, 255}, {136, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {128, 243, 247, 255}, {63, 204, 222, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {18, 192, 214, 255}, {46, 186, 200, 255}, {30, 139, 151, 255}, {23, 131, 143, 255}, {22, 133, 146, 255}, {21, 135, 149, 255}, {20, 137, 151, 255}, {18, 139, 153, 255}, {18, 141, 154, 255}, {19, 143, 157, 255}, {16, 143, 157, 255}, {18, 145, 160, 255}, {18, 147, 161, 255}, {17, 147, 161, 255}, {15, 147, 162, 255}, {16, 149, 163, 255}, {16, 150, 164, 255}, {15, 150, 164, 255}, {15, 150, 165, 255}, {14, 151, 165, 255}, {15, 151, 166, 255}, {14, 152, 166, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 153, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 156, 170, 255}, {13, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {59, 169, 179, 255}, {65, 82, 90, 255}, {69, 87, 96, 255}, {69, 88, 96, 255}, {70, 89, 98, 255}, {68, 88, 96, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 87, 97, 255}, {70, 88, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {70, 88, 98, 255}, {72, 91, 101, 81}, {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, 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, 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}, {67, 84, 91, 197}, {69, 83, 91, 255}, {69, 83, 91, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {88, 130, 135, 255}, {147, 227, 237, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {84, 213, 229, 255}, {24, 194, 215, 255}, {16, 192, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {42, 191, 207, 255}, {36, 149, 162, 255}, {24, 130, 142, 255}, {23, 132, 144, 255}, {21, 135, 148, 255}, {21, 137, 151, 255}, {19, 139, 152, 255}, {18, 140, 154, 255}, {19, 142, 155, 255}, {18, 143, 158, 255}, {17, 145, 159, 255}, {17, 146, 161, 255}, {16, 146, 161, 255}, {16, 147, 162, 255}, {16, 148, 163, 255}, {15, 149, 163, 255}, {16, 150, 165, 255}, {15, 150, 165, 255}, {15, 151, 165, 255}, {15, 151, 166, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {13, 152, 168, 255}, {14, 154, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 156, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 156, 171, 255}, {78, 118, 123, 255}, {67, 84, 93, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {71, 89, 98, 255}, {70, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 88, 98, 255}, {69, 88, 98, 255}, {68, 88, 96, 255}, {69, 89, 97, 255}, {71, 89, 98, 180}, {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, 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, 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}, {67, 83, 89, 46}, {70, 84, 91, 251}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {124, 194, 198, 255}, {138, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {114, 234, 240, 255}, {51, 201, 221, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {32, 195, 214, 255}, {44, 165, 179, 255}, {24, 129, 141, 255}, {22, 132, 144, 255}, {23, 134, 146, 255}, {21, 135, 151, 255}, {19, 138, 151, 255}, {18, 139, 153, 255}, {18, 142, 155, 255}, {18, 143, 157, 255}, {17, 143, 157, 255}, {17, 145, 160, 255}, {16, 146, 160, 255}, {17, 147, 162, 255}, {15, 147, 161, 255}, {16, 150, 164, 255}, {15, 149, 164, 255}, {15, 151, 165, 255}, {15, 150, 165, 255}, {15, 151, 166, 255}, {15, 151, 166, 255}, {14, 152, 167, 255}, {14, 153, 167, 255}, {14, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 154, 169, 255}, {12, 153, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {12, 154, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {77, 167, 172, 255}, {65, 82, 91, 255}, {70, 88, 97, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {68, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 246}, {70, 85, 100, 33}, {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, 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, 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}, {69, 83, 92, 144}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {77, 105, 112, 255}, {148, 225, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {137, 253, 253, 255}, {78, 209, 226, 255}, {18, 193, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {24, 194, 215, 255}, {47, 178, 192, 255}, {23, 129, 142, 255}, {23, 130, 143, 255}, {22, 133, 147, 255}, {21, 136, 149, 255}, {20, 137, 151, 255}, {19, 139, 153, 255}, {18, 140, 154, 255}, {18, 143, 156, 255}, {18, 143, 158, 255}, {18, 145, 160, 255}, {17, 147, 160, 255}, {17, 147, 161, 255}, {17, 148, 163, 255}, {16, 148, 162, 255}, {16, 150, 165, 255}, {15, 150, 165, 255}, {14, 150, 165, 255}, {15, 151, 166, 255}, {14, 151, 165, 255}, {14, 152, 167, 255}, {13, 152, 166, 255}, {13, 152, 167, 255}, {13, 153, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 170, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {22, 160, 174, 255}, {72, 98, 105, 255}, {69, 85, 94, 255}, {68, 89, 97, 255}, {69, 88, 96, 255}, {68, 88, 96, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 90, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 90, 98, 125}, {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, 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, 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}, {64, 85, 85, 12}, {70, 85, 92, 229}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {109, 170, 176, 255}, {141, 225, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 225, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {99, 224, 235, 255}, {39, 198, 218, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {17, 193, 215, 255}, {47, 186, 202, 255}, {29, 140, 151, 255}, {24, 130, 143, 255}, {22, 134, 146, 255}, {20, 134, 149, 255}, {21, 138, 151, 255}, {19, 139, 153, 255}, {18, 139, 154, 255}, {18, 142, 155, 255}, {18, 143, 157, 255}, {18, 145, 159, 255}, {17, 146, 160, 255}, {16, 146, 160, 255}, {17, 148, 163, 255}, {16, 147, 162, 255}, {16, 150, 164, 255}, {16, 150, 165, 255}, {14, 149, 165, 255}, {15, 151, 165, 255}, {14, 151, 166, 255}, {13, 152, 166, 255}, {15, 152, 168, 255}, {14, 152, 168, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 153, 169, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {85, 154, 159, 255}, {65, 82, 91, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 89, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {70, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {70, 89, 98, 255}, {71, 89, 99, 217}, {73, 109, 109, 7}, {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, 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, 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}, {68, 83, 92, 86}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {69, 83, 91, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {71, 90, 97, 255}, {145, 220, 227, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {131, 248, 250, 255}, {71, 206, 224, 255}, {15, 191, 214, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {42, 194, 209, 255}, {37, 152, 165, 255}, {23, 130, 142, 255}, {22, 132, 145, 255}, {21, 134, 148, 255}, {22, 137, 150, 255}, {19, 138, 151, 255}, {18, 139, 153, 255}, {19, 142, 155, 255}, {18, 143, 157, 255}, {17, 144, 159, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {17, 147, 162, 255}, {16, 148, 162, 255}, {16, 149, 164, 255}, {15, 150, 164, 255}, {16, 151, 165, 255}, {14, 150, 165, 255}, {15, 151, 167, 255}, {14, 152, 166, 255}, {15, 152, 168, 255}, {13, 152, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 156, 170, 255}, {13, 156, 170, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {42, 167, 177, 255}, {67, 85, 93, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 88, 98, 255}, {68, 89, 96, 255}, {69, 89, 98, 254}, {71, 90, 98, 68}, {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, 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, 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}, {69, 86, 90, 155}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {95, 146, 151, 255}, {144, 225, 236, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 225, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {89, 216, 230, 255}, {29, 195, 216, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {31, 195, 215, 255}, {45, 166, 180, 255}, {23, 129, 141, 255}, {22, 132, 145, 255}, {23, 134, 146, 255}, {21, 135, 151, 255}, {19, 138, 151, 255}, {19, 139, 153, 255}, {19, 141, 155, 255}, {18, 143, 156, 255}, {18, 144, 157, 255}, {16, 144, 159, 255}, {17, 146, 161, 255}, {16, 147, 161, 255}, {16, 147, 162, 255}, {16, 149, 163, 255}, {15, 149, 163, 255}, {16, 150, 165, 255}, {14, 149, 165, 255}, {14, 151, 166, 255}, {15, 151, 167, 255}, {14, 152, 167, 255}, {13, 152, 167, 255}, {13, 152, 167, 255}, {13, 153, 168, 255}, {13, 153, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {13, 155, 170, 255}, {12, 154, 171, 255}, {13, 156, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {83, 133, 139, 255}, {66, 84, 91, 255}, {69, 88, 96, 255}, {69, 89, 98, 255}, {69, 88, 96, 255}, {68, 89, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 87, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 97, 255}, {70, 90, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 90, 99, 136}, {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, 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, 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}, {64, 96, 96, 8}, {68, 83, 91, 210}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {134, 206, 213, 255}, {136, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {121, 239, 243, 255}, {58, 202, 222, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {23, 194, 214, 255}, {47, 180, 193, 255}, {24, 131, 143, 255}, {22, 130, 143, 255}, {22, 134, 147, 255}, {21, 135, 148, 255}, {20, 137, 151, 255}, {19, 138, 152, 255}, {18, 140, 153, 255}, {18, 142, 155, 255}, {17, 142, 157, 255}, {18, 145, 159, 255}, {16, 145, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {16, 147, 162, 255}, {16, 150, 164, 255}, {16, 150, 165, 255}, {15, 150, 165, 255}, {14, 150, 165, 255}, {15, 151, 167, 255}, {14, 151, 166, 255}, {14, 152, 167, 255}, {14, 153, 167, 255}, {13, 154, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {12, 154, 170, 255}, {13, 154, 169, 255}, {13, 155, 171, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {65, 169, 177, 255}, {65, 83, 91, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {69, 89, 99, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 98, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 97, 255}, {70, 91, 100, 197}, {128, 128, 128, 4}, {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, 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, 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}, {70, 83, 89, 40}, {68, 83, 91, 243}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {83, 120, 125, 255}, {148, 227, 238, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 224, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {137, 254, 254, 255}, {81, 212, 227, 255}, {21, 193, 215, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 192, 215, 255}, {47, 187, 204, 255}, {31, 140, 151, 255}, {23, 130, 142, 255}, {23, 133, 146, 255}, {20, 134, 148, 255}, {21, 137, 150, 255}, {20, 140, 153, 255}, {19, 140, 153, 255}, {18, 141, 155, 255}, {18, 143, 156, 255}, {17, 145, 158, 255}, {17, 145, 160, 255}, {17, 147, 160, 255}, {17, 147, 162, 255}, {17, 148, 163, 255}, {16, 150, 164, 255}, {16, 150, 165, 255}, {15, 150, 164, 255}, {14, 150, 165, 255}, {15, 151, 167, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {14, 152, 168, 255}, {14, 152, 168, 255}, {13, 153, 168, 255}, {13, 153, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {13, 155, 171, 255}, {13, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 170, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {12, 157, 172, 255}, {77, 110, 117, 255}, {66, 84, 93, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {68, 89, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 99, 255}, {69, 87, 97, 255}, {68, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {70, 89, 98, 236}, {73, 91, 100, 28}, {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, 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, 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}, {69, 83, 91, 92}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {119, 185, 190, 255}, {138, 225, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {108, 230, 238, 255}, {47, 200, 219, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {41, 193, 210, 255}, {38, 155, 168, 255}, {23, 130, 142, 255}, {23, 131, 144, 255}, {21, 134, 147, 255}, {21, 135, 150, 255}, {19, 138, 151, 255}, {19, 140, 153, 255}, {18, 141, 155, 255}, {18, 143, 156, 255}, {17, 145, 158, 255}, {17, 145, 159, 255}, {17, 147, 160, 255}, {16, 147, 161, 255}, {17, 148, 163, 255}, {16, 149, 163, 255}, {16, 150, 164, 255}, {15, 149, 163, 255}, {14, 149, 165, 255}, {15, 151, 165, 255}, {14, 151, 165, 255}, {14, 152, 167, 255}, {14, 153, 168, 255}, {14, 152, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {81, 162, 169, 255}, {64, 82, 90, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {68, 89, 97, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {68, 89, 97, 255}, {70, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 89, 99, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {68, 89, 97, 254}, {70, 91, 97, 76}, {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, 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, 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}, {69, 84, 90, 158}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {75, 99, 105, 255}, {146, 223, 232, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 224, 236, 255}, {162, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {135, 252, 253, 255}, {76, 208, 223, 255}, {16, 192, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {31, 195, 215, 255}, {45, 168, 182, 255}, {24, 129, 141, 255}, {23, 131, 145, 255}, {23, 133, 146, 255}, {21, 135, 149, 255}, {19, 138, 151, 255}, {19, 138, 152, 255}, {18, 141, 154, 255}, {19, 142, 156, 255}, {18, 143, 157, 255}, {18, 145, 159, 255}, {17, 146, 161, 255}, {16, 147, 161, 255}, {17, 148, 163, 255}, {16, 148, 163, 255}, {16, 150, 164, 255}, {15, 149, 164, 255}, {15, 150, 164, 255}, {16, 151, 166, 255}, {15, 151, 167, 255}, {14, 152, 166, 255}, {15, 152, 168, 255}, {14, 153, 167, 255}, {13, 154, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {13, 157, 171, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {29, 162, 175, 255}, {70, 93, 100, 255}, {68, 86, 94, 255}, {69, 88, 96, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 89, 97, 255}, {69, 87, 97, 255}, {70, 89, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {68, 88, 96, 255}, {70, 88, 98, 255}, {70, 90, 99, 139}, {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, 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, 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}, {57, 85, 85, 9}, {69, 83, 91, 212}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {104, 160, 165, 255}, {142, 224, 236, 255}, {135, 224, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {95, 222, 233, 255}, {33, 197, 217, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {22, 194, 215, 255}, {48, 181, 195, 255}, {24, 133, 145, 255}, {22, 130, 143, 255}, {22, 133, 146, 255}, {20, 135, 148, 255}, {20, 137, 151, 255}, {19, 137, 152, 255}, {19, 140, 153, 255}, {18, 141, 155, 255}, {18, 143, 156, 255}, {18, 145, 159, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {16, 148, 162, 255}, {16, 147, 162, 255}, {16, 150, 164, 255}, {15, 149, 163, 255}, {15, 150, 165, 255}, {14, 150, 165, 255}, {15, 151, 167, 255}, {13, 152, 166, 255}, {13, 151, 167, 255}, {15, 153, 168, 255}, {14, 153, 168, 255}, {13, 153, 168, 255}, {14, 153, 168, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 171, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 154, 170, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {84, 146, 152, 255}, {65, 84, 92, 255}, {69, 88, 96, 255}, {70, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {70, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {68, 88, 97, 255}, {69, 88, 98, 255}, {69, 90, 99, 199}, {128, 128, 128, 4}, {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, 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, 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}, {68, 81, 93, 41}, {69, 84, 91, 243}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {68, 86, 93, 255}, {140, 215, 221, 255}, {135, 223, 235, 255}, {135, 224, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {130, 246, 250, 255}, {65, 204, 222, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 193, 215, 255}, {46, 189, 204, 255}, {32, 145, 155, 255}, {24, 130, 142, 255}, {23, 132, 144, 255}, {21, 134, 148, 255}, {21, 136, 149, 255}, {19, 138, 151, 255}, {19, 140, 153, 255}, {19, 142, 155, 255}, {18, 142, 156, 255}, {18, 145, 158, 255}, {18, 146, 159, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {16, 149, 163, 255}, {16, 150, 164, 255}, {15, 149, 164, 255}, {16, 151, 166, 255}, {15, 151, 166, 255}, {14, 151, 166, 255}, {14, 152, 167, 255}, {15, 153, 168, 255}, {14, 152, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 155, 170, 255}, {13, 156, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {52, 168, 177, 255}, {65, 83, 91, 255}, {69, 87, 95, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {68, 88, 96, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 89, 99, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {70, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {69, 88, 98, 255}, {71, 89, 99, 237}, {70, 88, 97, 29}, {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, 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, 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, 0}, {0, 0, 0, 0}, {67, 83, 91, 95}, {67, 82, 90, 255}, {68, 83, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {89, 135, 140, 255}, {145, 225, 236, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {138, 255, 255, 255}, {87, 217, 229, 255}, {25, 194, 215, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {39, 193, 210, 255}, {38, 155, 169, 255}, {24, 129, 142, 255}, {23, 131, 143, 255}, {22, 134, 147, 255}, {20, 134, 149, 255}, {20, 138, 151, 255}, {20, 140, 153, 255}, {19, 141, 155, 255}, {18, 142, 156, 255}, {17, 143, 158, 255}, {18, 145, 159, 255}, {18, 146, 161, 255}, {16, 146, 161, 255}, {17, 147, 162, 255}, {15, 148, 162, 255}, {16, 150, 164, 255}, {15, 149, 164, 255}, {16, 151, 165, 255}, {15, 151, 166, 255}, {16, 152, 167, 255}, {13, 152, 166, 255}, {14, 152, 167, 255}, {14, 152, 168, 255}, {14, 153, 169, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 154, 169, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {13, 155, 171, 255}, {13, 156, 170, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {80, 122, 129, 255}, {67, 84, 93, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {68, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 89, 98, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {68, 88, 97, 255}, {69, 88, 97, 254}, {70, 89, 96, 77}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {67, 83, 91, 157}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {127, 197, 205, 255}, {137, 223, 235, 255}, {135, 223, 235, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {138, 255, 255, 255}, {139, 255, 255, 255}, {138, 255, 255, 255}, {118, 239, 244, 255}, {54, 201, 220, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {29, 196, 215, 255}, {46, 170, 185, 255}, {24, 129, 141, 255}, {24, 131, 144, 255}, {23, 133, 146, 255}, {21, 134, 148, 255}, {21, 137, 151, 255}, {19, 138, 151, 255}, {19, 139, 154, 255}, {19, 142, 155, 255}, {17, 143, 157, 255}, {17, 145, 158, 255}, {18, 146, 160, 255}, {17, 147, 160, 255}, {17, 147, 162, 255}, {15, 147, 161, 255}, {16, 149, 163, 255}, {16, 150, 164, 255}, {15, 150, 164, 255}, {15, 151, 166, 255}, {15, 151, 165, 255}, {14, 152, 166, 255}, {14, 152, 167, 255}, {13, 152, 167, 255}, {14, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 153, 168, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 156, 170, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {13, 155, 171, 255}, {12, 155, 171, 255}, {12, 154, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {72, 167, 175, 255}, {66, 83, 90, 255}, {69, 87, 95, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 87, 96, 255}, {70, 89, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 89, 98, 255}, {69, 89, 98, 255}, {68, 87, 97, 255}, {69, 89, 99, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {68, 88, 96, 255}, {69, 88, 97, 255}, {71, 89, 101, 137}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 128, 128, 4}, {69, 83, 91, 182}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {78, 110, 115, 255}, {146, 226, 236, 255}, {135, 223, 235, 255}, {134, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {136, 254, 254, 255}, {79, 211, 227, 255}, {17, 192, 215, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {20, 194, 216, 255}, {48, 182, 197, 255}, {25, 133, 147, 255}, {22, 130, 143, 255}, {24, 131, 145, 255}, {21, 134, 147, 255}, {21, 136, 150, 255}, {19, 137, 152, 255}, {19, 140, 153, 255}, {19, 141, 155, 255}, {19, 143, 157, 255}, {17, 144, 158, 255}, {18, 145, 160, 255}, {17, 146, 161, 255}, {17, 147, 162, 255}, {16, 148, 162, 255}, {15, 148, 162, 255}, {16, 150, 165, 255}, {16, 150, 165, 255}, {14, 149, 165, 255}, {16, 151, 166, 255}, {14, 151, 165, 255}, {14, 152, 166, 255}, {14, 153, 167, 255}, {14, 153, 168, 255}, {14, 153, 168, 255}, {13, 154, 169, 255}, {13, 153, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {16, 159, 172, 255}, {73, 103, 109, 255}, {67, 85, 93, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {68, 89, 97, 255}, {69, 89, 97, 255}, {70, 89, 97, 255}, {69, 87, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {70, 90, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 88, 98, 255}, {69, 89, 98, 255}, {69, 87, 97, 255}, {69, 89, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {70, 89, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {71, 89, 98, 166}, {255, 255, 255, 1}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {57, 85, 85, 9}, {68, 83, 91, 199}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {111, 175, 180, 255}, {139, 224, 235, 255}, {135, 223, 235, 255}, {134, 224, 236, 255}, {161, 255, 255, 255}, {139, 255, 255, 255}, {139, 255, 255, 255}, {102, 229, 238, 255}, {42, 198, 219, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {16, 193, 215, 255}, {45, 191, 205, 255}, {32, 146, 158, 255}, {22, 130, 143, 255}, {24, 132, 144, 255}, {22, 134, 148, 255}, {20, 135, 149, 255}, {20, 138, 152, 255}, {20, 139, 152, 255}, {18, 140, 155, 255}, {18, 142, 155, 255}, {18, 144, 158, 255}, {18, 145, 158, 255}, {16, 145, 160, 255}, {17, 147, 161, 255}, {15, 147, 161, 255}, {16, 148, 162, 255}, {15, 148, 163, 255}, {16, 150, 165, 255}, {14, 149, 165, 255}, {15, 151, 166, 255}, {14, 152, 166, 255}, {13, 152, 166, 255}, {15, 152, 168, 255}, {14, 153, 167, 255}, {14, 153, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 154, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {84, 157, 163, 255}, {65, 83, 91, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {68, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 96, 255}, {69, 89, 98, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 89, 99, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 88, 97, 255}, {70, 88, 98, 185}, {102, 102, 102, 5}, {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, 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, 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, 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}, {71, 85, 99, 18}, {68, 83, 91, 214}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {70, 92, 99, 255}, {145, 221, 229, 255}, {135, 223, 235, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {138, 255, 255, 255}, {134, 252, 253, 255}, {72, 207, 224, 255}, {15, 191, 214, 255}, {14, 191, 214, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {39, 196, 214, 255}, {39, 161, 175, 255}, {23, 131, 143, 255}, {23, 131, 144, 255}, {22, 134, 146, 255}, {21, 134, 148, 255}, {19, 138, 151, 255}, {19, 138, 152, 255}, {19, 140, 155, 255}, {18, 142, 155, 255}, {18, 143, 156, 255}, {16, 144, 158, 255}, {18, 145, 160, 255}, {16, 146, 161, 255}, {17, 148, 162, 255}, {16, 148, 162, 255}, {15, 148, 162, 255}, {15, 149, 164, 255}, {15, 150, 164, 255}, {15, 151, 166, 255}, {15, 151, 165, 255}, {14, 151, 166, 255}, {15, 152, 168, 255}, {14, 153, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 153, 169, 255}, {13, 153, 168, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 156, 170, 255}, {13, 155, 170, 255}, {13, 156, 170, 255}, {12, 154, 171, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 170, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {37, 166, 176, 255}, {67, 88, 94, 255}, {68, 86, 94, 255}, {69, 88, 97, 255}, {68, 88, 96, 255}, {69, 88, 96, 255}, {68, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 89, 97, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {70, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {68, 87, 97, 255}, {69, 89, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 89, 99, 203}, {70, 93, 116, 11}, {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, 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, 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, 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}, {64, 82, 91, 28}, {69, 83, 90, 226}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {97, 150, 155, 255}, {142, 225, 236, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {138, 255, 255, 255}, {91, 220, 234, 255}, {31, 196, 217, 255}, {14, 191, 214, 255}, {15, 191, 214, 255}, {31, 197, 218, 255}, {45, 177, 191, 255}, {22, 133, 145, 255}, {22, 133, 145, 255}, {22, 134, 146, 255}, {22, 135, 148, 255}, {20, 137, 150, 255}, {19, 138, 152, 255}, {18, 139, 152, 255}, {19, 141, 155, 255}, {18, 143, 156, 255}, {17, 145, 158, 255}, {18, 145, 159, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {16, 148, 162, 255}, {16, 149, 164, 255}, {15, 149, 164, 255}, {16, 150, 165, 255}, {15, 150, 166, 255}, {14, 151, 165, 255}, {16, 152, 167, 255}, {14, 152, 166, 255}, {14, 153, 167, 255}, {13, 152, 167, 255}, {15, 153, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 169, 255}, {13, 154, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 170, 255}, {13, 155, 171, 255}, {13, 156, 170, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {84, 138, 144, 255}, {66, 83, 91, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {68, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 89, 99, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 90, 99, 216}, {77, 89, 102, 20}, {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, 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, 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, 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}, {67, 85, 91, 42}, {68, 83, 90, 237}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 82, 90, 255}, {134, 209, 216, 255}, {135, 224, 236, 255}, {161, 255, 255, 255}, {126, 245, 249, 255}, {60, 203, 221, 255}, {15, 191, 214, 255}, {20, 195, 216, 255}, {47, 189, 203, 255}, {23, 140, 152, 255}, {21, 134, 147, 255}, {21, 134, 147, 255}, {21, 134, 148, 255}, {20, 136, 150, 255}, {20, 138, 151, 255}, {19, 139, 152, 255}, {18, 140, 155, 255}, {18, 142, 155, 255}, {17, 143, 158, 255}, {18, 145, 159, 255}, {17, 146, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {16, 148, 162, 255}, {15, 148, 163, 255}, {14, 148, 163, 255}, {14, 150, 164, 255}, {14, 150, 165, 255}, {14, 151, 166, 255}, {15, 151, 167, 255}, {14, 152, 167, 255}, {13, 152, 167, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 153, 169, 255}, {13, 155, 171, 255}, {13, 155, 170, 255}, {12, 155, 171, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 156, 170, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {62, 169, 177, 255}, {64, 82, 90, 255}, {70, 87, 96, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 87, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 89, 98, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {68, 87, 97, 255}, {68, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 98, 229}, {66, 90, 99, 31}, {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, 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, 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, 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}, {66, 84, 92, 58}, {67, 83, 90, 244}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {84, 124, 129, 255}, {147, 227, 238, 255}, {161, 255, 255, 255}, {82, 214, 228, 255}, {21, 193, 216, 255}, {46, 198, 213, 255}, {31, 153, 167, 255}, {21, 134, 148, 255}, {20, 134, 148, 255}, {21, 135, 150, 255}, {20, 136, 150, 255}, {20, 137, 151, 255}, {19, 139, 152, 255}, {18, 140, 155, 255}, {19, 142, 155, 255}, {17, 143, 158, 255}, {18, 145, 158, 255}, {18, 145, 160, 255}, {17, 147, 160, 255}, {16, 146, 161, 255}, {17, 148, 163, 255}, {15, 148, 162, 255}, {16, 150, 165, 255}, {15, 150, 164, 255}, {15, 151, 166, 255}, {14, 152, 166, 255}, {15, 151, 167, 255}, {14, 152, 167, 255}, {13, 152, 166, 255}, {13, 153, 168, 255}, {13, 154, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 156, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 154, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {77, 115, 120, 255}, {67, 85, 92, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {68, 88, 96, 255}, {69, 88, 96, 255}, {68, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {68, 87, 96, 255}, {69, 89, 98, 239}, {74, 91, 102, 45}, {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, 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, 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, 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}, {68, 85, 92, 75}, {67, 83, 91, 250}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {67, 82, 90, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {111, 172, 177, 255}, {118, 237, 244, 255}, {52, 202, 220, 255}, {40, 169, 182, 255}, {20, 135, 149, 255}, {20, 135, 149, 255}, {21, 135, 150, 255}, {20, 136, 151, 255}, {19, 138, 152, 255}, {19, 139, 152, 255}, {18, 140, 154, 255}, {19, 141, 155, 255}, {18, 144, 157, 255}, {18, 144, 158, 255}, {17, 145, 159, 255}, {17, 146, 161, 255}, {15, 146, 161, 255}, {17, 148, 163, 255}, {16, 149, 163, 255}, {16, 150, 165, 255}, {16, 151, 165, 255}, {14, 149, 165, 255}, {15, 151, 165, 255}, {14, 151, 166, 255}, {14, 152, 167, 255}, {14, 152, 168, 255}, {13, 152, 168, 255}, {15, 153, 168, 255}, {13, 153, 168, 255}, {13, 154, 169, 255}, {13, 154, 169, 255}, {13, 155, 170, 255}, {12, 154, 170, 255}, {13, 155, 171, 255}, {13, 156, 171, 255}, {13, 156, 171, 255}, {13, 155, 171, 255}, {12, 154, 171, 255}, {13, 156, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {13, 156, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {12, 155, 171, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {11, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {10, 155, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {9, 154, 170, 255}, {76, 148, 156, 255}, {65, 82, 91, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 89, 97, 246}, {71, 88, 96, 61}, {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, 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, 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, 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}, {67, 83, 91, 95}, {66, 81, 89, 254}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {75, 127, 134, 255}, {74, 150, 156, 255}, {75, 153, 161, 255}, {75, 153, 161, 255}, {75, 153, 162, 255}, {75, 153, 162, 255}, {74, 154, 162, 255}, {75, 155, 163, 255}, {75, 155, 163, 255}, {74, 155, 163, 255}, {74, 155, 164, 255}, {74, 155, 163, 255}, {75, 155, 164, 255}, {73, 155, 163, 255}, {74, 156, 164, 255}, {75, 156, 165, 255}, {74, 156, 164, 255}, {74, 156, 164, 255}, {74, 156, 164, 255}, {74, 157, 165, 255}, {75, 156, 166, 255}, {75, 158, 166, 255}, {73, 158, 165, 255}, {74, 158, 165, 255}, {74, 158, 166, 255}, {74, 158, 166, 255}, {74, 158, 166, 255}, {73, 157, 166, 255}, {74, 158, 166, 255}, {74, 158, 166, 255}, {74, 158, 166, 255}, {74, 158, 166, 255}, {73, 157, 166, 255}, {73, 158, 167, 255}, {73, 158, 167, 255}, {73, 158, 167, 255}, {74, 160, 167, 255}, {74, 160, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {73, 159, 167, 255}, {77, 165, 173, 255}, {77, 165, 174, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 174, 255}, {77, 165, 174, 255}, {77, 165, 173, 255}, {77, 165, 174, 255}, {77, 165, 174, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 174, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {76, 164, 173, 255}, {77, 165, 173, 255}, {77, 165, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {77, 165, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {75, 164, 173, 255}, {75, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {75, 164, 173, 255}, {76, 164, 173, 255}, {76, 164, 173, 255}, {75, 164, 173, 255}, {75, 164, 173, 255}, {75, 164, 173, 255}, {76, 164, 173, 255}, {75, 164, 173, 255}, {76, 158, 167, 255}, {73, 126, 134, 255}, {67, 85, 93, 255}, {69, 89, 96, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {68, 89, 97, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 86, 96, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {67, 87, 96, 255}, {68, 87, 96, 255}, {69, 89, 96, 252}, {68, 87, 97, 79}, {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, 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, 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, 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}, {69, 85, 90, 93}, {66, 82, 90, 250}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {71, 89, 97, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {72, 91, 101, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 89, 97, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {68, 88, 97, 255}, {69, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 88, 98, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {69, 87, 97, 255}, {68, 87, 97, 255}, {68, 88, 97, 246}, {70, 89, 99, 80}, {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, 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, 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, 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}, {69, 83, 90, 74}, {67, 82, 89, 244}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 88, 255}, {75, 95, 104, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 94, 104, 255}, {70, 90, 97, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {70, 89, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {68, 88, 97, 255}, {69, 87, 98, 239}, {71, 88, 96, 61}, {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, 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, 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, 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}, {64, 82, 87, 56}, {67, 82, 89, 236}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {69, 85, 94, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {73, 92, 102, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {68, 88, 97, 255}, {69, 89, 97, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {69, 88, 97, 255}, {68, 88, 96, 255}, {68, 87, 97, 255}, {68, 88, 98, 229}, {74, 91, 102, 45}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {68, 81, 93, 41}, {67, 82, 90, 225}, {66, 81, 89, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {74, 93, 102, 255}, {77, 97, 107, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {70, 90, 98, 255}, {69, 88, 96, 255}, {69, 88, 96, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {69, 89, 98, 255}, {69, 88, 97, 255}, {68, 87, 97, 255}, {68, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 97, 255}, {70, 90, 98, 216}, {66, 90, 99, 31}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 82, 91, 28}, {67, 81, 90, 213}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {67, 82, 91, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 93, 104, 255}, {69, 88, 97, 255}, {68, 88, 97, 255}, {69, 87, 96, 255}, {68, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 86, 96, 255}, {69, 87, 97, 255}, {69, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {68, 88, 96, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 88, 97, 203}, {64, 89, 102, 20}, {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, 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, 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, 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}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {60, 75, 90, 17}, {67, 81, 89, 198}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {72, 90, 99, 255}, {77, 97, 107, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {71, 90, 100, 255}, {69, 89, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {69, 88, 99, 185}, {70, 93, 116, 11}, {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, 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, 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, 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}, {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}, {57, 85, 85, 9}, {66, 82, 89, 181}, {65, 81, 88, 255}, {66, 81, 89, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {65, 80, 88, 255}, {77, 96, 105, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {73, 94, 103, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {69, 89, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 88, 96, 255}, {68, 87, 97, 255}, {68, 88, 98, 166}, {102, 102, 102, 5}, {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, 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, 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, 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}, {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}, {85, 85, 85, 3}, {67, 82, 90, 153}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {70, 86, 96, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {71, 92, 100, 255}, {69, 88, 97, 255}, {68, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 86, 96, 255}, {69, 87, 97, 255}, {69, 88, 96, 255}, {68, 88, 96, 255}, {67, 87, 96, 255}, {68, 87, 97, 254}, {71, 89, 99, 137}, {255, 255, 255, 1}, {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, 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, 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, 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}, {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}, {64, 81, 90, 91}, {67, 82, 89, 242}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {75, 94, 103, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {70, 89, 98, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {68, 86, 96, 255}, {69, 88, 98, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 86, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 87, 96, 255}, {70, 89, 97, 237}, {70, 89, 96, 77}, {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, 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, 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, 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}, {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}, {65, 85, 92, 39}, {66, 81, 89, 209}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {68, 84, 93, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {72, 93, 102, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 87, 96, 255}, {68, 88, 96, 255}, {70, 89, 98, 198}, {70, 88, 97, 29}, {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, 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, 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, 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}, {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}, {73, 73, 109, 7}, {65, 80, 88, 153}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {72, 91, 99, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {70, 89, 99, 255}, {69, 88, 97, 255}, {68, 86, 96, 255}, {68, 86, 96, 255}, {69, 88, 98, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {69, 87, 97, 255}, {69, 88, 96, 255}, {68, 87, 96, 254}, {68, 89, 98, 138}, {128, 128, 128, 4}, {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, 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, 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, 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}, {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}, {66, 80, 89, 89}, {67, 83, 89, 241}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {65, 81, 89, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {72, 94, 102, 255}, {69, 87, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 86, 96, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {70, 88, 98, 236}, {70, 91, 97, 76}, {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, 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, 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, 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}, {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, 0, 0, 0}, {64, 78, 85, 36}, {67, 83, 89, 207}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {69, 88, 96, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {77, 97, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {71, 91, 100, 255}, {68, 86, 96, 255}, {68, 86, 96, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {70, 88, 98, 197}, {73, 91, 100, 28}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {73, 73, 109, 7}, {64, 81, 88, 151}, {65, 81, 88, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 79, 86, 255}, {75, 95, 104, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 93, 103, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {69, 87, 97, 254}, {69, 88, 99, 136}, {128, 128, 128, 4}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {65, 81, 87, 79}, {66, 82, 88, 225}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 81, 88, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {68, 85, 94, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {72, 92, 100, 255}, {68, 86, 96, 255}, {69, 88, 98, 255}, {69, 87, 97, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {69, 87, 96, 255}, {67, 87, 95, 255}, {68, 88, 98, 217}, {68, 86, 98, 68}, {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, 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, 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, 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}, {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, 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}, {77, 77, 102, 10}, {65, 80, 87, 137}, {66, 81, 89, 249}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {74, 92, 101, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {69, 88, 98, 255}, {68, 87, 96, 255}, {67, 87, 95, 255}, {68, 87, 96, 255}, {68, 87, 96, 255}, {68, 88, 96, 246}, {69, 89, 97, 126}, {85, 85, 128, 6}, {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, 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, 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, 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}, {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, 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}, {67, 85, 91, 42}, {65, 80, 88, 191}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {65, 82, 90, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {73, 93, 102, 255}, {68, 87, 96, 255}, {69, 88, 97, 255}, {68, 87, 96, 255}, {69, 88, 96, 180}, {70, 85, 93, 33}, {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, 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, 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, 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}, {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, 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}, {67, 80, 89, 92}, {65, 81, 88, 231}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {70, 90, 97, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {70, 90, 99, 255}, {69, 88, 97, 224}, {70, 89, 99, 80}, {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, 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, 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, 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}, {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, 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}, {73, 73, 91, 14}, {66, 80, 87, 147}, {66, 81, 88, 252}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {64, 80, 87, 255}, {76, 96, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {75, 94, 104, 249}, {74, 95, 107, 134}, {77, 102, 102, 10}, {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, 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, 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, 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}, {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, 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}, {68, 83, 88, 49}, {67, 81, 90, 199}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {68, 86, 94, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 96, 105, 189}, {77, 96, 108, 40}, {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, 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, 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, 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}, {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, 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, 0, 0}, {0, 0, 0, 0}, {255, 255, 255, 1}, {65, 82, 88, 90}, {65, 80, 89, 216}, {64, 79, 87, 255}, {64, 79, 87, 255}, {65, 80, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {63, 78, 86, 255}, {74, 93, 103, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 105, 209}, {76, 94, 104, 81}, {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, 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, 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, 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}, {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, 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, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {85, 85, 85, 3}, {66, 81, 89, 97}, {65, 81, 89, 221}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {67, 83, 92, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {76, 96, 106, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 96, 105, 213}, {73, 94, 106, 87}, {255, 255, 255, 1}, {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, 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, 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, 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}, {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, 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, 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}, {64, 128, 128, 4}, {64, 79, 87, 103}, {64, 80, 88, 223}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {73, 91, 101, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {75, 95, 106, 215}, {75, 97, 105, 92}, {128, 128, 128, 2}, {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, 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, 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, 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}, {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, 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, 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}, {85, 85, 85, 3}, {64, 79, 88, 87}, {66, 80, 87, 202}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {64, 80, 89, 255}, {75, 94, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {75, 96, 105, 194}, {74, 97, 107, 79}, {255, 255, 255, 1}, {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, 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, 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, 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}, {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, 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, 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}, {62, 78, 86, 62}, {63, 80, 87, 178}, {65, 80, 88, 253}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {69, 87, 97, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {75, 94, 104, 252}, {75, 95, 104, 169}, {76, 94, 104, 54}, {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, 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, 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, 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}, {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, 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, 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}, {66, 80, 87, 35}, {64, 81, 88, 136}, {64, 80, 88, 230}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {63, 78, 87, 255}, {73, 94, 102, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {75, 95, 105, 225}, {75, 95, 105, 129}, {70, 97, 106, 29}, {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, 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, 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, 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}, {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, 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, 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, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 128, 128, 4}, {65, 81, 87, 82}, {63, 80, 87, 182}, {65, 80, 88, 252}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {64, 79, 87, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {66, 85, 92, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 105, 251}, {76, 95, 105, 175}, {75, 95, 105, 75}, {128, 128, 128, 2}, {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, 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, 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, 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}, {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, 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, 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, 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}, {64, 82, 91, 28}, {64, 79, 88, 116}, {64, 80, 87, 202}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 78, 86, 255}, {72, 92, 100, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 254}, {75, 96, 105, 196}, {75, 96, 105, 109}, {78, 100, 111, 23}, {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, 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, 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, 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}, {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, 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, 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, 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}, {62, 77, 85, 33}, {65, 80, 89, 121}, {63, 78, 87, 205}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {64, 82, 90, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 254}, {76, 96, 105, 199}, {76, 96, 105, 114}, {76, 94, 104, 27}, {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, 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, 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, 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}, {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, 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, 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, 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}, {68, 85, 85, 30}, {63, 80, 87, 105}, {63, 79, 88, 177}, {63, 79, 86, 242}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {69, 89, 98, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {75, 95, 105, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {75, 96, 106, 239}, {75, 94, 104, 171}, {75, 96, 107, 98}, {71, 92, 102, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {102, 102, 102, 5}, {62, 77, 85, 66}, {65, 79, 87, 138}, {63, 79, 87, 199}, {62, 79, 86, 249}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {63, 78, 86, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 78, 86, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 94, 104, 255}, {74, 95, 104, 255}, {74, 96, 104, 247}, {76, 97, 106, 195}, {77, 98, 105, 133}, {72, 94, 106, 60}, {85, 170, 170, 3}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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}, {64, 96, 96, 8}, {62, 78, 86, 62}, {63, 80, 86, 121}, {62, 78, 86, 180}, {64, 80, 87, 234}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {68, 86, 95, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {74, 95, 104, 255}, {76, 96, 106, 231}, {76, 96, 106, 175}, {76, 96, 107, 117}, {76, 94, 103, 57}, {85, 128, 128, 6}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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}, {61, 71, 82, 25}, {64, 78, 85, 72}, {65, 80, 86, 118}, {64, 79, 87, 164}, {63, 78, 87, 209}, {63, 78, 86, 247}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {61, 77, 84, 245}, {61, 77, 86, 205}, {73, 92, 104, 160}, {75, 95, 106, 115}, {75, 94, 105, 68}, {70, 93, 104, 22}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {255, 255, 255, 1}, {61, 71, 82, 25}, {65, 78, 86, 59}, {64, 80, 86, 92}, {64, 78, 86, 124}, {63, 78, 86, 157}, {62, 78, 85, 182}, {63, 79, 86, 201}, {64, 78, 86, 220}, {63, 78, 86, 239}, {62, 77, 85, 254}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 78, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 255}, {61, 76, 84, 255}, {62, 77, 85, 255}, {62, 77, 85, 255}, {61, 76, 84, 254}, {63, 77, 86, 237}, {62, 77, 85, 219}, {62, 78, 86, 199}, {62, 77, 86, 181}, {61, 78, 86, 154}, {61, 77, 86, 122}, {63, 80, 86, 89}, {59, 77, 87, 56}, {58, 81, 81, 22}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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}, {255, 255, 255, 1}, {85, 85, 85, 6}, {51, 77, 77, 10}, {70, 93, 93, 11}, {59, 78, 98, 13}, {68, 85, 85, 15}, {60, 75, 90, 17}, {57, 85, 85, 18}, {57, 85, 85, 18}, {64, 80, 96, 16}, {68, 85, 85, 15}, {59, 78, 78, 13}, {70, 93, 93, 11}, {57, 85, 85, 9}, {85, 85, 85, 6}, {255, 255, 255, 1}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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}, {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, 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, 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, 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} - } -}; diff --git a/cmd/vulkan_sample/main.cpp b/cmd/vulkan_sample/main.cpp index 0c412fdef0..cfc48d8e26 100644 --- a/cmd/vulkan_sample/main.cpp +++ b/cmd/vulkan_sample/main.cpp @@ -48,7 +48,7 @@ namespace cube { } namespace icon { -#include "icon.h" +#include "tools/logo/logo_256.h" } const uint32_t vertex_shader[] = #include "vert.h" diff --git a/tools/logo/BUILD.bazel b/tools/logo/BUILD.bazel index b6ae81d5ac..4a6266c0af 100644 --- a/tools/logo/BUILD.bazel +++ b/tools/logo/BUILD.bazel @@ -12,4 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +load("//tools/build:rules.bzl", "img2h") + exports_files(glob(["*.png"])) + +img2h( + name = "logo_256_h", + srcs = ["logo_256.png"], + visibility = ["//visibility:public"], +) From dd6c703aef8e66611dd43dc431a001c92bc58252 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 4 Mar 2020 11:08:17 -0800 Subject: [PATCH 0143/1218] Adds a img2ico rule to turn images into .ico files. --- cmd/img2ico/BUILD.bazel | 18 ++++ cmd/img2ico/main.go | 204 +++++++++++++++++++++++++++++++++++ tools/build/rules.bzl | 2 + tools/build/rules/images.bzl | 30 ++++++ 4 files changed, 254 insertions(+) create mode 100644 cmd/img2ico/BUILD.bazel create mode 100644 cmd/img2ico/main.go diff --git a/cmd/img2ico/BUILD.bazel b/cmd/img2ico/BUILD.bazel new file mode 100644 index 0000000000..16c9aa49c6 --- /dev/null +++ b/cmd/img2ico/BUILD.bazel @@ -0,0 +1,18 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = ["main.go"], + importpath = "github.com/google/gapid/cmd/img2ico", + visibility = ["//visibility:private"], + deps = [ + "//core/app:go_default_library", + "//core/log:go_default_library", + ], +) + +go_binary( + name = "img2ico", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) diff --git a/cmd/img2ico/main.go b/cmd/img2ico/main.go new file mode 100644 index 0000000000..075b2e3c25 --- /dev/null +++ b/cmd/img2ico/main.go @@ -0,0 +1,204 @@ +// Copyright (C) 2020 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// img2ico is a utility program that converts images to Windows ICO icons. + +package main + +import ( + "bytes" + "context" + "encoding/binary" + "flag" + "image" + "image/color" + "os" + + "github.com/google/gapid/core/app" + "github.com/google/gapid/core/log" + + // Import to register image formats. + _ "image/gif" + _ "image/jpeg" + "image/png" +) + +var ( + out = flag.String("out", "-", "Output file, '-' for stdout") +) + +func main() { + app.ShortHelp = "img2ico creates Windows ICO files" + app.Name = "img2ico" + app.Run(run) +} + +type header struct { + reserved uint16 + imgType uint16 + imgCount uint16 +} + +type entry struct { + width uint8 + height uint8 + paletteSize uint8 + reserved uint8 + numPlanes uint16 + bpp uint16 + imgSize uint32 + offset uint32 +} + +type bmp struct { + headerSize uint32 + width uint32 + height uint32 + planes uint16 + bpp uint16 + compression uint32 + imageSize uint32 + wResolution uint32 + hResolution uint32 + paletteSize uint32 + important uint32 +} + +type pixel struct { + b, g, r, a uint8 +} + +func run(ctx context.Context) (err error) { + if flag.NArg() < 1 { + app.Usage(ctx, "At least one input image is required") + return nil + } + + images := make([]image.Image, 0, flag.NArg()) + pngs := [][]byte{} + for _, file := range flag.Args() { + in, err := os.Open(file) + if err != nil { + return log.Errf(ctx, err, "Failed to open %s", file) + } + + img, _, err := image.Decode(in) + in.Close() + if err != nil { + return log.Errf(ctx, err, "Failed to decode image %s", file) + } + + size := img.Bounds().Size() + if size.X > 256 || size.Y > 256 { + return log.Errf(ctx, nil, "Image %s too big. Cannot be larger than 256x256", file) + } + + images = append(images, img) + + // Use PNG format for large icons. + if size.X == 256 || size.Y == 256 { + var pngOut bytes.Buffer + png.Encode(&pngOut, img) + pngs = append(pngs, pngOut.Bytes()) + } + } + + o := os.Stdout + if *out != "-" { + o, err = os.Create(*out) + if err != nil { + return log.Errf(ctx, err, "Failed to create %s", *out) + } + defer o.Close() + } + + binary.Write(o, binary.LittleEndian, &header{ + imgType: 1, // ICO + imgCount: uint16(len(images)), + }) + + offset := uint32(6 + 16*len(images)) + pngIdx := 0 + for _, img := range images { + w, h := img.Bounds().Dx(), img.Bounds().Dy() + size := uint32(40 + w*h*4 + h*((w+31) & ^31)/8) + + if w == 256 { + w = 0 + } + if h == 256 { + h = 0 + } + + if w == 0 || h == 0 { + size = uint32(len(pngs[pngIdx])) + pngIdx++ + } + + binary.Write(o, binary.LittleEndian, &entry{ + width: uint8(w), + height: uint8(h), + numPlanes: 1, + bpp: 32, + imgSize: size, + offset: offset, + }) + offset += size + } + + model := color.NRGBAModel + pngIdx = 0 + for _, img := range images { + w, h := img.Bounds().Dx(), img.Bounds().Dy() + + if w == 256 || h == 256 { + o.Write(pngs[pngIdx]) + pngIdx++ + continue + } + + binary.Write(o, binary.LittleEndian, &bmp{ + headerSize: 40, + width: uint32(w), + height: uint32(2 * h), + planes: 1, + bpp: 32, + imageSize: uint32(w * h * 4), + }) + + matte := make([]byte, h*((w+31) & ^31)/8) + mattePos := uint(0) + for y := h - 1; y >= 0; y-- { + for x := 0; x < w; x++ { + p := model.Convert(img.At(x, y)).(color.NRGBA) + binary.Write(o, binary.LittleEndian, &pixel{ + r: p.R, + g: p.G, + b: p.B, + a: p.A, + }) + if p.A == 0 { + matte[mattePos/8] |= byte(0x80 >> (mattePos % 8)) + } + mattePos++ + } + // Align to 4 bytes. + mattePos = (mattePos + 31) & ^uint(31) + } + + o.Write(matte) + } + + return nil +} diff --git a/tools/build/rules.bzl b/tools/build/rules.bzl index f7f90d4b7e..ec1f7440b9 100644 --- a/tools/build/rules.bzl +++ b/tools/build/rules.bzl @@ -44,6 +44,7 @@ load("//tools/build/rules:filehash.bzl", ) load("//tools/build/rules:images.bzl", _img2h = "img2h", + _img2ico = "img2ico", ) load("//tools/build/rules:jni.bzl", _jni_library = "jni_library", @@ -93,6 +94,7 @@ cc_dynamic_library = _cc_dynamic_library embed = _embed filehash = _filehash img2h = _img2h +img2ico = _img2ico jni_library = _jni_library api_library = _api_library api_template = _api_template diff --git a/tools/build/rules/images.bzl b/tools/build/rules/images.bzl index 9d9ac63da8..d94109236c 100644 --- a/tools/build/rules/images.bzl +++ b/tools/build/rules/images.bzl @@ -45,3 +45,33 @@ img2h = rule( }, output_to_genfiles = True, ) + +def _img2ico_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name + ".ico") + ctx.actions.run( + inputs = ctx.files.srcs, + outputs = [out], + arguments = ["-out", out.path] + [img.path for img in ctx.files.srcs], + executable = ctx.executable._img2ico, + use_default_shell_env = True, + ) + return [ + DefaultInfo(files = depset([out])), + ] + +img2ico = rule( + _img2ico_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + ), + "_img2ico": attr.label( + cfg = "host", + executable = True, + allow_files = True, + default = Label("//cmd/img2ico"), + ), + }, + output_to_genfiles = True, +) From 1421b27f2e265fbb1b4e196ef0b1eeefa8966005 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 9 Mar 2020 20:21:29 -0700 Subject: [PATCH 0144/1218] Update the AGI logo to the new version. --- tools/logo/BUILD.bazel | 5 ++++- tools/logo/logo.svg | 10 ++++++++++ tools/logo/logo_1024.png | Bin 260124 -> 58873 bytes tools/logo/logo_128.png | Bin 10323 -> 6202 bytes tools/logo/logo_16.png | Bin 752 -> 671 bytes tools/logo/logo_24.png | Bin 0 -> 1053 bytes tools/logo/logo_256.png | Bin 27405 -> 12702 bytes tools/logo/logo_32.png | Bin 1723 -> 1421 bytes tools/logo/logo_40.png | Bin 0 -> 1831 bytes tools/logo/logo_48.png | Bin 2644 -> 2194 bytes tools/logo/logo_512.png | Bin 81547 -> 26566 bytes tools/logo/logo_64.png | Bin 4033 -> 2931 bytes 12 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tools/logo/logo.svg create mode 100644 tools/logo/logo_24.png create mode 100644 tools/logo/logo_40.png diff --git a/tools/logo/BUILD.bazel b/tools/logo/BUILD.bazel index 4a6266c0af..ff63e6af73 100644 --- a/tools/logo/BUILD.bazel +++ b/tools/logo/BUILD.bazel @@ -14,7 +14,10 @@ load("//tools/build:rules.bzl", "img2h") -exports_files(glob(["*.png"])) +exports_files(glob([ + "*.png", + "*.svg", +])) img2h( name = "logo_256_h", diff --git a/tools/logo/logo.svg b/tools/logo/logo.svg new file mode 100644 index 0000000000..2a42d04c42 --- /dev/null +++ b/tools/logo/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tools/logo/logo_1024.png b/tools/logo/logo_1024.png index 8681ea3eb36a25f8721c972fc41b9ee5e0af5f1c..d39a7b1eb37280e1bcf3332900740057327c62d2 100644 GIT binary patch literal 58873 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 AhyVZp diff --git a/tools/logo/logo_128.png b/tools/logo/logo_128.png index e3f16092141e181f67a91250df9e4e4949fdd88a..7a3b0218cefd509f706a3940045fd5d2ce2cd93b 100644 GIT binary patch literal 6202 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 delta 729 zcmV;~0w(>R1@HxsBYyw^b5ch_0Itp)=>Px%s!2paR5%d@!QX3@bsPZT=lh;>+|GWS z*~pB+N*NS+5lB!NWIvEF=1thS5l3A~5M7l17wK(DKfK60-zc&>8EVvphIMC69L=e7 zPM5f|?Hte9dEZaZlK=n!W@b(dKd!gxu)WjhoIQJT6951b0Dm-_&B~L?$R|be8L=xO zh!8=rKyj)Oz0-M~7XS%h`pA)|!oW`=-b|=JyVIV-hi#Rmzw;lom+uoHGMDJRKbz-k zkf7OYR@$}EixK7iYQ1ji(6q_DuPU-6f+$OO{<>oR=kvBUJBW+pmHxYVo);CEdik|a zOY!mK{x|IX@P8wX$=xC)0!S%oOiY^Cw@(p0j~8z3-YC-j#kuR(s!(P=Pmv59J!){c zrk@fBKp-$sjO(XqF8?Mg%H#Mdo0&N=EaLf;k}E6gPOpa5&7K4Z6u7nY(3e+lx-s`J zD9dtcU$a@SKCZXwWh)SF-&^&}(5P?Lw|Sx6cW5kWwSU`wnOk!ENqDJNy1ugPl>jR3 z+F%v3O4Z=-s4_zF->UNI3IFt~mL9QoV@U{O)y&$`qR6U-8>2SY)+xwRzuz4iZICi0 z9z1H`_rCt-#hr=rh9kp8OaLI)tFzr?LejH#n}s5e_SKXjou%7Gsv z;+=>vxMN)T-XYzUhq5cb>nyJbNtT%{wyGb@=2Bm;K>~ng^IWAp^6Rl`mX4QYIR*WG zA&S0I%tyq@?fs2!^E@vA5&!_eTg~Rkw*KG{^r}zVm-BoB00906dLvovZa&Oj00000 LNkvXXu0mjfFGX$- diff --git a/tools/logo/logo_24.png b/tools/logo/logo_24.png new file mode 100644 index 0000000000000000000000000000000000000000..a607c7eed1fb9a865824694f30d1c9b0a2dd10fd GIT binary patch literal 1053 zcmV+&1mgRNP)XE zsYVlxF)0yUR09R8ZE9(>i)t-YB?PrVky4-x9cGxBH#6_u&jtU6VFv42e&^lu&Ue21 z?tO|C5UAN%VT@@2RgXv|P(DYEpwtjXI<#lECH^?^Pd*KmQ~2IT%ZyTQfIJ6StPG>z zD45rrp01()e1UJvjz)zX0Sftlh@#|~WcTUz%;FMv{w+K9E95i4pG%>nxP-!BA+cC2 z7wreN*DkFLdt*cAmUS@a{3xKaSKj3J^JMcA?A_grQku@=$N9Xag?K!XGcuGk&3B>z z0-GNxH(K{)$D)+tp$8w}`F;B+E-qf85}KOgNb8q;cj9}Dk!5jN%DOY&eR9+S(51H@ zQgDCf6L)Ob$m<6Vu)C>|U@*AMWqtYU=U6Cn;IS}6*x=HU8gS!b`#DIAS^ zy#LJ%S=lm`J z%5**^kv5D@FS@dQLYs8))lW8B`4;M-8HbeX<&!ZQ7|q8HUr&;9B_EAz43p7#{^<*& z8j*o~yk~^V*PXoUC#K_gCcgm`0~%B(D_|^|VkWsf0w?VfjytRfMTgd&-3BZu=+PL~ zg%Hde6Sy?#uvnPI)o=`1C<*CnXECwMOA^$cIcB*Nmm+paWd%yz2S8fTy+L~Jme256+({UsfCNa`ZYT^tTt;{20Y4Jh3?bH6RZ2#NuaPHm(;@mtqOK8=3? XVPdB$N5N*@00000NkvXXu0mjf)H?O^ literal 0 HcmV?d00001 diff --git a/tools/logo/logo_256.png b/tools/logo/logo_256.png index 81dbed512d289afb4114ba3a89e3eed21bc84e04..9de4f12915933c1046b17c9964162472e0ce4a96 100644 GIT binary patch literal 12702 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 diff --git a/tools/logo/logo_32.png b/tools/logo/logo_32.png index 1e4245c875f1fc4bbfc239a0bf770df4195dfa4f..c780fbab1631dfbd6dccc119cb255d62e7e94e32 100644 GIT binary patch delta 1403 zcmV->1%&#$4UG$sBYy={Nkl-Pk$8RRgBlZ!hD0B@ydd5lNc2Umnu?N$#8_YgVo?G@VFVOQsco4_+Uc}2 zXJ*cI`_Km4&Y8{$>+!7r{Oez9uf6sX__e0>v7l+R3dw2#4Sy1D1!hlpGXi=goRUHu zH1oxMTsWHbLn|r)LJeycN`*IslurP&e9FxuWjjLKW}N!@?`spVYE>kZkGzYZ4bXg7 zYN}Zvb{eytcZkP}z6FFDTNZ$`2e|7R15Yt2#W77YAIYCMa;2hxK*QR*72*B_+)#-) z5D1K?X<2@B^nXi5w3;Umbe9z{k@-FMpAQGtLH#Yo|Py1EJg>ecLP z=5Ix?vD}Ziuj~CR~?$nOD=h zSf{S!@!B<&N2Z5$o*bj&SC{jBAuo3{7!GgHgk-gs*D@Ria|Q?J{KldF6SQ6T7>lE~ z`3l@~#bDRo9F`klD4WN!yc<#oR%;Uvi>LLE8h_Nrf5C8`lP^-VY(LOZMZhIL$lj46mMbgbTvw7B^_RVrqDPT%$`9CfB>$$16>+IC z9mj`I0HL_26)A+TcNAc7)I>L(vVOyM7=O_#Hs0h498gTt`2i@YnHVZ1l8iTG+3YjA z=e2W;lown#EqA{{BA!Faucmvo{R0Gc|Ak0S9VD58OB-Tw?1a3^Idr6e`!+PSt)v9E*N>3_Ge zGTmOmP2nh8VPYY1l09i{?)+-tUaz_<19{ZnhasRK>t|t0&=f%|tf3}WlFk(wEf^pr z)^Hd4`CZtV#KfVMnvm=$b|2`tDgeM)bjuO7psW>wde6UX7v;hjYWE0oPMEPOjoRt} zN}`GWbQUXf9{s`x7^yh8heJ|b_U{*i_O z9qaZO_UXk8o&S{L<*$%d#hEs!N*=P${XBA&Z#p8lbj=ds%6(9#5>vne#nEsbA8Wag z|4LhJHP3XOnf$rrEig|W=ne>LDR8(VsVRL0m(ZnYa>exEQ;%RWZ?Z4%RCFzB4+Lx% zA?^W!6{D1qC=lC?TxgSZwsX|8FqIgh%bVxgmhukpG!XR}SO@WiaKyIana-Y>fc{s# zJDaP5n%XK9_dzK|qZnUgW>0uC5-thJ9};=UwB?T^;yFLG{{aUiSGeenbz1-c002ov JPDHLkV1hqbruP5< delta 1708 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 V_-2<35D@?X002ovPDHLkV1mjlhbaI6 literal 0 HcmV?d00001 diff --git a/tools/logo/logo_48.png b/tools/logo/logo_48.png index 67806a7a6ceb3007043ddfb0b835fa39dc7c5998..de7071fea7e67eb74bd7a21e7fa6ba2924d78556 100644 GIT binary patch delta 2182 zcmV;12zmF^6p|5;BYy~4Nklk$`2MxC=lgq|bAIRi&N)|c1%FVnVogmtt=1~hR-xn$ zV6lRE0+j#?q5@+;Kcc!tlOry}X^R~@Dps&+<+^#PwDW`#?K^_pQ>5`@qIlcw zQhOrpEo0Xt0B^&ZI!Duf1Z)M$i|v3*5CfVuVMpRb>)_Q1VEJ;F$FAN6@(NQ^<0>Go zV0$v^`8B-<%zrBufTyA9b~LpQXuL{}U+PvD!lUMimQQjqwOj=EvZjq_>iD&D9zd3& zk;_0G`HmPoww~d5lsfxLs}@ z+4ya~dgq;da;_KKv5Qfo0S_9r_2ahR*Pe-xF$dhsntwJbQTxa-LbGA@s+ByuWec@6 zH2{o^jPjS=yE)j}T8ugXTTq))T`lkC48U{unp<$R4q#59R&J`RGq#^R zb(%jkH`C|y6%#~MbZ14X<52hP0o?hp+v6H*r@(}rQ&q{6k3Y^s4?KXTWuI}5BeZ>R zh+S{KNq;aHDl~|XO+B=Vj*j%_f6SO7?z);66+DrzHeJ`bfBkxX@zT#|Y-m8K+^e!u zipBNy+`oQ30H2)e#c`Z`P1YJx7PkGq!_)dc|KV+1d!wW10V?v*w5+j_XSZ(Q=0%GN z?Zp{5KX`#R-uyF1+K=Tc64mweZSjr|hv1?S(0^;|e+Ar|OZvuzwY;$HIks&6F4fi5 zB{>f;XHFGO_ua=`OP0{v*GDjvb6U9tP1*i|_h4!Ss#dO>mrBWJWT|bu-ZD0A*uZ0( zHsNx)N_IRGEZgFr|2n{1yWb%ek7uLC+-|if(%v$r06fc@o=4Qq+1N|gH1ON!U#7DB zN`KXE*%6H=`0*>RbE-4jva7ytcD1~208Ev{vr^A~X@Z|ecJYk<5G&?<<*GV=%9r4c z18IE0nyfs9JO#XNlrO)x*0yDNHnNp;_%s=#IsJEbe^$v)YMx-B`}!;D_-NST)py4k ziB=K_I#^crVpL#7#a-(b7?y1`sXVIE3x7eA1ywGni1Bjh4Q@*=;`uK>LK&sygJr>6 z2S@4X^P*HGDa&R&mR}{E)>)$|(N^Wd7NCDD34o?SZ~3Qe3vB0aftDK^yTyj?%QpEZ8vk8+MD&4q^%RSL`IO9FX z(}C@5^xQ|)`McQrp@XKpXtOL8mg6uQiBklsiaM;=j_~P3GAqY$3;X2|`~G8~DR)-x za43%L6t@&;3Zlgb`Xec#W>KfC8Azlog7IXr;t@??q9{>;zR|?wj}qVy#(&6j)y#yT z2J{sx9ZuSeM6IH&hvFvjRJv$+;GBl2?ou@P#uC^?bfJh42o;sM7o$fLO^%eJ!L)?I ziGnsC07fDS(spS%BqASauC!{U#EJaBpoy8z`&fu&JB&pVB{>g>%ho>7Vy9aI3XYee z$q`{-BCi4rm`q%!gv1_VT+-_|jOdaY|gT91OQ$HVAJ*$WM`G2G6M=?004H~+;&6C9t3LhQYN4c#?gvq-L><9I&Vt=fu5flCBC{ZAGI!^fPPVCq~F{%JW!P90}+un?}vPqULUAtMJ88C{q zULtHnJ!hV1*)>kEwK_jTzti%%(dfI@QO${>uA$IPzQJ=sY4J+m(T#;suQ1D0JA z*A<;8=TWosP;V}3UP)?py?@TEc2!;tNTegIP1#~!9UE{Z1=tSmy8h^V7VvD-`=dpYy(@nZZaI)IB&+3?L9 zQp#>pN>(Fs2TIi|n19LVHY14mP^w!*9dV1^7CrgiaH+Qc5BhA6zPR06I{*Lx07*qo IM6N<$f`4sBPXGV_ delta 2636 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

%EBkhbSt4 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 Im3PAb0lc#&uK)l5 diff --git a/tools/logo/logo_64.png b/tools/logo/logo_64.png index 72bfcd3c39d976cca52f6ad5d5440fdb40d9e23f..43e92029891c3668cad4318426ea94c1872d276d 100644 GIT binary patch delta 2925 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 X9T&n-o4!?W00000NkvXXu0mjfIj6i- literal 4033 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 From b547205c59206edff702d824bfcd3e16901cdf46 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 11 Mar 2020 12:24:47 -0700 Subject: [PATCH 0145/1218] Build the Windows icon from the source images. Rather than having a separete checked-in copy. --- kokoro/windows/build.bat | 2 +- kokoro/windows/gapid.ico | Bin 141694 -> 0 bytes kokoro/windows/package.bat | 2 +- tools/logo/BUILD.bazel | 17 ++++++++++++++++- 4 files changed, 18 insertions(+), 3 deletions(-) delete mode 100644 kokoro/windows/gapid.ico diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat index 4e85ea7b6e..d225bda5d5 100644 --- a/kokoro/windows/build.bat +++ b/kokoro/windows/build.bat @@ -85,7 +85,7 @@ REM Build everything else. %BUILD_ROOT%\bazel build -c opt --config symbols ^ --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ --define AGI_BUILD_SHA="%BUILD_SHA%" ^ - //:pkg //:symbols //cmd/smoketests //cmd/vulkan_sample:vulkan_sample + //:pkg //:symbols //cmd/smoketests //cmd/vulkan_sample:vulkan_sample //tools/logo:agi_ico if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% echo %DATE% %TIME% diff --git a/kokoro/windows/gapid.ico b/kokoro/windows/gapid.ico deleted file mode 100644 index 9d1d1be535b45a41c609de59263492efcb8f5bec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141694 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 U#5lSsO)L-a#`)^lU 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

vXSvt|y*&gH_mx5K>lREkn4L}N=-7jY6rJp4g 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 Date: Mon, 9 Mar 2020 20:33:48 -0700 Subject: [PATCH 0146/1218] Use the correct logo for the gapid APKs. --- gapidapk/android/app/src/main/BUILD.bazel | 15 ++++++++++++++- .../app/src/main/res/drawable-xxxhdpi/logo.png | Bin 9189 -> 0 bytes 2 files changed, 14 insertions(+), 1 deletion(-) delete mode 100644 gapidapk/android/app/src/main/res/drawable-xxxhdpi/logo.png diff --git a/gapidapk/android/app/src/main/BUILD.bazel b/gapidapk/android/app/src/main/BUILD.bazel index 70077e0da1..6f1c5938f9 100644 --- a/gapidapk/android/app/src/main/BUILD.bazel +++ b/gapidapk/android/app/src/main/BUILD.bazel @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +load("//tools/build:rules.bzl", "copy_to") + filegroup( name = "source", srcs = glob([ @@ -26,7 +28,18 @@ android_library( custom_package = "com.google.android.gapid", manifest = "//tools/build/rules:AndroidManifest.xml", resource_files = [ - "res/drawable-xxxhdpi/logo.png", + ":logo_resource", ], visibility = ["//visibility:public"], ) + +copy_to( + name = "logo_resource", + srcs = [ + "//tools/logo:logo_256.png", + ], + rename = { + "logo_256.png": "logo.png", + }, + to = "res/drawable-xxxhdpi", +) diff --git a/gapidapk/android/app/src/main/res/drawable-xxxhdpi/logo.png b/gapidapk/android/app/src/main/res/drawable-xxxhdpi/logo.png deleted file mode 100644 index 40668c1c608c71b5b359bc0a7caee3e3d5f3a164..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9189 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 Date: Wed, 11 Mar 2020 12:41:11 -0700 Subject: [PATCH 0147/1218] Update the MacOS installer background. --- kokoro/macos/background.png | Bin 3950 -> 3521 bytes kokoro/macos/background@2x.png | Bin 9111 -> 7088 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/kokoro/macos/background.png b/kokoro/macos/background.png index 8f58e4b191c2db1df478b3c2748d348378646e3d..f66bfd0ac54a81280f89134ad3256fbf4c470b6c 100644 GIT binary patch delta 2687 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 R1{46CI&s>x@NdXle+SuiZ#Mt{ literal 9111 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 From 46db549ce7004aac503f600c73174b51b34da200 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 11 Mar 2020 12:47:50 -0700 Subject: [PATCH 0148/1218] Update the Windows installer images. --- kokoro/windows/banner.bmp | Bin 85978 -> 114514 bytes kokoro/windows/ui_dialog.bmp | Bin 615402 -> 615402 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/kokoro/windows/banner.bmp b/kokoro/windows/banner.bmp index d3941084f83800b836c342d6947dc9ce11d112da..579448ea3c701785eee6fc37d1e6d6ba05d0fbdf 100644 GIT binary patch literal 114514 zcmeI5du-KY7>75xgNorI1`HTNz>tV!2*_2OqN1Q?0Z{=VWK5I@2t#fgB3H#f5Jd?A zB1Vlw2?_}aD2NCKfk6z)J*a?k3(h#ufWgnb!;Y@&?VQuD?dh}7v^}TolJ@!a+1Ib% zOLo7UuQD^_XI|-4P&%D2UF}*r&&;?jqgv^F$L7q82K6$^rqb2_e^f@s)qk?CvLDPD zKYi=P+lQ@h-uSlJ=Q4YB=+JO_US8{7d3iOLFJ4@yd)))oS`D6`rR^>A>iU(^bd z01UuDL>PE&(g3_2VQ@Od>kI=hV8y_Z-K+7oOJ~o?zeV-Et9D?2 zIj~(*e2F)tD8T<-QhYPv6(Bg0o9z-lI;uaBI1@#otRF zzsdK$Zk$bio$|}~FaiVdV<3*T(xlINC9}Eh~9j z-2Kfnjnwl!>v`^OoK1G!WS4E=1P0>CK)TmBl|JintFN`GHBW2vf*sAueQj)Ki?jcj z-qqCET3`340~>hS*NwB|nM3ZsTz43N0XGb!Ypt}LK{YD%S!fY`rc1ma$=8jO)hPgmoAJ_bi zv&mf|xno;+fdLpumVqeNN^|RMdGAa=woC78S+;9uOWWIO?3dN zmfbpA+!GM8%R z*dK;q00vTFAk5yja<*AbalNCB%ZWH!+Som8`KZ{J;PVc)>teYn)m+ z+i7f<-q~}G^i)NMUsWXw2b$JF)B3XYbE~mmIGenAkvEP3M=$^bsWK48T4`p^ma$!W zC)+Kr{yAU$^?Q-h&dufROI69--mctjR*M{GlQWGa=CA+*Fc35YVe__`vtRzct)sIS z9m!Fr&TTArwf?+bIlV{yy>_;vx6Q_W;cPOhXNhHafB_f?nt?FYN;5j!X>8Z)NA6Sm zPrq;KYU6pma(tV*uq@Zs-RGxfRp{5o+2qs65$iAk127OY17Y#D(b=!;&oXUeOP}?Z zCuX>Ewej5k^TQfdGOv%NyY;omaW>gB^20hzzyJ({fq^j8IMqA5U`I1kU#~d!Y=u7S zWY68D&2OrbIrmp`w|?vw&L*45^2L6z0|PMNHv>V}O4FQeHnvOptbaQDSyF9ltMev( z-4{QZRLR??^V^g?Bgfff&WasAhYc8jfiN%-q_;I^7Z$ZFZ(~cJ^`29UJ$1G5JeT!# zzw>mtyJhUxFQb|&oJ}T;tgsFfFaQH#V<4y+r{Zk=*e>a_){out`#fFV{b6}uw~YP5 z*<{mi<~Tl#!2k@T%0N)H(!|-be(b2;J2p%epWo(d+uH6N$=I-xS07Nz`ZreD?Q11G z9oo67*zWjzM@C@)24DaNyksBPLhU>{UtK!0JMihk;f-qDv_}&5wKyJUlSMDH z$g$uF24KJq13}d|edFb))Y*gU)P)mY2QsZ$UZ9?Qpm|ch#@S@cO}5wuPGA5A{9quc zT50{dHB=wHJ+?}nz2oz@)R-Zil6JNB9G!MHS@a`|922f!00!JJ5R|vYfw?(tmAKT; zHn+6tXOHifva4}6d2*8{wt*8EfC0Z52)b6+Qsso zSTfJc_icUGlRj&lP2Q>^Z~P88g8>*wm4P5@rRiNM?~A$Z>z1~;ypOKm->+rb*<>u$ zjIloq!2k?+$v{}VE#8&)$L#vL<^6N7`>gGJkF&{|ms#Uj@B{-e-~|Ig)i^ctr8wEx z*DY=ERK{7G{T?@;;cW8dMZP!&9Kiq#c*#HzwbGoNDUO!DZZF1JJN+)J?{PLc^D<`~ z3!Y#A2E1Y*jNZ0#X;poWv&olN`QkXR1OqVOH3LD_IISuNC;EGEHW~9eV;m2rU;qZZ zWFW{|X^A@3@9l9m+43@591EUc00#VE0B>LYe>-tD`SK%Q922f!00z8fAPlwA{BB1( z9Uo_tE3b3K@n8xDV8Aa1;_hvnO}6~X7RQAx7=Qsk7zjg+Q>XT@U*B(AyJ)X?n~8G( X126ysFc1|6Mi04rcc~Y*#BKTy#D?c< literal 85978 zcmeI5c~BI07RO2L)>iHQyR}vO*Vg{AwI!@ZjTcctKu|6j4w)Hd5V;i;10Hyz26R1G z6$KMT1Oz<#;6GKLeYGe{M4a zm#jbEIU>CDZ-4pwM%70y+#o|EJ^ZecTbZDvQ~(tisKA>yuM2atqLscZ zq-?hlA@}rkcZ49C%Ab(*2pwYcf^G)!B>HBuDEh~{OdcH)FrA2l93SXJxQ7a$0#=|v z)8qPWX)A1(;1Dba`8ZFVIFinHlSrHjy$QkDK${^rO?mbx)1X6jz2j%Pj1QB}K#p61 z&!P#a04gA)z%N%WF8?gT=4h@6nC?1x3>AZGG9-lN^e3}uN!ru^HbOUc{N(Wt$Z;X} z!9G*~6|fEk-u3jHI&nBIBETkS9v|tOy?buz+5j*2ahy~*Co@i9ttmkvfw?AEP9vU! zbmw=M|(VS+&a7!tw04(0o@8bf2P`(xz(Cc9;xv9G9%*WGs>REq-*7&F^ci) zR|mp^B*S8g&J3oZhjdb(EVVV+^TCdXEV z;i+pB7fT|ppOHSfm7spS@MgJe|8~!C>8OpXJrd%)*nBt5Xr@A3lTqQt;N033f_t6g z;g>{!H&eBO9JeMvMO#n-R6taLzP`Q--<2iK53vTC1HqHx{Y(EFTU92zQ7XGxseIS? z8R2+Ug(5WQ zI}x%gYZE7CZ*x77<8`_)AZ2BMBPl0mVsH(+=>U8{vV{gZ1#xO=l#1e=CXJH%xd?ti ztlsbKuHwDZvt0`Y#1m&-1k z41th*K{%CNIh5sb?x^J4SN_NIf@8v`b3<VgB{QeM)pdO%Y- z2fPW&f#$hca$nC01lbyJQ^^*F=`_Ac+tYQzTS4w8sFPJ-a^U6-J5w4i!KJ2BSdz!~2`oEfJ@l z;YT5rv3W!2JN*z)o)|z2KSgxf7LL0glrN7V=qA6twg+ z9}gct_*gDcpNrg4@Y>wmY_+x zI+5eH;FV}2Du458?tGFPD`R z22l&1bEyT-qD)RmPJm8_=Vy;dlH$GKA-Cd&2_8j`57IkuI4Xb&*p32itxqzyrwX!9 zytAS>UKhckpQ$yx7@-YuL5^2f$P=Tf8pLF}oE&Np*+`sS`GlThdB*%7A~eVYIc_^H ziI$=QsDM!lz{`f#CJ*jqL*JKZrAIiiIjJ>#%c(Ww0$uPIz@<|PKMw~8$w_vFTJR)U zayG|uRC1yqO#HVC?iIZZj@i(NvHrSU{eaf%Z4h;zA^k|Ln0ifg7H$> z;~Vi@c5~Z;9EZ+LE2cqqB{^<9b%$rx3@RjNQBF4u=XiwNOX}we1ScDE+@_onjYS1e zfgvaWFB>X2V9?8kba9+4Z_>4fiClJb+qyUoHHef*f2Rs!OKm}}8fyPJmTlKwcNEgRRtzny1t)U?t2fpX+@_~?iVK`Mz4k0;{ zUC~74dO1EPct(J?GaH7p4UETa))~=oQ~(t)N`ZD&+xD%gvuC+*9~sC?JqvQ21mo3b z1!@fqX*W1GU?Ad

y-QJCWDB-+<;R)+3VA~01gV5t@Ps=& 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 HJ{b5vV|-bg literal 615402 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 R&)H|chP~4c*n#ah@c&194nF_@ From 3492691a76e2b70d961ec6fc1af3793a9e75a1c6 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 11 Mar 2020 15:06:24 -0700 Subject: [PATCH 0149/1218] Update the .classpath file to find the new logo. --- .classpath | 2 +- gapic/res/BUILD.bazel | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.classpath b/.classpath index bfb8ca26b1..0fe74dbda3 100644 --- a/.classpath +++ b/.classpath @@ -2,7 +2,7 @@ - + diff --git a/gapic/res/BUILD.bazel b/gapic/res/BUILD.bazel index cb4bbb1a76..aaa2c170c1 100644 --- a/gapic/res/BUILD.bazel +++ b/gapic/res/BUILD.bazel @@ -19,7 +19,10 @@ load("//tools/build:rules.bzl", "copy_to", "copy_tree") # into that struture first copy_tree( name = "copy_resources", - srcs = glob(["**/*"]), + srcs = glob( + ["**/*"], + exclude = ["BUILD.bazel"], + ), strip = package_name() + "/", to = "java", ) From 2566b7bc2e6e5d9137cbe00c68eced25b1908e78 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Thu, 12 Mar 2020 22:12:16 -0700 Subject: [PATCH 0150/1218] Only show pipeline view when a draw command is selected (#129) Bug: b/150943958 --- .../com/google/gapid/views/PipelineView.java | 12 +++++++++++- gapis/resolve/resource_data.go | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index 3fe81942db..c92cc85e03 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -87,6 +87,7 @@ import java.util.HashMap; import java.util.concurrent.ExecutionException; import java.util.logging.Logger; +import java.util.logging.Level; /** * View the displays the information for each stage of the pipeline. @@ -153,6 +154,15 @@ public void onResourcesLoaded() { updatePipelines(); } + @Override + public void onCommandsLoaded() { + if (!models.commands.isLoaded()) { + loading.showMessage(Error, Messages.CAPTURE_LOAD_FAILURE); + } else if (models.commands.getSelectedCommands() == null) { + loading.showMessage(Info, Messages.SELECT_DRAW_CALL); + } + } + @Override public void onCommandsSelected(CommandIndex path) { updatePipelines(); @@ -195,7 +205,7 @@ protected void onUiThreadError(Loadable.Message error) { } }); } else { - loading.showMessage(Info, Messages.SELECT_COMMAND); + loading.showMessage(Info, Messages.SELECT_DRAW_CALL); } } diff --git a/gapis/resolve/resource_data.go b/gapis/resolve/resource_data.go index 397993507a..e155190743 100644 --- a/gapis/resolve/resource_data.go +++ b/gapis/resolve/resource_data.go @@ -25,7 +25,9 @@ import ( "github.com/google/gapid/gapis/api/sync" "github.com/google/gapid/gapis/capture" "github.com/google/gapid/gapis/database" + "github.com/google/gapid/gapis/messages" "github.com/google/gapid/gapis/resolve/initialcmds" + "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" ) @@ -180,6 +182,19 @@ func (r *ResourceDataResolvable) Resolve(ctx context.Context) (interface{}, erro // Pipelines resolves the data of the currently bound pipelines at the specified // point in the capture. func Pipelines(ctx context.Context, p *path.Pipelines, r *path.ResolveConfig) (interface{}, error) { + cmd, err := Cmd(ctx, p.After, r) + if err != nil { + return nil, err + } + state, err := GlobalState(ctx, &path.GlobalState{After: p.After}, r) + if err != nil { + return nil, err + } + + if !cmd.CmdFlags(ctx, api.CmdID(p.After.Indices[0]), state).IsExecutedDraw() || len(p.After.Indices) == 1 { + return nil, &service.ErrDataUnavailable{Reason: messages.ErrNotADrawCall()} + } + obj, err := database.Build(ctx, &PipelinesResolvable{Path: p, Config: r}) if err != nil { return nil, err @@ -197,6 +212,7 @@ func (r *PipelinesResolvable) Resolve(ctx context.Context) (interface{}, error) if err != nil { return nil, err } + res, ok := resources.(*ResolvedResources) if !ok { return nil, fmt.Errorf("Cannot resolve resources at command: %v", r.Path.After) From fcbd76f2a40608d494afb1217cb446b8785d2973 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Fri, 13 Mar 2020 18:21:34 +0000 Subject: [PATCH 0151/1218] Remove racy and thus flaky test WithoutSpinLockGuard (#138) This test has a race, and as such it randomly fails on the CI. Bug: b/149401797 --- .../memory_tracker/cc/memory_tracker_test.cpp | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/core/memory_tracker/cc/memory_tracker_test.cpp b/core/memory_tracker/cc/memory_tracker_test.cpp index f622984c00..e072204554 100644 --- a/core/memory_tracker/cc/memory_tracker_test.cpp +++ b/core/memory_tracker/cc/memory_tracker_test.cpp @@ -225,28 +225,6 @@ void* VoidPointerAdd(void* addr, ssize_t offset) { using SpinLockTest = TestFixture; -// Thread A sleeps first, then increases the counter, while Thread B will -// increase the counter before Thread A wakes up. -TEST_F(SpinLockTest, WithoutSpinLockGuard) { - Init(); - uint32_t counter = 0u; - RunInTwoThreads( - // Thread A is initiated first and runs first. - [this, &counter]() { - m_.unlock(); - usleep(5000); - counter++; - EXPECT_EQ(2u, counter); - }, - // Thread B is initiated secondly and runs after thread A runs. - [this, &counter]() { - m_.lock(); - counter++; - EXPECT_EQ(1u, counter); - }); - EXPECT_EQ(2u, counter); -} - // Thread A sleeps first, then increases the counter, but Thread B waits for // the spin lock. So Thread A increases the counter before Thread B. TEST_F(SpinLockTest, WithSpinLockGuard) { From 6c6337f6997e195a12b5f71e39aff774d4cc7856 Mon Sep 17 00:00:00 2001 From: rschiu Date: Fri, 13 Mar 2020 14:07:54 -0700 Subject: [PATCH 0152/1218] Separate vk debug marker layer from cpu timing layer (#133) CPUTiming is often not need together with debug marker. Separate the two layers make the code much easier to maintain. Bug: b/148465074 --- core/app/layout/layout.go | 8 +- .../vk_api_timing_layer/cc/timing_layer.tmpl | 276 +--------------- .../vk_debug_marker_layer/apk/BUILD.bazel | 21 ++ .../vk_debug_marker_layer/cc/BUILD.bazel | 122 +++++++ .../cc/DebugMarkerLayer.json | 15 + .../cc/debug_marker_android.exports | 7 + .../cc/debug_marker_desktop.exports | 3 + .../cc/debug_marker_layer.tmpl | 305 ++++++++++++++++++ .../cc/layer_helpers.cpp | 53 +++ .../cc/vk_api_emitter.cpp | 4 +- .../cc/vk_api_emitter.h | 10 +- .../cc/vk_api_emitter.inc | 2 +- gapidapk/android/apk/BUILD.bazel | 1 + 13 files changed, 544 insertions(+), 283 deletions(-) create mode 100644 core/vulkan/vk_debug_marker_layer/apk/BUILD.bazel create mode 100644 core/vulkan/vk_debug_marker_layer/cc/BUILD.bazel create mode 100644 core/vulkan/vk_debug_marker_layer/cc/DebugMarkerLayer.json create mode 100644 core/vulkan/vk_debug_marker_layer/cc/debug_marker_android.exports create mode 100644 core/vulkan/vk_debug_marker_layer/cc/debug_marker_desktop.exports create mode 100644 core/vulkan/vk_debug_marker_layer/cc/debug_marker_layer.tmpl create mode 100644 core/vulkan/vk_debug_marker_layer/cc/layer_helpers.cpp rename core/vulkan/{vk_api_timing_layer => vk_debug_marker_layer}/cc/vk_api_emitter.cpp (81%) rename core/vulkan/{vk_api_timing_layer => vk_debug_marker_layer}/cc/vk_api_emitter.h (90%) rename core/vulkan/{vk_api_timing_layer => vk_debug_marker_layer}/cc/vk_api_emitter.inc (99%) diff --git a/core/app/layout/layout.go b/core/app/layout/layout.go index 0ea99e7cc9..24925bb436 100644 --- a/core/app/layout/layout.go +++ b/core/app/layout/layout.go @@ -40,6 +40,7 @@ const ( LibGraphicsSpy LibraryType = iota LibVirtualSwapChain LibCPUTiming + LibDebugMarker LibMemoryTracker ) @@ -78,12 +79,14 @@ var libTypeToName = map[LibraryType]string{ LibGraphicsSpy: "libgapii", LibVirtualSwapChain: "libVkLayer_VirtualSwapchain", LibCPUTiming: "libVkLayer_CPUTiming", + LibDebugMarker: "libVkLayer_DebugMarker", LibMemoryTracker: "libVkLayer_MemoryTracker", } var layerNameToLibType = map[string]LibraryType{ "VirtualSwapchain": LibVirtualSwapChain, "CPUTiming": LibCPUTiming, + "DebugMarker": LibDebugMarker, "MemoryTracker": LibMemoryTracker, } @@ -91,7 +94,7 @@ var dataSourceNameToLayerName = map[string]string{ "VirtualSwapchain": "VirtualSwapchain", "VulkanCPUTiming": "CPUTiming", "VulkanMemoryTracker": "MemoryTracker", - "VulkanAPI": "CPUTiming", + "VulkanAPI": "DebugMarker", } var libTypeToJson = map[LibraryType]string{ @@ -99,6 +102,7 @@ var libTypeToJson = map[LibraryType]string{ LibVirtualSwapChain: "VirtualSwapchainLayer.json", LibCPUTiming: "CPUTimingLayer.json", LibMemoryTracker: "MemoryTrackerLayer.json", + LibDebugMarker: "DebugMarker.json", } func withLibraryPlatformSuffix(lib string, os device.OSKind) string { @@ -266,6 +270,7 @@ var libTypeToLibPath = map[LibraryType]string{ LibGraphicsSpy: "gapid/gapii/cc/libgapii", LibVirtualSwapChain: "gapid/core/vulkan/vk_virtual_swapchain/cc/libVkLayer_VirtualSwapchain", LibCPUTiming: "gapid/core/vulkan/vk_api_timing_layer/cc/libVkLayer_CPUTiming", + LibDebugMarker: "gapid/core/vulkan/vk_api_timing_layer/cc/libVkLayer_DebugMarker", LibMemoryTracker: "gapid/core/vulkan/vk_memory_tracker_layer/cc/libVkLayer_MemoryTracker", } @@ -273,6 +278,7 @@ var libTypeToJsonPath = map[LibraryType]string{ LibGraphicsSpy: "gapid/gapii/vulkan/vk_graphics_spy/cc/GraphicsSpyLayer.json", LibVirtualSwapChain: "gapid/core/vulkan/vk_virtual_swapchain/cc/VirtualSwapchainLayer.json", LibCPUTiming: "gapid/core/vulkan/vk_api_timing_layer/cc/CPUTimingLayer.json", + LibDebugMarker: "gapid/core/vulkan/vk_api_timing_layer/cc/DebugMarkerLayer.json", LibMemoryTracker: "gapid/core/vulkan/vk_memory_tracker_layer/cc/MemoryTrackerLayer.json", } diff --git a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl index 31ebe0806c..cb4712a038 100644 --- a/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl +++ b/core/vulkan/vk_api_timing_layer/cc/timing_layer.tmpl @@ -18,49 +18,6 @@ {{Global "Vulkan.LayerName" "CPUTiming"}} {{Global "Vulkan.LayerDescription" "Vulkan API CPU Call Timing"}} -{{define "DEBUG_UTILS_FUNCTIONS"}} -vkSetDebugUtilsObjectNameEXT -vkSetDebugUtilsObjectTagEXT -vkQueueBeginDebugUtilsLabelEXT -vkQueueEndDebugUtilsLabelEXT -vkQueueInsertDebugUtilsLabelEXT -vkCmdBeginDebugUtilsLabelEXT -vkCmdEndDebugUtilsLabelEXT -vkCmdInsertDebugUtilsLabelEXT -vkCreateDebugUtilsMessengerEXT -vkDestroyDebugUtilsMessengerEXT -vkSubmitDebugUtilsMessageEXT -{{end}} - -{{define "IS_DEBUG_UTILS_FUNCTIONS"}} - {{$filters := Strings (Macro "DEBUG_UTILS_FUNCTIONS") | SplitEOL}} - {{range $f := $filters}} - {{if eq $.Name $f}}true{{end}} - {{end}} -{{end}} - -{{define "DEBUG_MARKER_FUNCTIONS"}} -vkDebugMarkerSetObjectTagEXT -vkDebugMarkerSetObjectNameEXT -vkCmdDebugMarkerBeginEXT -vkCmdDebugMarkerEndEXT -vkCmdDebugMarkerInsertEXT -{{end}} - -{{define "ALL_DEBUG_FUNCTIONS"}} - {{Macro "DEBUG_MARKER_FUNCTIONS"}} - {{Macro "DEBUG_UTILS_FUNCTIONS"}} -{{end}} - -{{define "IS_DEBUG_MARKER_FUNCTIONS"}} - {{$filters := Strings (Macro "DEBUG_MARKER_FUNCTIONS") | SplitEOL}} - {{range $f := $filters}} - {{if eq $.Name $f}}true{{end}} - {{end}} -{{end}} - -{{Global "Vulkan.ImplementedFunctions" (Strings (Macro "ALL_DEBUG_FUNCTIONS") | SplitEOL)}} - {{Include "../../../../gapis/api/vulkan/templates/vulkan_layer.tmpl"}} {{$ | Macro "layer_impl.cpp" | Reflow 4 | Write "layer_impl.cpp"}} @@ -70,11 +27,10 @@ vkCmdDebugMarkerInsertEXT {{Template "C++.Copyright"}} #include "core/vulkan/vk_api_timing_layer/cc/layer.h" #include "core/vulkan/vk_api_timing_layer/cc/tracing_helpers.h" -#include "core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.h" #include "core/cc/timer.h" #include -namespace api_timing { +namespace {{(Global "Vulkan.LayerNamespace")}} { struct timer { timer(const char* category, const char* name): @@ -87,13 +43,9 @@ struct timer { const char* cat; }; -static bool debug_utils_ext_supported = false; -static bool debug_marker_ext_supported = false; - {{range $c := AllCommands $}} {{$ind := Title (Macro "InitialIndirection" $c)}} {{if and (not (GetAnnotation $c "pfn")) (not (GetAnnotation $c "synthetic"))}} -{{if and (not (Macro "IS_DEBUG_UTILS_FUNCTIONS" $c)) (not (Macro "IS_DEBUG_MARKER_FUNCTIONS" $c)) (not (eq $c.Name "vkEnumerateInstanceExtensionProperties")) (not (eq $c.Name "vkEnumerateDeviceExtensionProperties"))}} {{Template "BeginPlatformIfDef" $c}} {{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) { timer t("{{$ind}}", "{{$c.Name}}"); @@ -101,232 +53,8 @@ static bool debug_marker_ext_supported = false; } {{Template "EndPlatformIfDef" $c}} -{{else}} - -// Since this layer is declaring the debug extensions are implemented, we need to also implement -// all functions in the extension, but we need to be careful not to forward the function call if -// the extension was not implemented. -{{if and (Macro "IS_DEBUG_UTILS_FUNCTIONS" $c) (not (eq $c.Name "vkSetDebugUtilsObjectNameEXT"))}} -{{Template "BeginPlatformIfDef" $c}} -{{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) { - timer t("{{$ind}}", "{{$c.Name}}"); - -{{if not (IsVoid $c.Return.Type)}} - return debug_utils_ext_supported ? next({{Template "C++.CallArguments" $c}}) : VK_SUCCESS; -{{else}} - if (debug_utils_ext_supported) { - next({{Template "C++.CallArguments" $c}}); - } -{{end}} -} -{{Template "EndPlatformIfDef" $c}} -{{end}} -{{if and (Macro "IS_DEBUG_MARKER_FUNCTIONS" $c) (not (eq $c.Name "vkDebugMarkerSetObjectNameEXT"))}} -{{Template "BeginPlatformIfDef" $c}} -{{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) { - timer t("{{$ind}}", "{{$c.Name}}"); - -{{if not (IsVoid $c.Return.Type)}} - return debug_marker_ext_supported ? next({{Template "C++.CallArguments" $c}}) : VK_SUCCESS; -{{else}} - if (debug_marker_ext_supported) { - next({{Template "C++.CallArguments" $c}}); - } -{{end}} -} -{{Template "EndPlatformIfDef" $c}} -{{end}} - {{end}} {{end}} -{{end}} - -// Maps VkDebugReportObjectTypeEXT to VkObjectType. -VkObjectType getVkObjectType(VkDebugReportObjectTypeEXT vk_debug_report_object_type) { -#define CASE(OBJ) \ - case VK_DEBUG_REPORT_OBJECT_TYPE_##OBJ##_EXT: \ - return VK_OBJECT_TYPE_##OBJ - - switch (vk_debug_report_object_type) { - CASE(UNKNOWN); - CASE(INSTANCE); - CASE(PHYSICAL_DEVICE); - CASE(DEVICE); - CASE(QUEUE); - CASE(SEMAPHORE); - CASE(COMMAND_BUFFER); - CASE(FENCE); - CASE(DEVICE_MEMORY); - CASE(BUFFER); - CASE(IMAGE); - CASE(EVENT); - CASE(QUERY_POOL); - CASE(BUFFER_VIEW); - CASE(IMAGE_VIEW); - CASE(SHADER_MODULE); - CASE(PIPELINE_CACHE); - CASE(PIPELINE_LAYOUT); - CASE(RENDER_PASS); - CASE(PIPELINE); - CASE(DESCRIPTOR_SET_LAYOUT); - CASE(SAMPLER); - CASE(DESCRIPTOR_POOL); - CASE(DESCRIPTOR_SET); - CASE(FRAMEBUFFER); - CASE(COMMAND_POOL); - CASE(SURFACE_KHR); - CASE(SWAPCHAIN_KHR); - CASE(DEBUG_REPORT_CALLBACK_EXT); - CASE(DISPLAY_KHR); - CASE(DISPLAY_MODE_KHR); - CASE(OBJECT_TABLE_NVX); - CASE(INDIRECT_COMMANDS_LAYOUT_NVX); - CASE(VALIDATION_CACHE_EXT); - CASE(SAMPLER_YCBCR_CONVERSION); - CASE(DESCRIPTOR_UPDATE_TEMPLATE); - CASE(ACCELERATION_STRUCTURE_NV); - default: - return VK_OBJECT_TYPE_UNKNOWN; - } -#undef CASE -} - -VkResult vkSetDebugUtilsObjectNameEXT( - PFN_vkSetDebugUtilsObjectNameEXT next, - VkDevice device, - const VkDebugUtilsObjectNameInfoEXT* pNameInfo) { - timer t("VkDevice", "vkSetDebugUtilsObjectNameEXT"); - - api_timing::VkApiEmit().EmitDebugUtilsObjectName( - reinterpret_cast(device), pNameInfo->objectType, pNameInfo->objectHandle, pNameInfo->pObjectName); - - // Must not forward function call if the extension was not supported. - return debug_utils_ext_supported ? next(device, pNameInfo) : VK_SUCCESS; -} - -VkResult vkDebugMarkerSetObjectNameEXT( - PFN_vkDebugMarkerSetObjectNameEXT next, - VkDevice device, - VkDebugMarkerObjectNameInfoEXT const* pNameInfo) { - timer t("VkDevice", "vkDebugMarkerSetObjectNameEXT"); - - // Convert object type to VkObjectType and emit the trace. - api_timing::VkApiEmit().EmitDebugUtilsObjectName( - reinterpret_cast(device), getVkObjectType(pNameInfo->objectType), pNameInfo->object, pNameInfo->pObjectName); - - // Must not forward function call if the extension was not supported. - return debug_marker_ext_supported ? next(device, pNameInfo) : VK_SUCCESS; -} - - -namespace { - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) - -const char* LAYER_NAME = "CPUTiming"; -const VkExtensionProperties INSTANCE_EXTENSIONS[] = { - {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}, -}; -const uint32_t NUM_INSTANCE_EXTENSIONS = ARRAY_SIZE(INSTANCE_EXTENSIONS); -const VkExtensionProperties DEVICE_EXTENSIONS[] = { - {VK_EXT_DEBUG_MARKER_EXTENSION_NAME, VK_EXT_DEBUG_MARKER_SPEC_VERSION}, -}; -const uint32_t NUM_DEVICE_EXTENSIONS = ARRAY_SIZE(DEVICE_EXTENSIONS); - -#undef ARRAY_SIZE - -/** - * Enumerate extension properties for a specific layer. - * - * This should expose only the new extensions added by the layer. - */ -VkResult enumerateExtensionPropertiesForLayer( - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties, - uint32_t numExtensions, - const VkExtensionProperties extensions[]) { - if (pProperties == nullptr) { - *pPropertyCount = numExtensions; - return VK_SUCCESS; - } - uint32_t capacity = std::min(*pPropertyCount, numExtensions); - memcpy(pProperties, extensions, capacity * sizeof(VkExtensionProperties)); - if (*pPropertyCount < numExtensions) { - return VK_INCOMPLETE; - } else { - *pPropertyCount = numExtensions; - return VK_SUCCESS; - } -} -} // end of anonymous namespace - -// This layer needs to add VK_EXT_debug_utils and VK_EXT_debug_marker as a supported extension. - -VkResult vkEnumerateInstanceExtensionProperties( - PFN_vkEnumerateInstanceExtensionProperties next, - char const* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties) { - timer t("", "vkEnumerateInstanceExtensionProperties"); - if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) { - return enumerateExtensionPropertiesForLayer( - pPropertyCount, - pProperties, - NUM_INSTANCE_EXTENSIONS, - INSTANCE_EXTENSIONS); - } - return next(pLayerName, pPropertyCount, pProperties); -} - -VkResult vkEnumerateDeviceExtensionProperties( - PFN_vkEnumerateDeviceExtensionProperties next, - VkPhysicalDevice physicalDevice, - char const* pLayerName, - uint32_t* pPropertyCount, - VkExtensionProperties* pProperties) { - timer t("VkPhysicalDevice", "vkEnumerateDeviceExtensionProperties"); - - if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) { - return enumerateExtensionPropertiesForLayer( - pPropertyCount, - pProperties, - NUM_DEVICE_EXTENSIONS, - DEVICE_EXTENSIONS); - } - // Manually append device extension. This should not be necessary, but the Android vulkan - // loader does not expose extensions from implicit layer (b/143293104). - if (pProperties == nullptr) { - VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties); - if (res == VK_SUCCESS) { - (*pPropertyCount) += NUM_DEVICE_EXTENSIONS; - } - return res; - } - if (*pPropertyCount > 0) { - uint32_t requestedCount = *pPropertyCount; - VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties); - if (res == VK_SUCCESS) { - for (uint32_t i = 0; i < *pPropertyCount; ++i) { - if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, pProperties[i].extensionName)) { - debug_utils_ext_supported = true; - } - if (!strcmp(VK_EXT_DEBUG_MARKER_EXTENSION_NAME, pProperties[i].extensionName)) { - debug_marker_ext_supported = true; - } - } - // *pPropertyCount is expected to be requestedCount - NUM_DEVICE_EXTENSIONS. - *pPropertyCount = std::min(*pPropertyCount + NUM_DEVICE_EXTENSIONS, requestedCount); - uint32_t count = std::min(NUM_DEVICE_EXTENSIONS, *pPropertyCount); - memcpy( - &pProperties[*pPropertyCount - count], - DEVICE_EXTENSIONS, - count * sizeof(VkExtensionProperties)); - } - return res; - } - return VK_SUCCESS; -} - -} +} // end of {{(Global "Vulkan.LayerNamespace")}} {{end}} diff --git a/core/vulkan/vk_debug_marker_layer/apk/BUILD.bazel b/core/vulkan/vk_debug_marker_layer/apk/BUILD.bazel new file mode 100644 index 0000000000..dc19ff9e2e --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/apk/BUILD.bazel @@ -0,0 +1,21 @@ +# Copyright (C) 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless requ`ired by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//tools/build:rules.bzl", "android_native") + +android_native( + name = "VkLayer_DebugMarker", + visibility = ["//visibility:public"], + deps = ["//core/vulkan/vk_debug_marker_layer/cc:libVkLayer_DebugMarker_android"], +) diff --git a/core/vulkan/vk_debug_marker_layer/cc/BUILD.bazel b/core/vulkan/vk_debug_marker_layer/cc/BUILD.bazel new file mode 100644 index 0000000000..803a74cf0f --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/BUILD.bazel @@ -0,0 +1,122 @@ +# Copyright (C) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//tools/build:rules.bzl", "android_dynamic_library", "api_template", "apic_template", "cc_copts", "cc_dynamic_library") + +api_template( + name = "debug_marker", + includes = [ + "//gapis/api/vulkan/templates:vulkan_layer", + ], + outputs = [ + "layer.h", + "layer.cpp", + "layer_impl.cpp", + ], + template = "debug_marker_layer.tmpl", +) + +apic_template( + name = "debug_marker_templated", + api = "//gapis/api/vulkan:api", + templates = [ + ":debug_marker", + ], +) + +cc_library( + name = "cc", + srcs = glob([ + "*.cpp", + "*.inc", + "*.h", + ]) + [ + ":debug_marker_templated", + ], + copts = cc_copts() + select({ + "//tools/build:linux": [ + "-DVK_USE_PLATFORM_XCB_KHR", + "-DVK_USE_PLATFORM_GGP", + ], + "//tools/build:darwin": [], + "//tools/build:windows": ["-DVK_USE_PLATFORM_WIN32_KHR"], + # Android + "//conditions:default": ["-DVK_USE_PLATFORM_ANDROID_KHR"], + }) + [ + "-fno-rtti", + "-fno-exceptions", + "-DNDEBUG", # always ndebug for perfetto + ], + linkopts = select({ + "//tools/build:linux": ["-lpthread"], + "//tools/build:darwin": [], + "//tools/build:windows": ["-lpthread"], + # Android + "//conditions:default": [ + "-ldl", + "-lm", + "-llog", + ], + }), + visibility = ["//visibility:public"], + deps = [ + "//core/cc", + "//core/vulkan/cc/include/ggp_c:vulkan_ggp_dummy", + "//core/vulkan/layer_helpers", + "//core/vulkan/perfetto_producer", + "@vulkan-headers//:vulkan", + ], +) + +cc_library( + name = "headers", + srcs = glob([ + "*.h", + ]), + copts = cc_copts() + select({ + "//tools/build:linux": [ + "-DVK_USE_PLATFORM_XCB_KHR", + ], + "//tools/build:darwin": [], + "//tools/build:windows": ["-DVK_USE_PLATFORM_WIN32_KHR"], + # Android + "//conditions:default": ["-DVK_USE_PLATFORM_ANDROID_KHR"], + }), + visibility = ["//visibility:public"], + deps = [ + "@vulkan-headers//:vulkan", + ], +) + +cc_dynamic_library( + name = "libVkLayer_DebugMarker", + visibility = ["//visibility:public"], + exports = "debug_marker_desktop.exports", + deps = [":cc"], +) + +android_dynamic_library( + name = "libVkLayer_DebugMarker_android", + visibility = ["//visibility:public"], + exports = "debug_marker_android.exports", + deps = [":cc"], +) + +filegroup( + name = "json", + srcs = [ + "DebugMarkerLayer.json", + ], + visibility = ["//visibility:public"], +) diff --git a/core/vulkan/vk_debug_marker_layer/cc/DebugMarkerLayer.json b/core/vulkan/vk_debug_marker_layer/cc/DebugMarkerLayer.json new file mode 100644 index 0000000000..890145ea9e --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/DebugMarkerLayer.json @@ -0,0 +1,15 @@ +{ + "file_format_version": "1.0.0", + "layer": { + "name": "DebugMarker", + "type": "GLOBAL", + "library_path": "", + "api_version": "1.0.5", + "implementation_version": "1", + "description": "Vulkan Debug Marker Producer", + "functions": { + "vkGetDeviceProcAddr": "VkApiGetDeviceProcAddr", + "vkGetInstanceProcAddr": "VkApiGetInstanceProcAddr" + } + } +} diff --git a/core/vulkan/vk_debug_marker_layer/cc/debug_marker_android.exports b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_android.exports new file mode 100644 index 0000000000..be14bdd399 --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_android.exports @@ -0,0 +1,7 @@ +DebugMarkerGetDeviceProcAddr +DebugMarkerGetInstanceProcAddr +vkEnumerateInstanceLayerProperties +vkEnumerateInstanceExtensionProperties +vkEnumerateDeviceLayerProperties +vkEnumerateDeviceExtensionProperties +_layer_dummy_func__ diff --git a/core/vulkan/vk_debug_marker_layer/cc/debug_marker_desktop.exports b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_desktop.exports new file mode 100644 index 0000000000..0a9cca735b --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_desktop.exports @@ -0,0 +1,3 @@ +DebugMarkerGetDeviceProcAddr +DebugMarkerGetInstanceProcAddr +_layer_dummy_func__ diff --git a/core/vulkan/vk_debug_marker_layer/cc/debug_marker_layer.tmpl b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_layer.tmpl new file mode 100644 index 0000000000..e565efb788 --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/debug_marker_layer.tmpl @@ -0,0 +1,305 @@ +{{/* + * Copyright (C) 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */}} + +{{Global "Vulkan.LayerNamespace" "vk_api"}} +{{Global "Vulkan.LayerName" "DebugMarker"}} +{{Global "Vulkan.LayerDescription" "Record Vulkan debug marker"}} + +{{define "DEBUG_UTILS_FUNCTIONS"}} +vkSetDebugUtilsObjectNameEXT +vkSetDebugUtilsObjectTagEXT +vkQueueBeginDebugUtilsLabelEXT +vkQueueEndDebugUtilsLabelEXT +vkQueueInsertDebugUtilsLabelEXT +vkCmdBeginDebugUtilsLabelEXT +vkCmdEndDebugUtilsLabelEXT +vkCmdInsertDebugUtilsLabelEXT +vkCreateDebugUtilsMessengerEXT +vkDestroyDebugUtilsMessengerEXT +vkSubmitDebugUtilsMessageEXT +{{end}} + +{{define "IS_DEBUG_UTILS_FUNCTIONS"}} + {{$filters := Strings (Macro "DEBUG_UTILS_FUNCTIONS") | SplitEOL}} + {{range $f := $filters}} + {{if eq $.Name $f}}true{{end}} + {{end}} +{{end}} + +{{define "DEBUG_MARKER_FUNCTIONS"}} +vkDebugMarkerSetObjectTagEXT +vkDebugMarkerSetObjectNameEXT +vkCmdDebugMarkerBeginEXT +vkCmdDebugMarkerEndEXT +vkCmdDebugMarkerInsertEXT +{{end}} + +{{define "OTHER_OVERRIDES"}} +vkEnumerateInstanceExtensionProperties +vkEnumerateDeviceExtensionProperties +{{end}} + + +{{define "ALL_DEBUG_FUNCTIONS"}} + {{Macro "DEBUG_MARKER_FUNCTIONS"}} + {{Macro "DEBUG_UTILS_FUNCTIONS"}} + {{Macro "OTHER_OVERRIDES"}} +{{end}} + +{{define "IS_DEBUG_MARKER_FUNCTIONS"}} + {{$filters := Strings (Macro "DEBUG_MARKER_FUNCTIONS") | SplitEOL}} + {{range $f := $filters}} + {{if eq $.Name $f}}true{{end}} + {{end}} +{{end}} + +{{Global "Vulkan.OverrideFunctions" (Strings (Macro "ALL_DEBUG_FUNCTIONS") | SplitEOL)}} +{{Global "Vulkan.ImplementedFunctions" (Strings (Macro "ALL_DEBUG_FUNCTIONS") | SplitEOL)}} + +{{Include "../../../../gapis/api/vulkan/templates/vulkan_layer.tmpl"}} + +{{$ | Macro "layer_impl.cpp" | Reflow 4 | Write "layer_impl.cpp"}} + +{{define "layer_impl.cpp"}} + +{{Template "C++.Copyright"}} +#include "core/vulkan/vk_debug_marker_layer/cc/layer.h" +#include "core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.h" +#include + +namespace {{(Global "Vulkan.LayerNamespace")}} { + +static bool debug_utils_ext_supported = false; +static bool debug_marker_ext_supported = false; + +// Since this layer is declaring the debug extensions are implemented, we need to also implement +// all functions in the extension, but we need to be careful not to forward the function call if +// the extension was not implemented. +{{range $c := AllCommands $}} + +{{if and (Macro "IS_DEBUG_UTILS_FUNCTIONS" $c) (not (eq $c.Name "vkSetDebugUtilsObjectNameEXT"))}} +{{Template "BeginPlatformIfDef" $c}} +{{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) { + +{{if not (IsVoid $c.Return.Type)}} + return (debug_utils_ext_supported && next != nullptr) ? next({{Template "C++.CallArguments" $c}}) : VK_SUCCESS; +{{else}} + if (next != nullptr) { + next({{Template "C++.CallArguments" $c}}); + } +{{end}} +} +{{Template "EndPlatformIfDef" $c}} +{{end}} + +{{if and (Macro "IS_DEBUG_MARKER_FUNCTIONS" $c) (not (eq $c.Name "vkDebugMarkerSetObjectNameEXT"))}} +{{Template "BeginPlatformIfDef" $c}} +{{Template "C++.BaseType" $c.Return.Type}} {{$c.Name}}(PFN_{{$c.Name}} next, {{Macro "C++.BaseCallParameters" $c | JoinWith ", "}}) { + +{{if not (IsVoid $c.Return.Type)}} + return (debug_marker_ext_supported && next != nullptr) ? next({{Template "C++.CallArguments" $c}}) : VK_SUCCESS; +{{else}} + if (next != nullptr) { + next({{Template "C++.CallArguments" $c}}); + } +{{end}} +} +{{Template "EndPlatformIfDef" $c}} +{{end}} + +{{end}} + + +// Maps VkDebugReportObjectTypeEXT to VkObjectType. +VkObjectType getVkObjectType(VkDebugReportObjectTypeEXT vk_debug_report_object_type) { +#define CASE(OBJ) \ + case VK_DEBUG_REPORT_OBJECT_TYPE_##OBJ##_EXT: \ + return VK_OBJECT_TYPE_##OBJ + + switch (vk_debug_report_object_type) { + CASE(UNKNOWN); + CASE(INSTANCE); + CASE(PHYSICAL_DEVICE); + CASE(DEVICE); + CASE(QUEUE); + CASE(SEMAPHORE); + CASE(COMMAND_BUFFER); + CASE(FENCE); + CASE(DEVICE_MEMORY); + CASE(BUFFER); + CASE(IMAGE); + CASE(EVENT); + CASE(QUERY_POOL); + CASE(BUFFER_VIEW); + CASE(IMAGE_VIEW); + CASE(SHADER_MODULE); + CASE(PIPELINE_CACHE); + CASE(PIPELINE_LAYOUT); + CASE(RENDER_PASS); + CASE(PIPELINE); + CASE(DESCRIPTOR_SET_LAYOUT); + CASE(SAMPLER); + CASE(DESCRIPTOR_POOL); + CASE(DESCRIPTOR_SET); + CASE(FRAMEBUFFER); + CASE(COMMAND_POOL); + CASE(SURFACE_KHR); + CASE(SWAPCHAIN_KHR); + CASE(DEBUG_REPORT_CALLBACK_EXT); + CASE(DISPLAY_KHR); + CASE(DISPLAY_MODE_KHR); + CASE(OBJECT_TABLE_NVX); + CASE(INDIRECT_COMMANDS_LAYOUT_NVX); + CASE(VALIDATION_CACHE_EXT); + CASE(SAMPLER_YCBCR_CONVERSION); + CASE(DESCRIPTOR_UPDATE_TEMPLATE); + CASE(ACCELERATION_STRUCTURE_NV); + default: + return VK_OBJECT_TYPE_UNKNOWN; + } +#undef CASE +} + +VkResult vkSetDebugUtilsObjectNameEXT( + PFN_vkSetDebugUtilsObjectNameEXT next, + VkDevice device, + const VkDebugUtilsObjectNameInfoEXT* pNameInfo) { + vk_api::VkApiEmit().EmitDebugUtilsObjectName( + reinterpret_cast(device), pNameInfo->objectType, pNameInfo->objectHandle, pNameInfo->pObjectName); + + // Must not forward function call if the extension was not supported. + return debug_utils_ext_supported ? next(device, pNameInfo) : VK_SUCCESS; +} + +VkResult vkDebugMarkerSetObjectNameEXT( + PFN_vkDebugMarkerSetObjectNameEXT next, + VkDevice device, + VkDebugMarkerObjectNameInfoEXT const* pNameInfo) { + // Convert object type to VkObjectType and emit the trace. + vk_api::VkApiEmit().EmitDebugUtilsObjectName( + reinterpret_cast(device), getVkObjectType(pNameInfo->objectType), pNameInfo->object, pNameInfo->pObjectName); + + // Must not forward function call if the extension was not supported. + return debug_marker_ext_supported ? next(device, pNameInfo) : VK_SUCCESS; +} + +namespace { + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +const char* LAYER_NAME = "{{Global "Vulkan.LayerName"}}"; +const VkExtensionProperties INSTANCE_EXTENSIONS[] = { + {VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_UTILS_SPEC_VERSION}, +}; +const uint32_t NUM_INSTANCE_EXTENSIONS = ARRAY_SIZE(INSTANCE_EXTENSIONS); +const VkExtensionProperties DEVICE_EXTENSIONS[] = { + {VK_EXT_DEBUG_MARKER_EXTENSION_NAME, VK_EXT_DEBUG_MARKER_SPEC_VERSION}, +}; +const uint32_t NUM_DEVICE_EXTENSIONS = ARRAY_SIZE(DEVICE_EXTENSIONS); + +#undef ARRAY_SIZE + +/** + * Enumerate extension properties for a specific layer. + * + * This should expose only the new extensions added by the layer. + */ +VkResult enumerateExtensionPropertiesForLayer( + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties, + uint32_t numExtensions, + const VkExtensionProperties extensions[]) { + if (pProperties == nullptr) { + *pPropertyCount = numExtensions; + return VK_SUCCESS; + } + uint32_t capacity = std::min(*pPropertyCount, numExtensions); + memcpy(pProperties, extensions, capacity * sizeof(VkExtensionProperties)); + if (*pPropertyCount < numExtensions) { + return VK_INCOMPLETE; + } else { + *pPropertyCount = numExtensions; + return VK_SUCCESS; + } +} +} // end of anonymous namespace + +// This layer needs to add VK_EXT_debug_utils and VK_EXT_debug_marker as a supported extension. + +VkResult vkEnumerateInstanceExtensionProperties( + PFN_vkEnumerateInstanceExtensionProperties next, + char const* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties) { + if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) { + return enumerateExtensionPropertiesForLayer( + pPropertyCount, + pProperties, + NUM_INSTANCE_EXTENSIONS, + INSTANCE_EXTENSIONS); + } + return next(pLayerName, pPropertyCount, pProperties); +} + +VkResult vkEnumerateDeviceExtensionProperties( + PFN_vkEnumerateDeviceExtensionProperties next, + VkPhysicalDevice physicalDevice, + char const* pLayerName, + uint32_t* pPropertyCount, + VkExtensionProperties* pProperties) { + if (pLayerName != nullptr && strcmp(pLayerName, LAYER_NAME) == 0) { + return enumerateExtensionPropertiesForLayer( + pPropertyCount, + pProperties, + NUM_DEVICE_EXTENSIONS, + DEVICE_EXTENSIONS); + } + // Manually append device extension. This should not be necessary, but the Android vulkan + // loader does not expose extensions from implicit layer (b/143293104). + if (pProperties == nullptr) { + VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties); + if (res == VK_SUCCESS) { + (*pPropertyCount) += NUM_DEVICE_EXTENSIONS; + } + return res; + } + if (*pPropertyCount > 0) { + uint32_t requestedCount = *pPropertyCount; + VkResult res = next(physicalDevice, pLayerName, pPropertyCount, pProperties); + if (res == VK_SUCCESS) { + for (uint32_t i = 0; i < *pPropertyCount; ++i) { + if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, pProperties[i].extensionName)) { + debug_utils_ext_supported = true; + } + if (!strcmp(VK_EXT_DEBUG_MARKER_EXTENSION_NAME, pProperties[i].extensionName)) { + debug_marker_ext_supported = true; + } + } + // *pPropertyCount is expected to be requestedCount - NUM_DEVICE_EXTENSIONS. + *pPropertyCount = std::min(*pPropertyCount + NUM_DEVICE_EXTENSIONS, requestedCount); + uint32_t count = std::min(NUM_DEVICE_EXTENSIONS, *pPropertyCount); + memcpy( + &pProperties[*pPropertyCount - count], + DEVICE_EXTENSIONS, + count * sizeof(VkExtensionProperties)); + } + return res; + } + return VK_SUCCESS; +} + +} // end of {{(Global "Vulkan.LayerNamespace")}} +{{end}} diff --git a/core/vulkan/vk_debug_marker_layer/cc/layer_helpers.cpp b/core/vulkan/vk_debug_marker_layer/cc/layer_helpers.cpp new file mode 100644 index 0000000000..25651942a7 --- /dev/null +++ b/core/vulkan/vk_debug_marker_layer/cc/layer_helpers.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "core/cc/log.h" +#include "core/cc/target.h" +extern "C" { +__attribute__((constructor)) void _layer_dummy_func__(); +} +#if (TARGET_OS == GAPID_OS_WINDOWS) || (TARGET_OS == GAPID_OS_OSX) +class dummy_struct {}; +#else +#include +#include +#include +class dummy_struct { + public: + dummy_struct(); +}; + +dummy_struct::dummy_struct() { + GAPID_ERROR("Loading dummy struct"); + Dl_info info; + if (dladdr((void*)&_layer_dummy_func__, &info)) { + dlopen(info.dli_fname, RTLD_NODELETE); + } +} +#endif + +extern "C" { +// _layer_dummy_func__ is marked __attribute__((constructor)) +// this means on .so open, it will be called. Once that happens, +// we create a dummy struct, which on Android and Linux, +// Forces the layer to never be unloaded. There is some global +// state in perfetto producers that does not like being unloaded. +void _layer_dummy_func__() { + dummy_struct d; + (void)d; +} +} diff --git a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.cpp b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.cpp similarity index 81% rename from core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.cpp rename to core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.cpp index edefe3242a..ec2e4f80ce 100644 --- a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.cpp +++ b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.cpp @@ -15,5 +15,5 @@ * */ -#include "core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.h" -PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(api_timing::VkApiProducer); +#include "core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.h" +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(vk_api::VkApiProducer); diff --git a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.h b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.h similarity index 90% rename from core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.h rename to core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.h index 6a1e3c114c..6fcad6fa6a 100644 --- a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.h +++ b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.h @@ -22,7 +22,7 @@ #include "core/vulkan/perfetto_producer/perfetto_data_source.h" #include "core/vulkan/perfetto_producer/perfetto_threadlocal_emitter.h" -namespace api_timing { +namespace vk_api { template class VkApiEmitter : ThreadlocalEmitterBase { @@ -81,12 +81,12 @@ struct VkApiTypeTraits { }; using VkApiProducer = VkApiEmitter; -auto const VkApiEmit = &api_timing::tracing::Emit; -} // namespace api_timing +auto const VkApiEmit = &vk_api::tracing::Emit; +} // namespace vk_api #define __INCLUDING_VK_API_EMITTER_INC__ -#include "core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.inc" +#include "core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.inc" #undef __INCLUDING_VK_API_EMITTER_INC__ -PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(api_timing::VkApiProducer); +PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(vk_api::VkApiProducer); #endif diff --git a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.inc b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.inc similarity index 99% rename from core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.inc rename to core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.inc index 50964be549..f8e32b52a8 100644 --- a/core/vulkan/vk_api_timing_layer/cc/vk_api_emitter.inc +++ b/core/vulkan/vk_debug_marker_layer/cc/vk_api_emitter.inc @@ -19,7 +19,7 @@ #include "perfetto/tracing/core/data_source_config.h" #include "perfetto/base/time.h" -namespace api_timing { +namespace vk_api { template VkApiEmitter::VkApiEmitter() { diff --git a/gapidapk/android/apk/BUILD.bazel b/gapidapk/android/apk/BUILD.bazel index c0a6eacee6..25a9177a1c 100644 --- a/gapidapk/android/apk/BUILD.bazel +++ b/gapidapk/android/apk/BUILD.bazel @@ -18,6 +18,7 @@ _NATIVE_LIBRARIES = { "deviceinfo": "//core/os/device/deviceinfo/apk", "VkLayer_VirtualSwapchain": "//core/vulkan/vk_virtual_swapchain/apk", "VkLayer_CPUTiming": "//core/vulkan/vk_api_timing_layer/apk", + "VkLayer_DebugMarker": "//core/vulkan/vk_debug_marker_layer/apk", "VkLayer_MemoryTracker": "//core/vulkan/vk_memory_tracker_layer/apk", "gapii": "//gapii/apk", "interceptor": "//gapii/apk", From 507af2c11dbabfe8c8e529b70834e2ba56e719c4 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Fri, 13 Mar 2020 21:16:34 +0000 Subject: [PATCH 0153/1218] Save trace of swiftshader test, for debug purposes (#136) We have a flaky failure on our swiftshader capture-replay test, so let's temporarily save the trace such that we can properly debug next time the failure occurs. Bug: b/151297033 --- kokoro/linux/build.sh | 4 ++-- kokoro/linux/common.cfg | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 7eee6c41bf..088efab801 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -125,6 +125,6 @@ test "${APP_EXIT_STATUS}" -eq 130 # TODO(https://github.com/google/gapid/issues/3163): The coherent memory # tracker must be disabled with SwiftShader for now. -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out out/dist/vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 vulkan_sample.gfxtrace +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 out/dist/vulkan_sample.gfxtrace diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index a3db974c96..6fe4469f5b 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -18,6 +18,8 @@ action { regex: "out/dist/agi*.deb" regex: "out/dist/agi*.zip" regex: "out/dist/*gapir*.sym" + # b/151297033: save trace of sample on swiftshader, for debug purposes + regex: "out/dist/*.gfxtrace" strip_prefix: "out/dist" } } From 874dad048b822f0f71429aeabf7c932bf21ff407 Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Fri, 13 Mar 2020 19:14:20 -0700 Subject: [PATCH 0154/1218] Add multiple improvements to system profiler selection. (#118) - Add selection behavior to Frame Event Panel, GPU Queue Panel and Thread Panel under time quantization. - Remove generic typed key in selection framework. - In Replay Profiler, set slice id with real perfetto query result. - Allow zooming for zero duration signals in Frame Event Panel. - Show full name at hovering for Surface Flinger track. - Set mouse cursor to hand when hanging over clickable area. - Bug: http://b/147922469. #1. --- .../perfetto/models/BatterySummaryTrack.java | 4 +- .../gapid/perfetto/models/CounterTrack.java | 4 +- .../gapid/perfetto/models/CpuTrack.java | 6 +- .../perfetto/models/FrameEventsTrack.java | 86 ++++++------- .../perfetto/models/MemorySummaryTrack.java | 4 +- .../gapid/perfetto/models/Selection.java | 76 ++++++------ .../gapid/perfetto/models/SliceTrack.java | 115 ++++++++---------- .../gapid/perfetto/models/ThreadTrack.java | 107 ++++++++-------- .../perfetto/models/VulkanEventTrack.java | 6 +- .../perfetto/views/BatterySummaryPanel.java | 9 +- .../gapid/perfetto/views/CounterPanel.java | 9 +- .../google/gapid/perfetto/views/CpuPanel.java | 16 ++- .../views/FrameEventsSummaryPanel.java | 55 ++++++++- .../gapid/perfetto/views/GpuQueuePanel.java | 46 +++++-- .../perfetto/views/MemorySummaryPanel.java | 9 +- .../perfetto/views/MultiSelectionView.java | 4 +- .../perfetto/views/ProcessSummaryPanel.java | 16 ++- .../google/gapid/perfetto/views/State.java | 10 +- .../gapid/perfetto/views/ThreadPanel.java | 62 ++++++---- .../perfetto/views/VulkanEventPanel.java | 2 +- .../main/com/google/gapid/util/Arrays.java | 4 + .../com/google/gapid/views/ProfileView.java | 48 +++++--- gapis/service/service.proto | 11 +- gapis/trace/android/adreno/profiling_data.go | 14 ++- 24 files changed, 412 insertions(+), 311 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java index 92c8a15d7b..51641f93ef 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/BatterySummaryTrack.java @@ -224,7 +224,7 @@ public static Data empty(DataRequest req) { } } - public static class Values implements Selection, Selection.Builder { + public static class Values implements Selection, Selection.Builder { public final long[] ts; public final long[] dur; public final long[] capacity; @@ -338,7 +338,7 @@ public Values combine(Values that) { } @Override - public Selection build() { + public Selection build() { return this; } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java index 8c39396444..4b4be9aebc 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java @@ -180,7 +180,7 @@ public static Data empty(DataRequest req) { } } - public static class Values implements Selection, Selection.Builder { + public static class Values implements Selection, Selection.Builder { public final long[] ts; public final String[] names; public final double[][] values; @@ -310,7 +310,7 @@ private static long[] combineTs(long[] a, long[] b) { } @Override - public Selection build() { + public Selection build() { return this; } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java index 54a9a4ee80..a1e525dceb 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java @@ -225,7 +225,7 @@ public static enum Kind { } } - public static class Slice implements Selection { + public static class Slice implements Selection { public final long id; public final long time; public final long dur; @@ -286,7 +286,7 @@ public String toString() { } } - public static class Slices implements Selection { + public static class Slices implements Selection { private final List slices; public final ImmutableList processes; public final ImmutableSet sliceKeys; @@ -350,7 +350,7 @@ public SlicesBuilder combine(SlicesBuilder other) { } @Override - public Selection build() { + public Selection build() { return new Slices(slices, processes.values().stream() .map(ByProcess.Builder::build) .sorted((p1, p2) -> Long.compare(p2.dur, p1.dur)) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java index d732296ddf..562f234c2a 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java @@ -37,6 +37,7 @@ import com.google.gapid.perfetto.views.FrameEventsSelectionView; import com.google.gapid.perfetto.views.State; +import java.util.Arrays; import org.eclipse.swt.widgets.Composite; import java.util.List; @@ -59,12 +60,16 @@ public class FrameEventsTrack extends Track.WithQueryEngine= %d - dur and ts <= %d order by ts"; private static final String SUMMARY_SQL = - "select quantum_ts, count(*) from %s " + + "select group_concat(id) ids, quantum_ts, count(*) from %s " + "where name = 'PresentFenceSignaled' or name GLOB '*[0-9]*'" + "group by quantum_ts"; private static final String RANGE_SQL = "select " + BASE_COLUMNS + " from %s " + "where ts < %d and ts + dur >= %d and depth >= %d and depth <= %d"; + private static final String RANGE_FOR_IDS_SQL = + "select " + BASE_COLUMNS + " from %s where id in (%s)"; + + private static final long SIGNAL_MARGIN_NS = 10000; private final long trackId; @@ -124,8 +129,14 @@ private String slicesSql(DataRequest req) { private ListenableFuture computeSummary(DataRequest req, Window w) { return transform(qe.query(summarySql()), result -> { - Data data = new Data(req, w.bucketSize, new long[w.getNumberOfBuckets()]); - result.forEachRow(($, r) -> data.numEvents[r.getInt(0)] = r.getLong(1)); + int len = w.getNumberOfBuckets(); + String[] concatedIds = new String[len]; + Arrays.fill(concatedIds, ""); + Data data = new Data(req, w.bucketSize, concatedIds, new long[len]); + result.forEachRow(($, r) -> { + data.concatedIds[r.getInt(1)] = r.getString(0); + data.numEvents[r.getInt(1)] = r.getLong(2); + }); return data; }); } @@ -156,10 +167,20 @@ private String sliceRangeSql(TimeSpan ts, int minDepth, int maxDepth) { return format(RANGE_SQL, tableName("slices"), ts.end, ts.start, minDepth, maxDepth); } + public ListenableFuture> getSlices(String ids) { + return transform(qe.query(sliceRangeForIdsSql(ids)), + res -> res.list(($, row) -> buildSlice(row, ArgSet.EMPTY))); + } + + private String sliceRangeForIdsSql(String ids) { + return format(RANGE_FOR_IDS_SQL, tableName("slices"), ids); + } + public static class Data extends Track.Data { public final Kind kind; // Summary. public final long bucketSize; + public final String[] concatedIds; public final long[] numEvents; // slices public final long[] ids; @@ -175,10 +196,11 @@ public static enum Kind { summary, } - public Data(DataRequest request, long bucketSize, long[] numEvents) { + public Data(DataRequest request, long bucketSize, String[] concatedIds, long[] numEvents) { super(request); this.kind = Kind.summary; this.bucketSize = bucketSize; + this.concatedIds = concatedIds; this.numEvents = numEvents; this.ids = null; this.starts = null; @@ -194,6 +216,7 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, int[] d super(request); this.kind = Kind.slices; this.bucketSize = 0; + this.concatedIds = null; this.numEvents = null; this.ids = ids; this.starts = starts; @@ -205,7 +228,7 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, int[] d } } - public static class Slice implements Selection { + public static class Slice implements Selection { public final long id; public final long time; public final long dur; @@ -245,8 +268,8 @@ public String getTitle() { } @Override - public boolean contains(Slice.Key key) { - return key.matches(this); + public boolean contains(Long key) { + return id == key; } @Override @@ -263,52 +286,21 @@ public Selection.Builder getBuilder() { public void getRange(Consumer span) { if (dur > 0) { span.accept(new TimeSpan(time, time + dur)); + } else { // Expand the zoom/highlight time range for signal selections whose dur is 0. + span.accept(new TimeSpan(time, time + dur).expand(SIGNAL_MARGIN_NS)); } } - public static class Key { - public final long time; - public final long dur; - - public Key(long time, long dur) { - this.time = time; - this.dur = dur; - } - - public Key(Slice slice) { - this(slice.time, slice.dur); - } - - public boolean matches(Slice slice) { - return slice.time == time && slice.dur == dur; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } else if (!(obj instanceof Key)) { - return false; - } - Key o = (Key)obj; - return time == o.time && dur == o.dur; - } - - @Override - public int hashCode() { - return Long.hashCode(time ^ dur); - } - } } - public static class Slices implements Selection { + public static class Slices implements Selection { private final List slices; private final String title; public final ImmutableList nodes; - public final ImmutableSet sliceKeys; + public final ImmutableSet sliceKeys; public Slices(List slices, String title, ImmutableList nodes, - ImmutableSet sliceKeys) { + ImmutableSet sliceKeys) { this.slices = slices; this.title = title; this.nodes = nodes; @@ -321,7 +313,7 @@ public String getTitle() { } @Override - public boolean contains(Slice.Key key) { + public boolean contains(Long key) { return sliceKeys.contains(key); } @@ -347,7 +339,7 @@ public static class SlicesBuilder implements Selection.Builder { private final List slices; private final String title; private final TreeMap roots = Maps.newTreeMap(); - private final Set sliceKeys = Sets.newHashSet(); + private final Set sliceKeys = Sets.newHashSet(); public SlicesBuilder(List slices) { this.slices = slices; @@ -355,7 +347,7 @@ public SlicesBuilder(List slices) { for (Slice slice : slices) { ti = slice.getTitle(); roots.put(slice.id, new Node(slice.name, slice.dur, slice.dur, slice.trackId)); - sliceKeys.add(new Slice.Key(slice)); + sliceKeys.add(slice.id); } this.title = ti; } @@ -369,7 +361,7 @@ public SlicesBuilder combine(SlicesBuilder other) { } @Override - public Selection build() { + public Selection build() { return new Slices(slices, title, ImmutableList.copyOf(roots.values()), ImmutableSet.copyOf(sliceKeys)); } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java index 2496e98cd8..d8aedfdb06 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/MemorySummaryTrack.java @@ -238,7 +238,7 @@ public static Data empty(DataRequest req) { } } - public static class Values implements Selection, Selection.Builder { + public static class Values implements Selection, Selection.Builder { public final long[] ts; public final long[] dur; public final long[] total; @@ -352,7 +352,7 @@ public Values combine(Values that) { } @Override - public Selection build() { + public Selection build() { return this; } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java index c77701efbb..4be6dcb0ce 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/Selection.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/Selection.java @@ -22,9 +22,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.perfetto.TimeSpan; -import com.google.gapid.perfetto.models.CounterTrack.Values; -import com.google.gapid.perfetto.models.SliceTrack.Slice; -import com.google.gapid.perfetto.models.ThreadTrack.StateSlice; import com.google.gapid.perfetto.views.MultiSelectionView; import com.google.gapid.perfetto.views.State; @@ -40,9 +37,9 @@ /** * Data about the current selection in the UI. */ -public interface Selection { +public interface Selection { public String getTitle(); - public boolean contains(Key key); + public boolean contains(Long key); public Composite buildUi(Composite parent, State state); public Selection.Builder getBuilder(); @@ -54,21 +51,20 @@ public default boolean isEmpty() { return false; } - public static final Selection EMPTY_SELECTION = new EmptySelection(); + public static final Selection EMPTY_SELECTION = new EmptySelection(); - @SuppressWarnings("unchecked") - public static Selection emptySelection() { - return (Selection)EMPTY_SELECTION; + public static Selection emptySelection() { + return EMPTY_SELECTION; } - public static class EmptySelection implements Selection, Builder> { + public static class EmptySelection implements Selection, Builder { @Override public String getTitle() { return ""; } @Override - public boolean contains(K key) { + public boolean contains(Long key) { return false; } @@ -88,12 +84,12 @@ public Selection.Builder getBuilder() { } @Override - public EmptySelection combine(EmptySelection other) { + public EmptySelection combine(EmptySelection other) { return this; } @Override - public Selection build() { + public Selection build() { return this; } } @@ -102,14 +98,14 @@ public Selection build() { * MultiSelection stores selections across different {@link Kind}s. * */ public static class MultiSelection { - private final NavigableMap, Selection> selections; + private final NavigableMap selections; - public MultiSelection(Kind type, Selection selection) { + public MultiSelection(Kind type, Selection selection) { this.selections = Maps.newTreeMap(); this.selections.put(type, selection); } - public MultiSelection(NavigableMap, Selection> selections) { + public MultiSelection(NavigableMap selections) { this.selections = selections; } @@ -121,13 +117,11 @@ public Composite buildUi(Composite parent, State state) { } } - @SuppressWarnings("unchecked") - public Selection getSelection(Kind type) { - return selections.containsKey(type) ? - (Selection) selections.get(type) : Selection.emptySelection(); + public Selection getSelection(Kind type) { + return selections.containsKey(type) ? selections.get(type) : Selection.emptySelection(); } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"rawtypes" }) public void addSelection(MultiSelection other) { for (Selection.Kind k : other.selections.keySet()) { this.addSelection(k, other.selections.get(k)); @@ -135,8 +129,8 @@ public void addSelection(MultiSelection other) { } @SuppressWarnings("unchecked") - public > void addSelection(Kind kind, Selection selection) { - Selection old = getSelection(kind); + public > void addSelection(Kind kind, Selection selection) { + Selection old = getSelection(kind); if (old == null || old == Selection.EMPTY_SELECTION) { selections.put(kind, selection); } else { @@ -154,13 +148,13 @@ public void zoom(State state) { private TimeSpan getRange() { TimeSpan[] range = new TimeSpan[] { TimeSpan.ZERO }; - for (Selection sel : selections.values()) { + for (Selection sel : selections.values()) { sel.getRange(r -> range[0] = range[0].expand(r)); } return range[0]; } - private Selection firstSelection() { + private Selection firstSelection() { return selections.firstEntry().getValue(); } } @@ -169,21 +163,21 @@ private Selection firstSelection() { * Selection builder for combining selections across different {@link Kind}s. * */ public static class CombiningBuilder { - private final Map, ListenableFuture>> selections = + private final Map>> selections = Maps.newTreeMap(); @SuppressWarnings("unchecked") public > void add( - Kind type, ListenableFuture> selection) { + Kind type, ListenableFuture> selection) { selections.merge(type, selection, (f1, f2) -> transformAsync(f1, r1 -> transform(f2, r2 -> (((T)r1).combine((T)r2))))); } public ListenableFuture build() { return transform(Futures.allAsList(selections.values()), sels -> { - Iterator> keys = selections.keySet().iterator(); + Iterator keys = selections.keySet().iterator(); Iterator> vals = sels.iterator(); - TreeMap, Selection> res = Maps.newTreeMap(); + TreeMap res = Maps.newTreeMap(); while (keys.hasNext()) { res.put(keys.next(), vals.next().build()); } @@ -197,20 +191,20 @@ public ListenableFuture build() { * */ public static interface Builder> { public T combine(T other); - public Selection build(); + public Selection build(); } @SuppressWarnings("unused") - public static class Kind implements Comparable>{ - public static final Kind Thread = new Kind(0); - public static final Kind ThreadState = new Kind(1); - public static final Kind Cpu = new Kind(2); - public static final Kind Gpu = new Kind(3); - public static final Kind VulkanEvent = new Kind(4); - public static final Kind Counter = new Kind(5); - public static final Kind FrameEvents = new Kind(6); - public static final Kind Memory = new Kind(7); - public static final Kind Battery = new Kind(8); + public static class Kind implements Comparable{ + public static final Kind Thread = new Kind(0); + public static final Kind ThreadState = new Kind(1); + public static final Kind Cpu = new Kind(2); + public static final Kind Gpu = new Kind(3); + public static final Kind VulkanEvent = new Kind(4); + public static final Kind Counter = new Kind(5); + public static final Kind FrameEvents = new Kind(6); + public static final Kind Memory = new Kind(7); + public static final Kind Battery = new Kind(8); public int priority; @@ -219,7 +213,7 @@ public Kind(int priority) { } @Override - public int compareTo(Kind other) { + public int compareTo(Kind other) { return this.priority - other.priority; } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java index 29c423da01..056eb43b89 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java @@ -70,13 +70,13 @@ public static SliceTrack forGpuQueue(QueryEngine qe, GpuInfo.Queue queue) { private final String GPU_COLUMNS = "render_target, render_target_name, render_pass, render_pass_name, command_buffer, command_buffer_name, submission_id"; private final String GPU_SLICES_QUANT_SQL = "select min(start_ts), max(end_ts), depth, label, max(cnt), " + - " first_value(submission_id) over (partition by depth, label, i) from (" + + " group_concat(id) id, first_value(submission_id) over (partition by depth, label, i) from (" + " select quantum_ts, start_ts, end_ts, depth, label, count(1) cnt, " + " quantum_ts-row_number() over (partition by depth, label order by quantum_ts) i, " + - " submission_id from (" + + " group_concat(id) id, submission_id from (" + " select quantum_ts, min(ts) over win1 start_ts, max(ts + dur) over win1 end_ts, depth, " + " substr(group_concat(name) over win1, 0, 101) label, " + - " first_value(submission_id) over win1 submission_id" + + " id, first_value(submission_id) over win1 submission_id " + " from %s" + " window win1 as (partition by quantum_ts, depth order by dur desc" + " range between unbounded preceding and unbounded following))" + @@ -95,7 +95,8 @@ protected String slicesQuantSql() { @Override protected void appendForQuant(Data data, QueryEngine.Result res) { - data.putExtraLongs("submissionIds", res.stream().mapToLong(r -> r.getLong(5)).toArray()); + super.appendForQuant(data, res); + data.putExtraLongs("submissionIds", res.stream().mapToLong(r -> r.getLong(6)).toArray()); } @Override @@ -143,6 +144,7 @@ protected Slice buildSlice(Row row, ArgSet args) { } public abstract ListenableFuture getSlice(long id); + public abstract ListenableFuture> getSlices(String concatedId); public abstract ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth); public static class Data extends Track.Data { @@ -154,6 +156,7 @@ public static class Data extends Track.Data { public final String[] categories; public final ArgSet[] args; public Map extraLongs = Maps.newHashMap(); + public Map extraStrings = Maps.newHashMap(); public Data(DataRequest request) { super(request); @@ -178,16 +181,25 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, int[] d this.args = args; } - public void putExtraLongs(String s, long[] longs) { - extraLongs.put(s, longs); + public void putExtraLongs(String name, long[] longs) { + extraLongs.put(name, longs); } - public long[] getExtraLongs(String s) { - return extraLongs.getOrDefault(s, new long[0]); + public long[] getExtraLongs(String name) { + return extraLongs.getOrDefault(name, new long[0]); + } + + public void putExtraStrings(String name, String[] strings) { + extraStrings.put(name, strings); + } + + public String[] getExtraStrings(String name) { + return extraStrings.getOrDefault(name, new String[0]); } } - public static abstract class Slice implements Selection { + public static abstract class Slice implements Selection { + public final long id; public final long time; public final long dur; public final String category; @@ -197,8 +209,9 @@ public static abstract class Slice implements Selection { public final long parentId; public final ArgSet args; - public Slice(long time, long dur, String category, String name, int depth, long stackId, + public Slice(long id, long time, long dur, String category, String name, int depth, long stackId, long parentId, ArgSet args) { + this.id = id; this.time = time; this.dur = dur; this.category = category; @@ -210,7 +223,8 @@ public Slice(long time, long dur, String category, String name, int depth, long } public Slice(QueryEngine.Row row, ArgSet args) { - this(row.getLong(1), row.getLong(2), row.getString(3), row.getString(4), row.getInt(5), + this(row.getLong(0), row.getLong(1), row.getLong(2), + row.getString(3), row.getString(4), row.getInt(5), row.getLong(6), row.getLong(7), args); } @@ -223,8 +237,8 @@ public RenderStageInfo getRenderStageInfo() { } @Override - public boolean contains(Slice.Key key) { - return key.matches(this); + public boolean contains(Long key) { + return key == id; } @Override @@ -244,42 +258,6 @@ public void getRange(Consumer span) { } } - public static class Key { - public final long time; - public final long dur; - public final int depth; - - public Key(long time, long dur, int depth) { - this.time = time; - this.dur = dur; - this.depth = depth; - } - - public Key(Slice slice) { - this(slice.time, slice.dur, slice.depth); - } - - public boolean matches(Slice slice) { - return slice.time == time && slice.dur == dur && slice.depth == depth; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } else if (!(obj instanceof Key)) { - return false; - } - Key o = (Key)obj; - return time == o.time && dur == o.dur && depth == o.depth; - } - - @Override - public int hashCode() { - return Long.hashCode(time ^ dur) ^ Integer.hashCode(depth); - } - } - public static class ThreadSlice extends Slice { public final ThreadInfo thread; @@ -341,14 +319,14 @@ public RenderStageInfo(long frameBufferHandle, String frameBufferName, long rend } } - public static class Slices implements Selection { + public static class Slices implements Selection { private final List slices; private final String title; public final ImmutableList nodes; - public final ImmutableSet sliceKeys; + public final ImmutableSet sliceKeys; public Slices(List slices, String title, ImmutableList nodes, - ImmutableSet sliceKeys) { + ImmutableSet sliceKeys) { this.slices = slices; this.title = title; this.nodes = nodes; @@ -361,7 +339,7 @@ public String getTitle() { } @Override - public boolean contains(Slice.Key key) { + public boolean contains(Long key) { return sliceKeys.contains(key); } @@ -389,7 +367,7 @@ public static class SlicesBuilder implements Selection.Builder { private final Map byStack = Maps.newHashMap(); private final Map> byParent = Maps.newHashMap(); private final Set roots = Sets.newHashSet(); - private final Set sliceKeys = Sets.newHashSet(); + private final Set sliceKeys = Sets.newHashSet(); public SlicesBuilder(List slices) { this.slices = slices; @@ -404,7 +382,7 @@ public SlicesBuilder(List slices) { } roots.remove(slice.stackId); child.add(slice.dur); - sliceKeys.add(new Slice.Key(slice)); + sliceKeys.add(slice.id); } this.title = ti; } @@ -427,7 +405,7 @@ public SlicesBuilder combine(SlicesBuilder other) { } @Override - public Selection build() { + public Selection build() { return new Slices(slices, title, roots.stream() .filter(not(byStack::containsKey)) .flatMap(root -> byParent.get(root).stream()) @@ -500,7 +478,7 @@ public Node build(Map> byParent) { } } - private abstract static class WithQueryEngine extends SliceTrack { + public abstract static class WithQueryEngine extends SliceTrack { protected static final String BASE_COLUMNS = "id, ts, dur, category, name, depth, stack_id, parent_stack_id, arg_set_id"; protected final String table; @@ -512,11 +490,12 @@ private abstract static class WithQueryEngine extends SliceTrack { "select " + baseColumns() + " from %s " + "where ts >= %d - dur and ts <= %d order by ts"; private static final String SLICES_QUANT_SQL = - "select min(start_ts), max(end_ts), depth, label, max(cnt) from (" + + "select min(start_ts), max(end_ts), depth, label, max(cnt), group_concat(id) id from (" + " select quantum_ts, start_ts, end_ts, depth, label, count(1) cnt, " + - " quantum_ts-row_number() over (partition by depth, label order by quantum_ts) i from (" + + " quantum_ts-row_number() over (partition by depth, label order by quantum_ts) i, " + + " group_concat(id) id from (" + " select quantum_ts, min(ts) over win1 start_ts, max(ts + dur) over win1 end_ts, depth, " + - " substr(group_concat(name) over win1, 0, 101) label" + + " substr(group_concat(name) over win1, 0, 101) label, id" + " from %s" + " window win1 as (partition by quantum_ts, depth order by dur desc" + " range between unbounded preceding and unbounded following))" + @@ -528,13 +507,17 @@ private abstract static class WithQueryEngine extends SliceTrack { private final String SLICE_RANGE_SQL = "select " + baseColumns() + " from %s " + "where ts < %d and ts + dur >= %d and depth >= %d and depth <= %d"; + private final String SLICES_BY_ID_SQL = + "select " + baseColumns() + " from %s where id in (%s)"; private final QueryEngine qe; protected String baseColumns() { return BASE_COLUMNS; } - protected void appendForQuant(Data data, QueryEngine.Result res) { /* Do nothing by default. */} + protected void appendForQuant(Data data, QueryEngine.Result res) { + data.putExtraStrings("concatedIds", res.stream().map(r -> r.getString(5)).toArray(String[]::new)); + } protected WithQueryEngine(QueryEngine qe, String table, long trackId) { super(trackId); @@ -630,6 +613,16 @@ private String sliceSql(long id) { return format(SLICE_SQL, tableName("slices"), id); } + @Override + public ListenableFuture> getSlices(String concatedId) { + return transform(qe.query(slicesByIdSql(concatedId)), + res -> res.list(($, row) -> buildSlice(row))); + } + + private String slicesByIdSql(String concatedId) { + return format(SLICES_BY_ID_SQL, tableName("slices"), concatedId); + } + @Override public ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth) { return transform(qe.query(sliceRangeSql(ts, minDepth, maxDepth)), diff --git a/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java index 3d0137841d..c28fc1d3f8 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java @@ -64,17 +64,20 @@ public class ThreadTrack extends Track.WithQueryEngine { "select ts, lead(ts, 1, (select end_ts from trace_bounds)) over (order by ts) - ts dur " + "from wakeup"; private static final String STATE_SPAN_VIEW = - "select ts, dur, case " + + "select ts, dur, case when end_state is null then false else true end is_sched, case " + " when end_state is not null then 'r'" + " when lag(end_state) over ts_win is not null then lag(end_state) over ts_win" + " else 'R'" + - "end as state, id " + + "end as state, case " + + " when id is not null then id " + // Sched id, for slices of 'Running'. + " else rank() over ts_win + (select max(id) from %s)" + // Assigned unique id, for other state slices like 'Waking', 'Runnable', etc. + "end as id " + "from %s window ts_win as (order by ts)"; private static final String SCHED_SQL = - "select ts, dur, state, id from %s where state != 'S' and state != 'x'"; + "select ts, dur, is_sched, state, id from %s where state != 'S' and state != 'x'"; private static final String SCHED_RANGE_SQL = - "select ts, dur, state from %s where ts < %d and ts + dur >= %d"; + "select ts, dur, is_sched, state, id from %s where ts < %d and ts + dur >= %d"; private final ThreadInfo thread; @@ -109,7 +112,7 @@ protected ListenableFuture initialize() { createView(sched, format(SCHED_VIEW, thread.utid)), createView(wakeup, format(INSTANT_VIEW, thread.utid, sched)), createSpanLeftJoin(spanJoin, wakeup + ", " + sched), - createView(spanView, format(STATE_SPAN_VIEW, spanJoin)), + createView(spanView, format(STATE_SPAN_VIEW, spanJoin, spanJoin)), createSpan(span, window + ", " + spanView))); } @@ -124,14 +127,15 @@ protected ListenableFuture computeData(DataRequest req) { private ListenableFuture computeSched(DataRequest req, SliceTrack.Data slices) { return transform(qe.query(schedSql()), res -> { int rows = res.getNumRows(); - Data data = new Data(req, new long[rows], new long[rows], new long[rows], + Data data = new Data(req, new boolean[rows], new long[rows], new long[rows], new long[rows], new ThreadState[rows], slices); res.forEachRow((i, row) -> { long start = row.getLong(0); data.schedStarts[i] = start; data.schedEnds[i] = start + row.getLong(1); - data.schedStates[i] = ThreadState.of(row.getString(2)); - data.schedIds[i] = row.getLong(3); + data.isSched[i] = row.getInt(2) != 0; + data.schedStates[i] = ThreadState.of(row.getString(3)); + data.ids[i] = row.getLong(4); }); return data; }); @@ -149,6 +153,10 @@ public ListenableFuture getCpuSlice(long id) { return CpuTrack.getSlice(qe, id); } + public ListenableFuture> getSlices(String concatedId) { + return sliceTrack.getSlices(concatedId); + } + public ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth) { return sliceTrack.getSlices(ts, minDepth, maxDepth); } @@ -171,17 +179,19 @@ private String stateRangeSql(TimeSpan ts) { public static class Data extends Track.Data { // sched - public final long[] schedIds; + public final boolean[] isSched; + public final long[] ids; // Sched id for sched slice, generated unique id for other state slice. public final long[] schedStarts; public final long[] schedEnds; public final ThreadState[] schedStates; // slices public final SliceTrack.Data slices; - public Data(DataRequest request, long[] schedIds, long[] schedStarts, long[] schedEnds, + public Data(DataRequest request, boolean[] isSched, long[] ids, long[] schedStarts, long[] schedEnds, ThreadState[] schedStates, SliceTrack.Data slices) { super(request); - this.schedIds = schedIds; + this.isSched = isSched; + this.ids = ids; this.schedStarts = schedStarts; this.schedEnds = schedEnds; this.schedStates = schedStates; @@ -189,24 +199,30 @@ public Data(DataRequest request, long[] schedIds, long[] schedStarts, long[] sch } } - public static class StateSlice implements Selection { + public static class StateSlice implements Selection { public final long time; public final long dur; public final long utid; + public final boolean isSched; public final ThreadState state; + public final long id; - public StateSlice(long time, long dur, long utid, ThreadState state) { + public StateSlice(long time, long dur, long utid, boolean isSched, ThreadState state, long id) { this.time = time; this.dur = dur; this.utid = utid; + this.isSched = isSched; this.state = state; + this.id = id; } public StateSlice(QueryEngine.Row row, long utid) { this.time = row.getLong(0); this.dur = row.getLong(1); this.utid = utid; - this.state = ThreadState.of(row.getString(2)); + this.isSched = row.getInt(2) != 0; + this.state = ThreadState.of(row.getString(3)); + this.id = row.getLong(4); } @Override @@ -215,8 +231,8 @@ public String getTitle() { } @Override - public boolean contains(StateSlice.Key key) { - return key.matches(this); + public boolean contains(Long key) { + return key == id; } @Override @@ -235,51 +251,15 @@ public void getRange(Consumer span) { span.accept(new TimeSpan(time, time + dur)); } } - - public static class Key { - public final long time; - public final long dur; - public final long utid; - - public Key(long time, long dur, long utid) { - this.time = time; - this.dur = dur; - this.utid = utid; - } - - public Key(StateSlice slice) { - this(slice.time, slice.dur, slice.utid); - } - - public boolean matches(StateSlice slice) { - return slice.time == time && slice.dur == dur && slice.utid == utid; - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } else if (!(obj instanceof Key)) { - return false; - } - Key o = (Key)obj; - return time == o.time && dur == o.dur && utid == o.utid; - } - - @Override - public int hashCode() { - return Long.hashCode(time ^ dur ^ utid); - } - } } - public static class StateSlices implements Selection { + public static class StateSlices implements Selection { private final List slices; public final ImmutableList entries; - public final ImmutableSet sliceKeys; + public final ImmutableSet sliceKeys; public StateSlices(List slices, ImmutableList entries, - ImmutableSet sliceKeys) { + ImmutableSet sliceKeys) { this.slices = slices; this.entries = entries; this.sliceKeys = sliceKeys; @@ -291,7 +271,7 @@ public String getTitle() { } @Override - public boolean contains(StateSlice.Key key) { + public boolean contains(Long key) { return sliceKeys.contains(key); } @@ -326,13 +306,13 @@ public Entry(ThreadState state, long totalDur) { public static class StateSlicesBuilder implements Selection.Builder { private final List slices; private final Map byState = Maps.newHashMap(); - private final Set sliceKeys = Sets.newHashSet(); + private final Set sliceKeys = Sets.newHashSet(); public StateSlicesBuilder(List slices) { this.slices = slices; for (StateSlice slice : slices) { byState.compute(slice.state, (state, old) -> (old == null) ? slice.dur : old + slice.dur); - sliceKeys.add(new StateSlice.Key(slice)); + sliceKeys.add(slice.id); } } @@ -347,7 +327,7 @@ public StateSlicesBuilder combine(StateSlicesBuilder other) { } @Override - public Selection build() { + public Selection build() { return new StateSlices(slices, byState.entrySet().stream() .map(e -> new StateSlices.Entry(e.getKey(), e.getValue())) .sorted((e1, e2) -> Long.compare(e2.totalDur, e1.totalDur)) @@ -373,6 +353,10 @@ public default ListenableFuture getSlice(long id) { throw new UnsupportedOperationException(); } + public default ListenableFuture> getSlices(String concatedId) { + return Futures.immediateFuture(Collections.emptyList()); + } + @SuppressWarnings("unused") public default ListenableFuture> getSlices( TimeSpan ts, int minDepth, int maxDepth) { @@ -401,6 +385,11 @@ public ListenableFuture getSlice(long id) { return track.getSlice(id); } + @Override + public ListenableFuture> getSlices(String concatedId) { + return track.getSlices(concatedId); + } + @Override public ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth) { return track.getSlices(ts, minDepth, maxDepth); diff --git a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java index 2e1e280c0e..bb7857e76b 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java @@ -162,7 +162,7 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, String[ } } - public static class Slice implements Selection { + public static class Slice implements Selection { public final long id; public final long time; public final long dur; @@ -217,7 +217,7 @@ public void getRange(Consumer span) { } } - public static class Slices implements Selection { + public static class Slices implements Selection { public final List slices; public final ImmutableSet sliceKeys; private final Set submissionIds; @@ -279,7 +279,7 @@ public SlicesBuilder combine(SlicesBuilder other) { } @Override - public Selection build() { + public Selection build() { return new Slices(slices, ImmutableSet.copyOf(sliceKeys)); } } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java index dbc58c7f69..c61a31a094 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/BatterySummaryPanel.java @@ -35,6 +35,8 @@ import com.google.gapid.perfetto.models.Selection.Kind; import java.util.List; import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.widgets.Display; public class BatterySummaryPanel extends TrackPanel implements Selectable { private static final double HEIGHT = 50; @@ -78,7 +80,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou } double maxAbs = track.getMaxAbsCurrent(); - Selection selected = state.getSelection(Selection.Kind.Battery); + Selection selected = state.getSelection(Selection.Kind.Battery); List visibleSelected = Lists.newArrayList(); // Draw outgoing battery current above the x axis. @@ -192,6 +194,11 @@ public void stop() { hovered = null; } + @Override + public Cursor getCursor(Display display) { + return display.getSystemCursor(SWT.CURSOR_HAND); + } + @Override public boolean click() { if ((mods & SWT.MOD1) == SWT.MOD1) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java index b20c22bfb3..c2140f0aef 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/CounterPanel.java @@ -35,6 +35,8 @@ import org.eclipse.swt.SWT; import java.util.List; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.widgets.Display; public class CounterPanel extends TrackPanel implements Selectable { private static final double HOVER_MARGIN = 10; @@ -93,7 +95,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou CounterInfo counter = track.getCounter(); double min = counter.range.min, range = counter.range.range(); - Selection selected = state.getSelection(Selection.Kind.Counter); + Selection selected = state.getSelection(Selection.Kind.Counter); List visibleSelected = Lists.newArrayList(); mainGradient().applyBaseAndBorder(ctx); ctx.path(path -> { @@ -198,6 +200,11 @@ public void stop() { hovered = null; } + @Override + public Cursor getCursor(Display display) { + return display.getSystemCursor(SWT.CURSOR_HAND); + } + @Override public boolean click() { if ((mods & SWT.MOD1) == SWT.MOD1) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java index 949954c4cc..a4c5d32d8b 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/CpuPanel.java @@ -34,6 +34,7 @@ import com.google.gapid.perfetto.models.Selection.CombiningBuilder; import com.google.gapid.perfetto.models.ThreadInfo; +import com.google.gapid.util.Arrays; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.RGBA; @@ -97,7 +98,7 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double private void renderSummary(RenderContext ctx, CpuTrack.Data data, double w, double h) { long tStart = data.request.range.start; int start = Math.max(0, (int)((state.getVisibleTime().start - tStart) / data.bucketSize)); - Selection selected = state.getSelection(Selection.Kind.Cpu); + Selection selected = state.getSelection(Selection.Kind.Cpu); List visibleSelected = Lists.newArrayList(); gradient(track.getCpu().id).applyBase(ctx); @@ -110,8 +111,8 @@ private void renderSummary(RenderContext ctx, CpuTrack.Data data, double w, doub path.lineTo(x, y); path.lineTo(x, nextY); y = nextY; - for (String id : data.concatedIds[i].split(",")) { - if (!id.isEmpty() && selected.contains(Long.parseLong(id))) { + for (String id : Arrays.getOrDefault(data.concatedIds, i, "").split(",")) { + if (!id.isEmpty() && !selected.isEmpty() && selected.contains(Long.parseLong(id))) { visibleSelected.add(i); break; } @@ -148,7 +149,7 @@ private void renderSummary(RenderContext ctx, CpuTrack.Data data, double w, doub private void renderSlices(RenderContext ctx, CpuTrack.Data data, double h) { TimeSpan visible = state.getVisibleTime(); - Selection selected = state.getSelection(Selection.Kind.Cpu); + Selection selected = state.getSelection(Selection.Kind.Cpu); List visibleSelected = Lists.newArrayList(); for (int i = 0; i < data.starts.length; i++) { long tStart = data.starts[i]; @@ -284,7 +285,7 @@ private Hover summaryHover(CpuTrack.Data data, Fonts.TextMeasurer m, double x, i data.request.range.start + hovered.bucket * data.bucketSize + data.bucketSize / 2); double dx = HOVER_PADDING + hovered.size.w + HOVER_PADDING; double dy = height; - String ids = data.concatedIds[bucket]; + String ids = Arrays.getOrDefault(data.concatedIds, bucket, ""); return new Hover() { @Override @@ -297,6 +298,11 @@ public void stop() { hovered = null; } + @Override + public Cursor getCursor(Display display) { + return ids.isEmpty() ? null : display.getSystemCursor(SWT.CURSOR_HAND); + } + @Override public boolean click() { if (ids.isEmpty()) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java index e7ba88e63c..16bfc6ea1a 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java @@ -19,6 +19,7 @@ import static com.google.gapid.perfetto.views.StyleConstants.SELECTION_THRESHOLD; import static com.google.gapid.perfetto.views.StyleConstants.TRACK_MARGIN; import static com.google.gapid.perfetto.views.StyleConstants.colors; +import static com.google.gapid.perfetto.views.StyleConstants.gradient; import static com.google.gapid.perfetto.views.StyleConstants.mainGradient; import static com.google.gapid.util.MoreFutures.transform; @@ -35,6 +36,7 @@ import com.google.gapid.perfetto.models.Selection; import com.google.gapid.perfetto.models.Selection.CombiningBuilder; +import com.google.gapid.util.Arrays; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.RGBA; @@ -74,6 +76,11 @@ public String getTitle() { return buffer.getDisplay(); } + @Override + public String getTooltip() { + return "\\b" + buffer.getDisplay(); + } + @Override public double getHeight() { return buffer.maxDepth * SLICE_HEIGHT; @@ -101,6 +108,8 @@ private void renderSummary( RenderContext ctx, FrameEventsTrack.Data data, double w, double h) { long tStart = data.request.range.start; int start = Math.max(0, (int)((state.getVisibleTime().start - tStart) / data.bucketSize)); + Selection selected = state.getSelection(Selection.Kind.FrameEvents); + List visibleSelected = Lists.newArrayList(); mainGradient().applyBaseAndBorder(ctx); ctx.path(path -> { @@ -112,6 +121,12 @@ private void renderSummary( path.lineTo(x, y); path.lineTo(x, nextY); y = nextY; + for (String id : Arrays.getOrDefault(data.concatedIds, i, "").split(",")) { + if (!id.isEmpty() && !selected.isEmpty() && selected.contains(Long.parseLong(id))) { + visibleSelected.add(i); + break; + } + } } path.lineTo(x, h); path.close(); @@ -119,6 +134,14 @@ private void renderSummary( ctx.drawPath(path); }); + // Draw Highlight line after the whole graph is rendered, so that the highlight is on the top. + ctx.setBackgroundColor(mainGradient().highlight); + for (int index : visibleSelected) { + ctx.fillRect(state.timeToPx(tStart + index * data.bucketSize), + Math.round(Math.max(0,h - (h * (data.numEvents[index])))) - 1, + state.durationToDeltaPx(data.bucketSize), 3); + } + if (hovered != null && hovered.bucket >= start) { double x = state.timeToPx(tStart + hovered.bucket * data.bucketSize + data.bucketSize / 2); if (x < w) { @@ -138,7 +161,7 @@ private void renderSummary( public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { TimeSpan visible = state.getVisibleTime(); - Selection selected = state.getSelection(Selection.Kind.FrameEvents); + Selection selected = state.getSelection(Selection.Kind.FrameEvents); List visibleSelected = Lists.newArrayList(); for (int i = 0; i < data.starts.length; i++) { @@ -159,7 +182,7 @@ public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { double y = depth * SLICE_HEIGHT; ctx.fillRect(rectStart, y, rectWidth, SLICE_HEIGHT); - if (selected.contains(new Slice.Key(tStart, tEnd - tStart))) { + if (selected.contains(data.ids[i])) { visibleSelected.add(Highlight.slice(color.border, rectStart, y, rectWidth)); } @@ -178,7 +201,7 @@ public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { double[] diamondY = { y + (SLICE_HEIGHT / 2), y, y + (SLICE_HEIGHT / 2), SLICE_HEIGHT }; ctx.fillPolygon(diamondX, diamondY, 4); - if (selected.contains(new Slice.Key(tStart, tEnd - tStart))) { + if (selected.contains(data.ids[i])) { visibleSelected.add(Highlight.diamond(color.border, diamondX, diamondY)); } @@ -223,12 +246,12 @@ protected Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int m switch (data.kind) { case slices: return sliceHover(data, m, x, y, mods); - case summary: return summaryHover(data, m, x); + case summary: return summaryHover(data, m, x, mods); default: return Hover.NONE; } } - private Hover summaryHover(FrameEventsTrack.Data data, Fonts.TextMeasurer m, double x) { + private Hover summaryHover(FrameEventsTrack.Data data, Fonts.TextMeasurer m, double x, int mods) { long time = state.pxToTime(x); int bucket = (int)((time - data.request.range.start) / data.bucketSize); if (bucket < 0 || bucket >= data.numEvents.length) { @@ -250,6 +273,8 @@ private Hover summaryHover(FrameEventsTrack.Data data, Fonts.TextMeasurer m, dou data.request.range.start + hovered.bucket * data.bucketSize + data.bucketSize / 2); double dx = HOVER_PADDING + hovered.size.w + HOVER_PADDING; double dy = height; + String ids = Arrays.getOrDefault(data.concatedIds, bucket, ""); + return new Hover() { @Override public Area getRedraw() { @@ -260,6 +285,26 @@ public Area getRedraw() { public void stop() { hovered = null; } + + @Override + public Cursor getCursor(Display display) { + return p == 0 ? null : display.getSystemCursor(SWT.CURSOR_HAND); + } + + @Override + public boolean click() { + if (ids.isEmpty()) { + return false; + } + if ((mods & SWT.MOD1) == SWT.MOD1) { + state.addSelection(Selection.Kind.FrameEvents, + transform(track.getSlices(ids), r -> new FrameEventsTrack.SlicesBuilder(r).build())); + } else { + state.setSelection(Selection.Kind.FrameEvents, + transform(track.getSlices(ids), r -> new FrameEventsTrack.SlicesBuilder(r).build())); + } + return true; + } }; } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/GpuQueuePanel.java b/gapic/src/main/com/google/gapid/perfetto/views/GpuQueuePanel.java index dabccc2f39..6ff818fcfd 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/GpuQueuePanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/GpuQueuePanel.java @@ -93,16 +93,18 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double } TimeSpan visible = state.getVisibleTime(); - Selection selected = state.getSelection(Selection.Kind.Gpu); + Selection selected = state.getSelection(Selection.Kind.Gpu); List visibleSelected = Lists.newArrayList(); Set selectedSIds = getSelectedSubmissionIdsInVulkanEventTrack(state); long[] sIds = data.getExtraLongs("submissionIds"); + String[] concatedIds = data.getExtraStrings("concatedIds"); for (int i = 0; i < data.starts.length; i++) { long tStart = data.starts[i]; long tEnd = data.ends[i]; int depth = data.depths[i]; + long id = data.ids[i]; String title = buildSliceTitle(data.titles[i], data.args[i]); if (tEnd <= visible.start || tStart >= visible.end) { @@ -123,10 +125,17 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double ctx.fillRect(rectStart, y, rectWidth, SLICE_HEIGHT); // Highlight GPU queue slice if it's selected or linked by a vulkan api event. - if (selected.contains(new Slice.Key(tStart, tEnd - tStart, depth)) || - (i < sIds.length && selectedSIds.contains(sIds[i]))) { + if (selected.contains(id) || (i < sIds.length && selectedSIds.contains(sIds[i]))) { // Unquantized track. visibleSelected.add(new Highlight(color.border, rectStart, y, rectWidth)); } + if (i < concatedIds.length) { // Quantized track. + for (String cId : concatedIds[i].split(",")) { + if (selected.contains(Long.parseLong(cId))) { + visibleSelected.add(new Highlight(color.border, rectStart, y, rectWidth)); + break; + } + } + } // Don't render text when we have less than 7px to play with. if (rectWidth < 7) { @@ -201,6 +210,8 @@ protected Hover onTrackMouseMove(Fonts.TextMeasurer m, double x, double y, int m mouseYpos = Math.max(0, Math.min(mouseYpos - (hoveredSize.h - SLICE_HEIGHT) / 2, (1 + queue.maxDepth) * SLICE_HEIGHT - hoveredSize.h)); long id = data.ids[i]; + String concatedId = i < data.getExtraStrings("concatedIds").length ? + data.getExtraStrings("concatedIds")[i] : ""; return new Hover() { @Override @@ -216,20 +227,29 @@ public void stop() { @Override public Cursor getCursor(Display display) { - return (id < 0) ? null : display.getSystemCursor(SWT.CURSOR_HAND); + return (id < 0 && concatedId.isEmpty()) ? null : display.getSystemCursor(SWT.CURSOR_HAND); } @Override public boolean click() { - if (id < 0) { - return false; - } - if ((mods & SWT.MOD1) == SWT.MOD1) { - state.addSelection(Selection.Kind.Gpu, track.getSlice(id)); - } else { - state.setSelection(Selection.Kind.Gpu, track.getSlice(id)); + if (id > 0) { // Track data with no quantization. + if ((mods & SWT.MOD1) == SWT.MOD1) { + state.addSelection(Selection.Kind.Gpu, track.getSlice(id)); + } else { + state.setSelection(Selection.Kind.Gpu, track.getSlice(id)); + } + return true; + } else if (!concatedId.isEmpty()) { // Track data with quantization. + if ((mods & SWT.MOD1) == SWT.MOD1) { + state.addSelection(Selection.Kind.Gpu, transform(track.getSlices(concatedId), + s -> new SliceTrack.SlicesBuilder(s).build())); + } else { + state.setSelection(Selection.Kind.Gpu, transform(track.getSlices(concatedId), + s -> new SliceTrack.SlicesBuilder(s).build())); + } + return true; } - return true; + return false; } }; } @@ -266,7 +286,7 @@ public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) { } private static Set getSelectedSubmissionIdsInVulkanEventTrack(State state) { - Selection selection = state.getSelection(Selection.Kind.VulkanEvent); + Selection selection = state.getSelection(Selection.Kind.VulkanEvent); Set res = Sets.newHashSet(); // On Vulkan Event Track. if (selection instanceof VulkanEventTrack.Slice) { res = Sets.newHashSet(((VulkanEventTrack.Slice)selection).submissionId); diff --git a/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java index 0a0d46159d..a239b29140 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/MemorySummaryPanel.java @@ -34,6 +34,8 @@ import com.google.gapid.perfetto.models.Selection.Kind; import java.util.List; import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.widgets.Display; /** * Displays information about the system memory usage. @@ -80,7 +82,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou return; } - Selection selected = state.getSelection(Selection.Kind.Memory); + Selection selected = state.getSelection(Selection.Kind.Memory); List visibleSelected = Lists.newArrayList(); memoryBuffersGradient().applyBase(ctx); @@ -205,6 +207,11 @@ public void stop() { hovered = null; } + @Override + public Cursor getCursor(Display display) { + return display.getSystemCursor(SWT.CURSOR_HAND); + } + @Override public boolean click() { if ((mods & SWT.MOD1) == SWT.MOD1) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/MultiSelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/MultiSelectionView.java index b459648bfd..162ac0c75d 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/MultiSelectionView.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/MultiSelectionView.java @@ -32,12 +32,12 @@ */ public class MultiSelectionView extends Composite { public MultiSelectionView( - Composite parent, Map, Selection> selections, State state) { + Composite parent, Map selections, State state) { super(parent, SWT.NONE); setLayout(new FillLayout()); TabFolder folder = createStandardTabFolder(this); - for (Selection s : selections.values()) { + for (Selection s : selections.values()) { createStandardTabItem(folder, s.getTitle(), s.buildUi(folder, state)); } } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java index 5944d14fa8..45ee94327b 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/ProcessSummaryPanel.java @@ -36,6 +36,7 @@ import com.google.gapid.perfetto.models.Selection.CombiningBuilder; import com.google.gapid.perfetto.models.ThreadInfo; +import com.google.gapid.util.Arrays; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.RGBA; @@ -113,7 +114,7 @@ private void renderSummary( // TODO: dedupe with CpuRenderer long tStart = data.request.range.start; int start = Math.max(0, (int)((state.getVisibleTime().start - tStart) / data.bucketSize)); - Selection selected = state.getSelection(Selection.Kind.Cpu); + Selection selected = state.getSelection(Selection.Kind.Cpu); List visibleSelected = Lists.newArrayList(); mainGradient().applyBaseAndBorder(ctx); @@ -126,8 +127,8 @@ private void renderSummary( path.lineTo(x, y); path.lineTo(x, nextY); y = nextY; - for (String id : data.concatedIds[i].split(",")) { - if (!id.isEmpty() && selected.contains(Long.parseLong(id))) { + for (String id : Arrays.getOrDefault(data.concatedIds, i, "").split(",")) { + if (!id.isEmpty() && !selected.isEmpty() && selected.contains(Long.parseLong(id))) { visibleSelected.add(i); break; } @@ -166,7 +167,7 @@ private void renderSummary( private void renderSlices(RenderContext ctx, ProcessSummaryTrack.Data data, double h) { // TODO: dedupe with CpuRenderer TimeSpan visible = state.getVisibleTime(); - Selection selected = state.getSelection(Selection.Kind.Cpu); + Selection selected = state.getSelection(Selection.Kind.Cpu); List visibleSelected = Lists.newArrayList(); int cpuCount = state.getCpuInfo().count(); double cpuH = (h - cpuCount + 1) / cpuCount; @@ -298,7 +299,7 @@ private Hover summaryHover(ProcessSummaryTrack.Data data, Fonts.TextMeasurer m, data.request.range.start + hovered.bucket * data.bucketSize + data.bucketSize / 2); double dx = HOVER_PADDING + hovered.size.w + HOVER_PADDING; double dy = height; - String ids = data.concatedIds[bucket]; + String ids = Arrays.getOrDefault(data.concatedIds, bucket, ""); return new Hover() { @Override @@ -311,6 +312,11 @@ public void stop() { hovered = null; } + @Override + public Cursor getCursor(Display display) { + return ids.isEmpty() ? null : display.getSystemCursor(SWT.CURSOR_HAND); + } + @Override public boolean click() { if (ids.isEmpty()) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/State.java b/gapic/src/main/com/google/gapid/perfetto/views/State.java index a349ba0859..b476aed6e0 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/State.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/State.java @@ -130,7 +130,7 @@ public Selection.MultiSelection getSelection() { return selection; } - public Selection getSelection(Selection.Kind type) { + public Selection getSelection(Selection.Kind type) { if (selection == null) { return Selection.emptySelection(); } else { @@ -213,7 +213,7 @@ public boolean resetSelections() { return hasDeselection; } - public void addSelection(Selection.Kind type, ListenableFuture> futureSel) { + public void addSelection(Selection.Kind type, ListenableFuture futureSel) { int myId = lastSelectionUpdateId.incrementAndGet(); thenOnUiThread(futureSel, newSelection -> { if (lastSelectionUpdateId.get() == myId) { @@ -222,7 +222,7 @@ public void addSelection(Selection.Kind type, ListenableFuture void addSelection(Selection.Kind type, Selection newSel) { + public void addSelection(Selection.Kind type, Selection newSel) { if (selection == null) { setSelection(type, newSel); } else { @@ -245,7 +245,7 @@ public void addSelection(ListenableFuture futureSel) { }); } - public void setSelection(Selection.Kind type, ListenableFuture> futureSel) { + public void setSelection(Selection.Kind type, ListenableFuture futureSel) { int myId = lastSelectionUpdateId.incrementAndGet(); thenOnUiThread(futureSel, newSelection -> { if (lastSelectionUpdateId.get() == myId) { @@ -254,7 +254,7 @@ public void setSelection(Selection.Kind type, ListenableFuture void setSelection(Selection.Kind type, Selection selection) { + public void setSelection(Selection.Kind type, Selection selection) { setSelection(new Selection.MultiSelection(type, selection)); } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java index 1814bff302..ff6ab4c4db 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/ThreadPanel.java @@ -109,9 +109,9 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double } TimeSpan visible = state.getVisibleTime(); - Selection selectedCpu = state.getSelection(Selection.Kind.Cpu); - Selection selectedThreadState = state.getSelection(Selection.Kind.ThreadState); - Selection selectedThread = state.getSelection(Selection.Kind.Thread); + Selection selectedCpu = state.getSelection(Selection.Kind.Cpu); + Selection selectedThreadState = state.getSelection(Selection.Kind.ThreadState); + Selection selectedThread = state.getSelection(Selection.Kind.Thread); List visibleSelected = Lists.newArrayList(); boolean merging = false; @@ -178,9 +178,8 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double } } - if (selectedCpu.contains(data.schedIds[i]) - || selectedThreadState.contains(new StateSlice.Key(data.schedStarts[i], - data.schedEnds[i] - data.schedStarts[i], track.getThread().utid))) { + if (data.isSched[i] && selectedCpu.contains(data.ids[i]) + || !data.isSched[i] && selectedThreadState.contains(data.ids[i])) { visibleSelected.add( new Highlight(data.schedStates[i].color.get().border, rectStart, 0, rectWidth)); } @@ -192,10 +191,12 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double if (expanded) { SliceTrack.Data slices = data.slices; + String[] concatedIds = slices.getExtraStrings("concatedIds"); for (int i = 0; i < slices.starts.length; i++) { long tStart = slices.starts[i]; long tEnd = slices.ends[i]; int depth = slices.depths[i]; + long id = slices.ids[i]; //String cat = data.categories[i]; String title = slices.titles[i]; if (tEnd <= visible.start || tStart >= visible.end) { @@ -209,9 +210,17 @@ public void renderTrack(RenderContext ctx, Repainter repainter, double w, double color.applyBase(ctx); ctx.fillRect(rectStart, y, rectWidth, SLICE_HEIGHT); - if (selectedThread.contains(new Slice.Key(tStart, tEnd - tStart, depth))) { + if (selectedThread.contains(id)) { // Unquantized track. visibleSelected.add(new Highlight(color.border, rectStart, y, rectWidth)); } + if (i < concatedIds.length) { // Quantized track. + for (String cId : concatedIds[i].split(",")) { + if (selectedThread.contains(Long.parseLong(cId))) { + visibleSelected.add(new Highlight(color.border, rectStart, y, rectWidth)); + break; + } + } + } // Don't render text when we have less than 7px to play with. if (rectWidth < 7) { @@ -290,12 +299,12 @@ public void stop() { @Override public boolean click() { - if (data.schedIds[index] != 0) { + if (data.isSched[index]) { if ((mods & SWT.MOD1) == SWT.MOD1) { - state.addSelection(Selection.Kind.Cpu, track.getCpuSlice(data.schedIds[index])); + state.addSelection(Selection.Kind.Cpu, track.getCpuSlice(data.ids[index])); state.addSelectedThread(state.getThreadInfo(track.getThread().utid)); } else { - state.setSelection(Selection.Kind.Cpu, track.getCpuSlice(data.schedIds[index])); + state.setSelection(Selection.Kind.Cpu, track.getCpuSlice(data.ids[index])); state.setSelectedThread(state.getThreadInfo(track.getThread().utid)); } } else { @@ -303,12 +312,12 @@ public boolean click() { state.addSelection(Selection.Kind.ThreadState, new ThreadTrack.StateSlice(data.schedStarts[index], data.schedEnds[index] - data.schedStarts[index], track.getThread().utid, - data.schedStates[index])); + data.isSched[index], data.schedStates[index], data.ids[index])); } else { state.setSelection(Selection.Kind.ThreadState, new ThreadTrack.StateSlice(data.schedStarts[index], data.schedEnds[index] - data.schedStarts[index], track.getThread().utid, - data.schedStates[index])); + data.isSched[index], data.schedStates[index], data.ids[index])); } } return true; @@ -337,6 +346,8 @@ public boolean click() { mouseYpos = Math.max(0, Math.min(mouseYpos - (hoveredSize.h - SLICE_HEIGHT) / 2, (1 + track.getThread().maxDepth) * SLICE_HEIGHT - hoveredSize.h)); long id = slices.ids[i]; + String concatedId = i < slices.getExtraStrings("concatedIds").length ? + slices.getExtraStrings("concatedIds")[i] : ""; return new Hover() { @Override @@ -352,20 +363,29 @@ public void stop() { @Override public Cursor getCursor(Display display) { - return (id < 0) ? null : display.getSystemCursor(SWT.CURSOR_HAND); + return (id < 0 && concatedId.isEmpty()) ? null : display.getSystemCursor(SWT.CURSOR_HAND); } @Override public boolean click() { - if (id < 0) { - return false; - } - if ((mods & SWT.MOD1) == SWT.MOD1) { - state.addSelection(Selection.Kind.Thread, track.getSlice(id)); - } else { - state.setSelection(Selection.Kind.Thread, track.getSlice(id)); + if (id > 0) { // Track data with no quantization. + if ((mods & SWT.MOD1) == SWT.MOD1) { + state.addSelection(Selection.Kind.Thread, track.getSlice(id)); + } else { + state.setSelection(Selection.Kind.Thread, track.getSlice(id)); + } + return true; + } else if (!concatedId.isEmpty()) { // Track data with quantization. + if ((mods & SWT.MOD1) == SWT.MOD1) { + state.addSelection(Selection.Kind.Thread, transform(track.getSlices(concatedId), + s -> new SliceTrack.SlicesBuilder(s).build())); + } else { + state.setSelection(Selection.Kind.Thread, transform(track.getSlices(concatedId), + s -> new SliceTrack.SlicesBuilder(s).build())); + } + return true; } - return true; + return false; } }; } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java index 9535eb4d2b..ede9163635 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/VulkanEventPanel.java @@ -88,7 +88,7 @@ protected void renderTrack(RenderContext ctx, Repainter repainter, double w, dou } TimeSpan visible = state.getVisibleTime(); - Selection selected = state.getSelection(Selection.Kind.VulkanEvent); + Selection selected = state.getSelection(Selection.Kind.VulkanEvent); List visibleSelected = Lists.newArrayList(); for (int i = 0; i < data.starts.length; i++) { diff --git a/gapic/src/main/com/google/gapid/util/Arrays.java b/gapic/src/main/com/google/gapid/util/Arrays.java index 2cdf98fa08..7ac8e794ff 100644 --- a/gapic/src/main/com/google/gapid/util/Arrays.java +++ b/gapic/src/main/com/google/gapid/util/Arrays.java @@ -25,4 +25,8 @@ private Arrays() { public static T last(T[] array) { return (array == null || array.length == 0) ? null : array[array.length - 1]; } + + public static T getOrDefault(T[] array, int idx, T dflt) { + return array == null || idx >= array.length ? dflt : array[idx]; + } } diff --git a/gapic/src/main/com/google/gapid/views/ProfileView.java b/gapic/src/main/com/google/gapid/views/ProfileView.java index d57a8cc427..53acf1358c 100644 --- a/gapic/src/main/com/google/gapid/views/ProfileView.java +++ b/gapic/src/main/com/google/gapid/views/ProfileView.java @@ -24,6 +24,7 @@ import static java.util.stream.Collectors.toList; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.models.Capture; @@ -54,6 +55,8 @@ import com.google.gapid.widgets.Theme; import com.google.gapid.widgets.Widgets; +import java.util.Arrays; +import java.util.Set; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; @@ -279,7 +282,22 @@ protected GpuSliceTrack(long trackId, List getSlice(long id) { - return Futures.immediateFuture(toSlice(slices.get((int)id))); + for (Service.ProfilingData.GpuSlices.Slice s : slices) { + if (s.getId() == id) { + return Futures.immediateFuture(toSlice(s)); + } + } + return Futures.immediateFuture(null); + } + + @Override + public ListenableFuture> getSlices(String concatedId) { + Set ids = Sets.newHashSet(); + Arrays.stream(concatedId.split(",")).mapToLong(Long::parseLong).forEach(ids::add); + return Scheduler.EXECUTOR.submit(() -> slices.stream() + .filter(s -> ids.contains(s.getId())) + .map(this::toSlice) + .collect(toList())); } @Override @@ -299,11 +317,11 @@ protected ListenableFuture initialize() { @Override protected ListenableFuture computeData(DataRequest req) { return Scheduler.EXECUTOR.submit(() -> { - List matched = Lists.newArrayList(); + List matched = Lists.newArrayList(); for (int i = 0; i < slices.size(); i++) { Service.ProfilingData.GpuSlices.Slice slice = slices.get(i); if (req.range.overlaps(slice.getTs(), slice.getTs() + slice.getDur())) { - matched.add(new SliceAndId(slice, i)); + matched.add(slice); } } @@ -311,12 +329,12 @@ protected ListenableFuture computeData(DataRequest req) { Data data = new Data(req, new long[n], new long[n], new long[n], new int[n], new String[n], new String[n], new ArgSet[n]); for (int i = 0; i < n; i++) { - SliceAndId s = matched.get(i); - data.ids[i] = s.id; - data.starts[i] = s.slice.getTs(); - data.ends[i] = s.slice.getTs() + s.slice.getDur(); - data.depths[i] = s.slice.getDepth(); - data.titles[i] = s.slice.getLabel(); + Service.ProfilingData.GpuSlices.Slice s = matched.get(i); + data.ids[i] = s.getId(); + data.starts[i] = s.getTs(); + data.ends[i] = s.getTs() + s.getDur(); + data.depths[i] = s.getDepth(); + data.titles[i] = s.getLabel(); data.categories[i] = ""; data.args[i] = ArgSet.EMPTY; } @@ -325,23 +343,13 @@ protected ListenableFuture computeData(DataRequest req) { } private Slice toSlice(Service.ProfilingData.GpuSlices.Slice s) { - return new Slice(s.getTs(), s.getDur(), "", s.getLabel(), s.getDepth(), -1, -1, ArgSet.EMPTY) { + return new Slice(s.getId(), s.getTs(), s.getDur(), "", s.getLabel(), s.getDepth(), -1, -1, ArgSet.EMPTY) { @Override public String getTitle() { return "GPU Render Stages"; } }; } - - private static class SliceAndId { - public final Service.ProfilingData.GpuSlices.Slice slice; - public final int id; - - public SliceAndId(Service.ProfilingData.GpuSlices.Slice slice, int id) { - this.slice = slice; - this.id = id; - } - } } } } diff --git a/gapis/service/service.proto b/gapis/service/service.proto index cc582a8bab..7602e8a0fa 100644 --- a/gapis/service/service.proto +++ b/gapis/service/service.proto @@ -1305,12 +1305,13 @@ message ProfilingData { uint64 ts = 1; uint64 dur = 2; - string label = 3; - int32 depth = 4; - repeated Extra extras = 5; + uint64 id = 3; + string label = 4; + int32 depth = 5; + repeated Extra extras = 6; - int32 trackId = 6; // references Track.id - int32 groupId = 7; // references Group.id + int32 trackId = 7; // references Track.id + int32 groupId = 8; // references Group.id } message Track { diff --git a/gapis/trace/android/adreno/profiling_data.go b/gapis/trace/android/adreno/profiling_data.go index 3e26d5de8a..f0553e0867 100644 --- a/gapis/trace/android/adreno/profiling_data.go +++ b/gapis/trace/android/adreno/profiling_data.go @@ -30,7 +30,7 @@ import ( var ( slicesQuery = "" + - "SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " + + "SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.id, s.name, depth, arg_set_id, track_id, t.name " + "FROM gpu_track t LEFT JOIN gpu_slice s " + "ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage' ORDER BY s.ts" argsQueryFmt = "" + @@ -124,11 +124,12 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur hwQueueIds := slicesColumns[4].GetLongValues() timestamps := slicesColumns[7].GetLongValues() durations := slicesColumns[8].GetLongValues() - names := slicesColumns[9].GetStringValues() - depths := slicesColumns[10].GetLongValues() - argSetIds := slicesColumns[11].GetLongValues() - trackIds := slicesColumns[12].GetLongValues() - trackNames := slicesColumns[13].GetStringValues() + ids := slicesColumns[9].GetLongValues() + names := slicesColumns[10].GetStringValues() + depths := slicesColumns[11].GetLongValues() + argSetIds := slicesColumns[12].GetLongValues() + trackIds := slicesColumns[13].GetLongValues() + trackNames := slicesColumns[14].GetStringValues() subCommandGroupMap := make(map[api.CmdSubmissionKey]int) for i, v := range submissionIds { @@ -219,6 +220,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur slices[i] = &service.ProfilingData_GpuSlices_Slice{ Ts: uint64(timestamps[i]), Dur: uint64(durations[i]), + Id: uint64(ids[i]), Label: names[i], Depth: int32(depths[i]), Extras: extras, From 9e9d74624dbb9dbc3d7eef1fa6e0db99f410a04e Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 13 Mar 2020 16:58:56 -0700 Subject: [PATCH 0155/1218] kokoro: Pin mingw-w64-crt-git version --- kokoro/windows/build.bat | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat index d225bda5d5..8e336b5920 100644 --- a/kokoro/windows/build.bat +++ b/kokoro/windows/build.bat @@ -44,11 +44,13 @@ REM Fix up the MSYS environment. wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-binutils-2.33.1-1-any.pkg.tar.xz wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-9.2.0-2-any.pkg.tar.xz wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-gcc-libs-9.2.0-2-any.pkg.tar.xz +wget -q http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-crt-git-8.0.0.5647.1fe2e62e-1-any.pkg.tar.xz c:\tools\msys64\usr\bin\bash --login -c "pacman -R --noconfirm catgets libcatgets" c:\tools\msys64\usr\bin\bash --login -c "pacman -Syu --noconfirm" -c:\tools\msys64\usr\bin\bash --login -c "pacman -Sy --noconfirm mingw-w64-x86_64-crt-git patch" +c:\tools\msys64\usr\bin\bash --login -c "pacman -Sy --noconfirm patch" c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-binutils-2.33.1-1-any.pkg.tar.xz" c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-gcc*-9.2.0-2-any.pkg.tar.xz" +c:\tools\msys64\usr\bin\bash --login -c "pacman -U --noconfirm mingw-w64-x86_64-crt-git-8.0.0.5647.1fe2e62e-1-any.pkg.tar.xz" set PATH=c:\tools\msys64\mingw64\bin;c:\tools\msys64\usr\bin;%PATH% set BAZEL_SH=C:\tools\msys64\usr\bin\bash.exe From acf6d79fdf8aa829c15805e8d09c02654c849734 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 16 Mar 2020 11:14:02 -0700 Subject: [PATCH 0156/1218] Change the key type of the ResourceMap type. Currently the key is the Resource interface (i.e. a pointer). This key is only useful if the exact same state object is used for map lookups. Since the map is put into the DB, this is not usually the case. With this change, the key is the resource handle. However, since the APIs are allowed to re-use handles, they are no longer "time-globally" unique, and so the mapping is only valid at a specific point in the trace. It is currently only used at specific points in the trace, so this is OK. --- gapis/api/gles/resources.go | 2 +- gapis/api/resource.go | 6 ++++-- gapis/api/vulkan/resources.go | 2 +- gapis/resolve/resource_data.go | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gapis/api/gles/resources.go b/gapis/api/gles/resources.go index 9e9f043c0f..ad8af8d55c 100644 --- a/gapis/api/gles/resources.go +++ b/gapis/api/gles/resources.go @@ -329,7 +329,7 @@ func (s Shaderʳ) SetResourceData( if err != nil { return err } - resourceID := resourceIDs[s] + resourceID := resourceIDs[s.ResourceHandle()] resource, err := resources.Find(s.ResourceType(ctx), resourceID) if err != nil { diff --git a/gapis/api/resource.go b/gapis/api/resource.go index 0303d2cd55..0c72bc5c2f 100644 --- a/gapis/api/resource.go +++ b/gapis/api/resource.go @@ -24,8 +24,10 @@ import ( "github.com/google/gapid/gapis/service/path" ) -// ResourceMap is a map from Resource to its id in a database. -type ResourceMap map[Resource]id.ID +// ResourceMap is a map from Resource handles to Resource IDs in the database. +// Note this map is not time-globally valid. It is only valid at a specific +// point in a trace, since handles may be re-used. +type ResourceMap map[string]id.ID // Resource represents an asset in a capture. type Resource interface { diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go index f923256cf8..47c777985f 100644 --- a/gapis/api/vulkan/resources.go +++ b/gapis/api/vulkan/resources.go @@ -853,7 +853,7 @@ func (shader ShaderModuleObjectʳ) SetResourceData( if err != nil { return err } - resourceID := resourceIDs[shader] + resourceID := resourceIDs[shader.ResourceHandle()] resource, err := resources.Find(shader.ResourceType(ctx), resourceID) if err != nil { diff --git a/gapis/resolve/resource_data.go b/gapis/resolve/resource_data.go index e155190743..870d1ed47f 100644 --- a/gapis/resolve/resource_data.go +++ b/gapis/resolve/resource_data.go @@ -88,7 +88,7 @@ func buildResources(ctx context.Context, p *path.Command, t api.ResourceType) (* state.OnResourceCreated = func(r api.Resource) { currentCmdResourceCount++ i := genResourceID(currentCmdIndex, currentCmdResourceCount) - idMap[r] = i + idMap[r.ResourceHandle()] = i resources[i] = r } From c033b572d330ebedae27d1c8ca1eaa57501bd36f Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 16 Mar 2020 13:19:11 -0700 Subject: [PATCH 0157/1218] Make the shader search actually work. It was matching against Java's default .toString() impl, yikes. --- gapic/src/main/com/google/gapid/views/ShaderView.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/ShaderView.java b/gapic/src/main/com/google/gapid/views/ShaderView.java index 97607cc87a..fc4f652291 100644 --- a/gapic/src/main/com/google/gapid/views/ShaderView.java +++ b/gapic/src/main/com/google/gapid/views/ShaderView.java @@ -419,8 +419,7 @@ private static ViewerFilter createSearchFilter(Pattern pattern) { return new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { - return !(element instanceof Data) || - pattern.matcher(((Data)element).toString()).find(); + return !(element instanceof Data) || ((Data)element).matches(pattern); } }; } @@ -547,6 +546,7 @@ private void updateSearchFilter(String text, boolean isRegex) { // Remove the previous one each time to avoid filter accumulation. if (keywordSearchFilter != null) { shaderViewer.removeFilter(keywordSearchFilter); + keywordSearchFilter = null; } if (!text.isEmpty()) { Pattern pattern = SearchBox.getPattern(text, isRegex); @@ -755,5 +755,9 @@ public long getSortId() { public String getLabel() { return info.getLabel(); } + + public boolean matches(Pattern pattern) { + return pattern.matcher(getId()).find() || pattern.matcher(getLabel()).find(); + } } } From 7b9162ad62e4ffd18fa08e57bf9b32203107cb82 Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Mon, 16 Mar 2020 15:11:36 -0700 Subject: [PATCH 0158/1218] Fix wrong combination when selecting across multiple gpu counters. (#143) - Can test out by 1. Select some gpu counters. 2. Ctrl + select some other gpu counters. 3. Look at the info box. 4. Notice the wrong columns and messy counter values. - Bug: N/A. --- .../gapid/perfetto/models/CounterTrack.java | 61 +++++++++---------- .../perfetto/views/CountersSelectionView.java | 10 ++- .../main/com/google/gapid/util/Arrays.java | 6 ++ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java index 4b4be9aebc..8dba5a6fcc 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/CounterTrack.java @@ -21,16 +21,19 @@ import static com.google.gapid.perfetto.models.QueryEngine.dropTable; import static com.google.gapid.perfetto.models.QueryEngine.dropView; import static com.google.gapid.perfetto.models.QueryEngine.expectOneRow; +import static com.google.gapid.util.Arrays.filled; import static com.google.gapid.util.MoreFutures.transform; import static com.google.gapid.util.MoreFutures.transformAsync; import static java.lang.String.format; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.perfetto.TimeSpan; import com.google.gapid.perfetto.views.CountersSelectionView; import com.google.gapid.perfetto.views.State; +import java.util.Map; import org.eclipse.swt.widgets.Composite; import java.util.Arrays; @@ -182,29 +185,26 @@ public static Data empty(DataRequest req) { public static class Values implements Selection, Selection.Builder { public final long[] ts; - public final String[] names; - public final double[][] values; - public final long[][] ids; + public final Map values = Maps.newHashMap(); // counter_name -> values. + public final Map ids = Maps.newHashMap(); // counter_name -> ids. private final Set valueKeys = Sets.newHashSet(); public Values(String name, Data data) { this.ts = data.ts; - this.names = new String[] { name }; - this.values = new double[][] { data.values }; - this.ids = new long[][] { data.ids }; + this.values.put(name, data.values); + this.ids.put(name, data.ids); initKeys(); } - private Values(long[] ts, String[] names, double[][] values, long[][] ids) { + private Values(long[] ts, Map values, Map ids) { this.ts = ts; - this.names = names; - this.values = values; - this.ids = ids; + this.values.putAll(values); + this.ids.putAll(ids); initKeys(); } private void initKeys() { - for (long[] keys : ids) { + for (long[] keys : ids.values()) { Arrays.stream(keys).forEach(valueKeys::add); } } @@ -246,40 +246,37 @@ public Values combine(Values other) { long[] newTs = combineTs(ts, other.ts); - double[][] newValues = new double[names.length + other.names.length][newTs.length]; - long[][] newIds = new long[names.length + other.names.length][newTs.length]; + Map newValues = Maps.newHashMap(); + Map newIds = Maps.newHashMap(); + for (String name : this.values.keySet()) { + newValues.put(name, new double[newTs.length]); + newIds.put(name, filled(new long[newTs.length], -1)); + } + for (String name : other.values.keySet()) { + newValues.put(name, new double[newTs.length]); + newIds.put(name, filled(new long[newTs.length], -1)); + } + for (int i = 0, me = 0, them = 0; i < newTs.length; i++) { long rTs = newTs[i], meTs = ts[me], themTs = other.ts[them]; if (rTs == meTs) { - for (int n = 0; n < names.length; n++) { - newValues[n][i] = values[n][me]; - newIds[n][i] = ids[n][me]; + for (String name : this.values.keySet()) { + newValues.get(name)[i] = values.get(name)[me]; + newIds.get(name)[i] = ids.get(name)[me]; } me = Math.min(me + 1, ts.length - 1); - } else if (i > 0) { - for (int n = 0; n < names.length; n++) { - newValues[n][i] = newValues[n][i - 1]; - newIds[n][i] = newIds[n][i - 1]; - } } if (rTs == themTs) { - for (int n = 0; n < other.names.length; n++) { - newValues[n + names.length][i] = other.values[n][them]; - newIds[n + names.length][i] = other.ids[n][them]; + for (String name : other.values.keySet()) { + newValues.get(name)[i] = other.values.get(name)[them]; + newIds.get(name)[i] = other.ids.get(name)[them]; } them = Math.min(them + 1, other.ts.length - 1); - } else if (i > 0) { - for (int n = 0; n < other.names.length; n++) { - newValues[names.length + n][i] = newValues[names.length + n][i - 1]; - newIds[names.length + n][i] = newIds[names.length + n][i - 1]; - } } } - String[] newNames = Arrays.copyOf(names, names.length + other.names.length); - System.arraycopy(other.names, 0, newNames, names.length, other.names.length); - return new Values(newTs, newNames, newValues, newIds); + return new Values(newTs, newValues, newIds); } private static long[] combineTs(long[] a, long[] b) { diff --git a/gapic/src/main/com/google/gapid/perfetto/views/CountersSelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/CountersSelectionView.java index f9b6912cc4..d64e9bcd78 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/CountersSelectionView.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/CountersSelectionView.java @@ -40,9 +40,13 @@ public CountersSelectionView(Composite parent, State state, CounterTrack.Values createTableColumn( viewer, "Time", r -> timeToString(sel.ts[(Integer)r] - state.getTraceTime().start)); - for (int i = 0; i < sel.names.length; i++) { - final int idx = i; - createTableColumn(viewer, sel.names[i], r -> String.valueOf(sel.values[idx][(Integer)r])); + for (String name : sel.values.keySet()) { + createTableColumn(viewer, name, r -> { + if (sel.ids.get(name)[(Integer)r] == -1) { + return "/"; + } + return String.valueOf(sel.values.get(name)[(Integer)r]); + }); } // Skip the last row (it represents the end of the selection range). diff --git a/gapic/src/main/com/google/gapid/util/Arrays.java b/gapic/src/main/com/google/gapid/util/Arrays.java index 7ac8e794ff..64187596ba 100644 --- a/gapic/src/main/com/google/gapid/util/Arrays.java +++ b/gapic/src/main/com/google/gapid/util/Arrays.java @@ -29,4 +29,10 @@ public static T last(T[] array) { public static T getOrDefault(T[] array, int idx, T dflt) { return array == null || idx >= array.length ? dflt : array[idx]; } + + public static long[] filled(long[] array, long val) { + // No generic pattern here because want a long[] array rather than Long[] array. + java.util.Arrays.fill(array, val); + return array; + } } From 8bd0b3a29e360280a54aeb3230ea23b937ad757f Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Mon, 16 Mar 2020 15:13:01 -0700 Subject: [PATCH 0159/1218] Fix duplicate selection when selecting the same item multiple times. (#142) - Bug: http://b/147922469. #4. --- .../gapid/perfetto/models/CpuTrack.java | 34 +++++++++----- .../perfetto/models/FrameEventsTrack.java | 10 ++-- .../gapid/perfetto/models/SliceTrack.java | 46 ++++++++++--------- .../gapid/perfetto/models/ThreadTrack.java | 18 +++++--- .../perfetto/models/VulkanEventTrack.java | 8 +++- 5 files changed, 70 insertions(+), 46 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java index a1e525dceb..a95908cea3 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/CpuTrack.java @@ -341,11 +341,15 @@ public SlicesBuilder(List slices) { @Override public SlicesBuilder combine(SlicesBuilder other) { - this.slices.addAll(other.slices); + for (Slice s : other.slices) { + if (!this.sliceKeys.contains(s.id)) { + this.slices.add(s); + this.sliceKeys.add(s.id); + } + } for (Map.Entry e : other.processes.entrySet()) { processes.merge(e.getKey(), e.getValue(), ByProcess.Builder::combine); } - sliceKeys.addAll(other.sliceKeys); return this; } @@ -363,15 +367,14 @@ public static class ByProcess { public final long dur; public final ImmutableList threads; - public ByProcess(long pid, long dur, ImmutableList threads) { + public ByProcess(long pid, ImmutableList threads) { this.pid = pid; - this.dur = dur; + this.dur = threads.stream().mapToLong(t -> t.dur).sum(); this.threads = threads; } public static class Builder { public final long pid; - public long dur = 0; public final Map threads = Maps.newHashMap(); public Builder(long pid) { @@ -379,12 +382,10 @@ public Builder(long pid) { } public void add(Slice slice) { - dur += slice.dur; threads.computeIfAbsent(slice.utid, ByThread.Builder::new).add(slice); } public Builder combine(Builder other) { - dur += other.dur; for (Map.Entry e : other.threads.entrySet()) { threads.merge(e.getKey(), e.getValue(), ByThread.Builder::combine); } @@ -392,7 +393,7 @@ public Builder combine(Builder other) { } public ByProcess build() { - return new ByProcess(pid, dur, threads.values().stream() + return new ByProcess(pid, threads.values().stream() .map(ByThread.Builder::build) .sorted((t1, t2) -> Long.compare(t2.dur, t1.dur)) .collect(toImmutableList())); @@ -415,19 +416,28 @@ public static class Builder { private final long tid; private long dur = 0; private final List slices = Lists.newArrayList(); + private final Set ids = Sets.newHashSet(); public Builder(long tid) { this.tid = tid; } public void add(Slice slice) { - dur += slice.dur; - slices.add(slice); + if (!ids.contains(slice.id)) { + dur += slice.dur; + slices.add(slice); + ids.add(slice.id); + } } public Builder combine(Builder other) { - dur += other.dur; - slices.addAll(other.slices); + for (Slice s : other.slices) { + if (!ids.contains(s.id)) { + dur += s.dur; + slices.add(s); + ids.add(s.id); + } + } return this; } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java index 562f234c2a..790b169361 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java @@ -354,9 +354,13 @@ public SlicesBuilder(List slices) { @Override public SlicesBuilder combine(SlicesBuilder other) { - this.slices.addAll(other.slices); - roots.putAll(other.roots); - sliceKeys.addAll(other.sliceKeys); + for (Slice s : other.slices) { + if (!this.sliceKeys.contains(s.id)) { + this.slices.add(s); + this.roots.put(s.id, other.roots.get(s.id)); + this.sliceKeys.add(s.id); + } + } return this; } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java index 056eb43b89..8d23262552 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/SliceTrack.java @@ -381,7 +381,7 @@ public SlicesBuilder(List slices) { roots.add(slice.parentId); } roots.remove(slice.stackId); - child.add(slice.dur); + child.add(slice.id, slice.dur); sliceKeys.add(slice.id); } this.title = ti; @@ -389,18 +389,22 @@ public SlicesBuilder(List slices) { @Override public SlicesBuilder combine(SlicesBuilder other) { - this.slices.addAll(other.slices); for (Map.Entry e : other.byStack.entrySet()) { Node.Builder mine = byStack.get(e.getKey()); if (mine == null) { byStack.put(e.getKey(), mine = new Node.Builder(e.getValue())); - byParent.computeIfAbsent(mine.parent, $ -> Lists.newArrayList()).add(mine); + byParent.computeIfAbsent(mine.parentId, $ -> Lists.newArrayList()).add(mine); } else { mine.add(e.getValue()); } } roots.addAll(other.roots); - sliceKeys.addAll(other.sliceKeys); + for (Slice s : other.slices) { + if (!this.sliceKeys.contains(s.id)) { + this.slices.add(s); + this.sliceKeys.add(s.id); + } + } return this; } @@ -432,41 +436,39 @@ public Node(String name, long dur, long self, int count, ImmutableList chi public static class Builder { public final String name; - public final long id; - public final long parent; - private long dur = 0; - private int count = 0; + public final long stackId; + public final long parentId; + private final Map durs = Maps.newHashMap(); // slice_id -> slice_dur. - public Builder(String name, long id, long parent) { + public Builder(String name, long stackId, long parentId) { this.name = name; - this.id = id; - this.parent = parent; + this.stackId = stackId; + this.parentId = parentId; } public Builder(Builder other) { this.name = other.name; - this.id = other.id; - this.parent = other.parent; - this.dur = other.dur; - this.count = other.count; + this.stackId = other.stackId; + this.parentId = other.parentId; + this.durs.putAll(other.durs); } public long getParent() { - return parent; + return parentId; } - public void add(long duration) { - dur += duration; - count++; + public void add(long sliceId, long duration) { + durs.put(sliceId, duration); } public void add(Builder other) { - dur += other.dur; - count += other.count; + durs.putAll(other.durs); } public Node build(Map> byParent) { - ImmutableList cs = byParent.getOrDefault(id, emptyList()).stream() + long dur = durs.values().stream().mapToLong(d -> d).sum(); + int count = durs.size(); + ImmutableList cs = byParent.getOrDefault(stackId, emptyList()).stream() .map(b -> b.build(byParent)) .sorted((n1, n2) -> Long.compare(n2.dur, n1.dur)) .collect(toImmutableList()); diff --git a/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java index c28fc1d3f8..ba4c724b90 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/ThreadTrack.java @@ -305,31 +305,35 @@ public Entry(ThreadState state, long totalDur) { public static class StateSlicesBuilder implements Selection.Builder { private final List slices; - private final Map byState = Maps.newHashMap(); + private final Map> byState = Maps.newHashMap(); // state -> (slice_id -> dur) private final Set sliceKeys = Sets.newHashSet(); public StateSlicesBuilder(List slices) { this.slices = slices; for (StateSlice slice : slices) { - byState.compute(slice.state, (state, old) -> (old == null) ? slice.dur : old + slice.dur); + byState.putIfAbsent(slice.state, Maps.newHashMap()); + byState.get(slice.state).put(slice.id, slice.dur); sliceKeys.add(slice.id); } } @Override public StateSlicesBuilder combine(StateSlicesBuilder other) { - this.slices.addAll(other.slices); - for (Map.Entry e : other.byState.entrySet()) { - byState.merge(e.getKey(), e.getValue(), Long::sum); + for (StateSlice s : other.slices) { + if (!this.sliceKeys.contains(s.id)) { + this.slices.add(s); + this.sliceKeys.add(s.id); + byState.putIfAbsent(s.state, Maps.newHashMap()); + byState.get(s.state).put(s.id, s.dur); + } } - sliceKeys.addAll(other.sliceKeys); return this; } @Override public Selection build() { return new StateSlices(slices, byState.entrySet().stream() - .map(e -> new StateSlices.Entry(e.getKey(), e.getValue())) + .map(e -> new StateSlices.Entry(e.getKey(), e.getValue().values().stream().mapToLong(v -> v).sum())) .sorted((e1, e2) -> Long.compare(e2.totalDur, e1.totalDur)) .collect(ImmutableList.toImmutableList()), ImmutableSet.copyOf(sliceKeys)); } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java index bb7857e76b..42216e073a 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/VulkanEventTrack.java @@ -273,8 +273,12 @@ public SlicesBuilder(List slices) { @Override public SlicesBuilder combine(SlicesBuilder other) { - this.slices.addAll(other.slices); - sliceKeys.addAll(other.sliceKeys); + for (Slice s : other.slices) { + if (!this.sliceKeys.contains(s.id)) { + this.slices.add(s); + this.sliceKeys.add(s.id); + } + } return this; } From c0db6d381e33d1d087129308e8a05db809ba26c7 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 16 Mar 2020 13:04:13 -0700 Subject: [PATCH 0160/1218] Remove the context drop down in the UI. --- .../com/google/gapid/GraphicsTraceView.java | 4 +- .../com/google/gapid/models/ApiContext.java | 316 ------------------ .../com/google/gapid/models/ApiState.java | 4 +- .../google/gapid/models/CommandStream.java | 30 +- .../main/com/google/gapid/models/Models.java | 20 +- .../main/com/google/gapid/models/Reports.java | 13 +- .../com/google/gapid/models/Timeline.java | 31 +- .../src/main/com/google/gapid/util/Paths.java | 23 +- .../com/google/gapid/views/CommandTree.java | 16 +- ...elector.java => ReplayDeviceSelector.java} | 42 +-- .../com/google/gapid/views/ReportView.java | 21 +- .../com/google/gapid/views/ShaderView.java | 29 +- .../com/google/gapid/views/TextureView.java | 15 - .../google/gapid/views/ThumbnailScrubber.java | 23 +- 14 files changed, 55 insertions(+), 532 deletions(-) delete mode 100644 gapic/src/main/com/google/gapid/models/ApiContext.java rename gapic/src/main/com/google/gapid/views/{ContextSelector.java => ReplayDeviceSelector.java} (65%) diff --git a/gapic/src/main/com/google/gapid/GraphicsTraceView.java b/gapic/src/main/com/google/gapid/GraphicsTraceView.java index a56eca6f20..1d6b03a5cb 100644 --- a/gapic/src/main/com/google/gapid/GraphicsTraceView.java +++ b/gapic/src/main/com/google/gapid/GraphicsTraceView.java @@ -28,7 +28,7 @@ import com.google.gapid.proto.service.Service.ClientAction; import com.google.gapid.proto.service.path.Path; import com.google.gapid.views.CommandTree; -import com.google.gapid.views.ContextSelector; +import com.google.gapid.views.ReplayDeviceSelector; import com.google.gapid.views.FramebufferView; import com.google.gapid.views.GeometryView; import com.google.gapid.views.LogView; @@ -81,7 +81,7 @@ public GraphicsTraceView(Composite parent, Models models, Widgets widgets) { setLayout(new GridLayout(1, false)); - new ContextSelector(this, models) + new ReplayDeviceSelector(this, models) .setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); tabs = new TabArea(this, models.analytics, widgets.theme, new Persistance() { diff --git a/gapic/src/main/com/google/gapid/models/ApiContext.java b/gapic/src/main/com/google/gapid/models/ApiContext.java deleted file mode 100644 index 40863e1eb0..0000000000 --- a/gapic/src/main/com/google/gapid/models/ApiContext.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.gapid.models; - -import static com.google.gapid.util.Paths.context; -import static java.util.Arrays.stream; -import static java.util.Comparator.comparingInt; - -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.gapid.proto.service.Service; -import com.google.gapid.proto.service.path.Path; -import com.google.gapid.server.Client; -import com.google.gapid.util.Events; -import com.google.gapid.util.MoreFutures; - -import org.eclipse.swt.widgets.Shell; - -import java.util.List; -import java.util.Objects; -import java.util.logging.Logger; - -/** - * Model containing the different API contexts of a capture. - */ -public class ApiContext - extends CaptureDependentModel.ForPath { - private static final Logger LOG = Logger.getLogger(ApiContext.class.getName()); - - private FilteringContext selectedContext = null; - - public ApiContext( - Shell shell, Analytics analytics, Client client, Capture capture, Devices devices) { - super(LOG, shell, analytics, client, Listener.class, capture, devices); - } - - @Override - protected void reset(boolean maintainState) { - super.reset(maintainState); - if (!maintainState) { - selectedContext = null; - } - } - - @Override - protected Path.Any getSource(Capture.Data capture) { - return Path.Any.newBuilder() - .setContexts(Path.Contexts.newBuilder() - .setCapture(capture.path)) - .build(); - } - - @Override - protected boolean shouldLoad(Capture.Data capture) { - return capture != null && capture.isGraphics(); - } - - @Override - protected ListenableFuture doLoad(Path.Any path, Path.Device device) { - return MoreFutures.transform(MoreFutures.transformAsync(client.get(path, device), val -> { - List> contexts = Lists.newArrayList(); - for (Path.Context ctx : val.getContexts().getListList()) { - contexts.add(MoreFutures.transform(client.get(context(ctx), device), - value -> new IdAndContext(ctx, value.getContext()))); - } - return Futures.allAsList(contexts); - }), ctxList -> new Contexts(device, unbox(ctxList))); - } - - private static FilteringContext[] unbox(List contexts) { - if (contexts.isEmpty()) { - return new FilteringContext[0]; - } else if (contexts.size() == 1) { - return new FilteringContext[] { FilteringContext.withoutFilter(contexts.get(0)) }; - } else { - FilteringContext[] result = new FilteringContext[contexts.size() + 1]; - result[0] = FilteringContext.ALL; - for (int i = 0; i < contexts.size(); i++) { - result[i + 1] = new FilteringContext(contexts.get(i)); - } - return result; - } - } - - @Override - protected void fireLoadStartEvent() { - // Do nothing. - } - - @Override - protected void fireLoadedEvent() { - if (count() == 1) { - selectedContext = getData().contexts[0]; - } else if (selectedContext != null) { - selectedContext = stream(getData().contexts) - .filter(c -> c.equals(selectedContext)) - .findFirst() - .orElseGet(this::highestPriorityContext); - } else { - selectedContext = highestPriorityContext(); - } - listeners.fire().onContextsLoaded(); - } - - private FilteringContext highestPriorityContext() { - return stream(getData().contexts) - .max(comparingInt(FilteringContext::getPriority)) - .orElse(FilteringContext.ALL); - } - - public int count() { - return isLoaded() ? getData().contexts.length : 0; - } - - public FilteringContext getSelectedContext() { - return selectedContext != null ? selectedContext : highestPriorityContext(); - } - - public void selectContext(FilteringContext context) { - if (!Objects.equals(context, selectedContext)) { - selectedContext = context; - listeners.fire().onContextSelected(context); - } - } - - public static class Contexts extends DeviceDependentModel.Data { - public final FilteringContext[] contexts; - - public Contexts(Path.Device device, FilteringContext[] contexts) { - super(device); - this.contexts = contexts; - } - } - - /** - * A {@link com.google.gapid.proto.service.Service.Context} wrapper to allow filtering of the - * command tree. - */ - public static class FilteringContext { - public static final FilteringContext ALL = new FilteringContext(null, null) { - @Override - public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { - return path - .setGroupByContext(true) - .setIncludeNoContextGroups(true); - } - - @Override - public Path.Events.Builder events(Path.Events.Builder path) { - return path; - } - - @Override - public Path.Report.Builder report(Path.Report.Builder path) { - return path; - } - - @Override - public String toString() { - return "All contexts"; - } - - @Override - public boolean equals(Object obj) { - return obj == ALL; - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean matches(Path.Context path) { - return true; - } - }; - - private final Path.ID id; - private final Service.Context context; - - public FilteringContext(IdAndContext context) { - this(context.id, context.context); - } - - protected FilteringContext(Path.ID id, Service.Context context) { - this.id = id; - this.context = context; - } - - public static FilteringContext withoutFilter(IdAndContext context) { - return new FilteringContext(context.id, context.context) { - @Override - public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { - return path - .setGroupByFrame(true) - .setGroupByDrawCall(true) - .setGroupByTransformFeedback(true) - .setGroupByUserMarkers(true) - .setGroupBySubmission(true) - .setAllowIncompleteFrame(true); - } - - @Override - public Path.Events.Builder events(Path.Events.Builder path) { - return path; - } - - @Override - public Path.Report.Builder report(Path.Report.Builder path) { - return path; - } - }; - } - - public Path.CommandTree.Builder commandTree(Path.CommandTree.Builder path) { - path.getFilterBuilder().setContext(id); - return path - .setGroupByFrame(true) - .setGroupByDrawCall(true) - .setGroupByTransformFeedback(true) - .setGroupByUserMarkers(true) - .setGroupBySubmission(true) - .setAllowIncompleteFrame(true); - } - - public int getPriority() { - return context != null ? context.getPriority() : 0; - } - - public Path.State.Builder state(Path.State.Builder path) { - if (id != null) { - path.getContextBuilder().setData(id.getData()); - } - return path; - } - - public Path.StateTree.Builder stateTree(Path.StateTree.Builder path) { - if (id != null) { - path.getStateBuilder().getContextBuilder().setData(id.getData()); - } - return path; - } - - public Path.Events.Builder events(Path.Events.Builder path) { - path.getFilterBuilder().setContext(id); - return path; - } - - public Path.Report.Builder report(Path.Report.Builder path) { - path.getFilterBuilder().setContext(id); - return path; - } - - @Override - public String toString() { - return context.getName(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else if (obj == ALL || !(obj instanceof FilteringContext)) { - return false; - } - return Objects.equals(id, ((FilteringContext)obj).id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - public boolean matches(Path.Context path) { - return Objects.equals(id, path.getID()); - } - } - - @SuppressWarnings("unused") - public static interface Listener extends Events.Listener { - /** - * Event indicating that the contexts have finished loading from the server. - */ - public default void onContextsLoaded() { /* empty */ } - - /** - * Event indicating that the currently selected context has changed. - */ - public default void onContextSelected(FilteringContext context) { /* empty */ } - } - - protected static class IdAndContext { - public final Path.ID id; - public final Service.Context context; - - public IdAndContext(Path.Context path, Service.Context context) { - this.id = path.getID(); - this.context = context; - } - } -} diff --git a/gapic/src/main/com/google/gapid/models/ApiState.java b/gapic/src/main/com/google/gapid/models/ApiState.java index 76c753d8b3..db2b0a65b4 100644 --- a/gapic/src/main/com/google/gapid/models/ApiState.java +++ b/gapic/src/main/com/google/gapid/models/ApiState.java @@ -58,14 +58,14 @@ public class ApiState private final ObjectStore selection = ObjectStore.create(); public ApiState(Shell shell, Analytics analytics, Client client, Devices devices, - Follower follower, CommandStream commands, ApiContext contexts, ConstantSets constants) { + Follower follower, CommandStream commands, ConstantSets constants) { super(LOG, shell, analytics, client, Listener.class, devices); this.constants = constants; commands.addListener(new CommandStream.Listener() { @Override public void onCommandsSelected(CommandIndex index) { - load(stateTree(index, contexts.getSelectedContext()), false); + load(stateTree(index), false); } }); follower.addListener(new Follower.Listener() { diff --git a/gapic/src/main/com/google/gapid/models/CommandStream.java b/gapic/src/main/com/google/gapid/models/CommandStream.java index ee9b24f282..c04c9537cc 100644 --- a/gapic/src/main/com/google/gapid/models/CommandStream.java +++ b/gapic/src/main/com/google/gapid/models/CommandStream.java @@ -28,7 +28,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.proto.device.Device.Instance; import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.api.API; @@ -54,24 +53,21 @@ */ public class CommandStream extends DeviceDependentModel.ForPath - implements ApiContext.Listener, Capture.Listener, Devices.Listener { + implements Capture.Listener, Devices.Listener { protected static final Logger LOG = Logger.getLogger(CommandStream.class.getName()); private final Capture capture; - private final ApiContext context; private final ConstantSets constants; private CommandIndex selection; public CommandStream(Shell shell, Analytics analytics, Client client, Capture capture, - Devices devices, ApiContext context, ConstantSets constants) { + Devices devices, ConstantSets constants) { super(LOG, shell, analytics, client, Listener.class, devices); this.capture = capture; - this.context = context; this.constants = constants; capture.addListener(this); devices.addListener(this); - context.addListener(this); } @Override @@ -84,11 +80,11 @@ public void onCaptureLoadingStart(boolean maintainState) { @Override public void onCaptureLoaded(Loadable.Message error) { - if (error == null && selection != null) { - selection = selection.withCapture(capture.getData().path); - if (isLoaded()) { - resolve(selection.getCommand(), node -> selectCommands(selection.withNode(node), true)); + if (error == null) { + if (selection != null) { + selection = selection.withCapture(capture.getData().path); } + load(Paths.commandTree(capture.getData().path), false); } } @@ -100,20 +96,6 @@ public void onReplayDeviceChanged(Instance dev) { } } - @Override - public void onContextsLoaded() { - onContextSelected(context.getSelectedContext()); - } - - @Override - public void onContextSelected(FilteringContext ctx) { - if (selection != null && selection.getNode() != null) { - // Clear the node, so the selection will be re-resolved once the context has updated. - selection = selection.withNode(null); - } - load(commandTree(capture.getData().path, ctx), false); - } - @Override protected ListenableFuture doLoad(Path.Any path, Path.Device device) { return MoreFutures.transformAsync(client.get(path, device), diff --git a/gapic/src/main/com/google/gapid/models/Models.java b/gapic/src/main/com/google/gapid/models/Models.java index 9fbd401012..f82898ae17 100644 --- a/gapic/src/main/com/google/gapid/models/Models.java +++ b/gapic/src/main/com/google/gapid/models/Models.java @@ -28,7 +28,6 @@ public class Models { public final Capture capture; public final Devices devices; public final CommandStream commands; - public final ApiContext contexts; public final Timeline timeline; public final Resources resources; public final ApiState state; @@ -43,17 +42,15 @@ public class Models { public final StatusBar status; // The "model" part of this "widget". public Models(Settings settings, Analytics analytics, Follower follower, Capture capture, - Devices devices, CommandStream commands, ApiContext contexts, Timeline timeline, - Resources resources, ApiState state, Reports reports, ImagesModel images, - ConstantSets constants, Geometries geos, Memory memory, MemoryTypes types, Perfetto perfetto, - Profile profile, StatusBar status) { + Devices devices, CommandStream commands, Timeline timeline, Resources resources, + ApiState state, Reports reports, ImagesModel images, ConstantSets constants, Geometries geos, + Memory memory, MemoryTypes types, Perfetto perfetto, Profile profile, StatusBar status) { this.settings = settings; this.analytics = analytics; this.follower = follower; this.capture = capture; this.devices = devices; this.commands = commands; - this.contexts = contexts; this.timeline = timeline; this.resources = resources; this.state = state; @@ -75,21 +72,20 @@ public static Models create( Capture capture = new Capture(shell, analytics, client, settings); Devices devices = new Devices(shell, analytics, client, capture, settings); ConstantSets constants = new ConstantSets(client, devices); - ApiContext contexts = new ApiContext(shell, analytics, client, capture, devices); - Timeline timeline = new Timeline(shell, analytics, client, capture, devices, contexts); + Timeline timeline = new Timeline(shell, analytics, client, capture, devices); CommandStream commands = new CommandStream( - shell, analytics, client, capture, devices, contexts, constants); + shell, analytics, client, capture, devices, constants); Resources resources = new Resources(shell, analytics, client, capture, devices, commands); ApiState state = new ApiState( - shell, analytics, client, devices, follower, commands, contexts, constants); - Reports reports = new Reports(shell, analytics, client, capture, devices, contexts); + shell, analytics, client, devices, follower, commands, constants); + Reports reports = new Reports(shell, analytics, client, capture, devices); ImagesModel images = new ImagesModel(client, devices, capture, settings); Geometries geometries = new Geometries(shell, analytics, client, devices, commands); Memory memory = new Memory(shell, analytics, client, devices, commands); MemoryTypes types = new MemoryTypes(client, devices, constants); Perfetto perfetto = new Perfetto(shell, analytics, client, capture, status); Profile profile = new Profile(shell, analytics, client, capture, devices); - return new Models(settings, analytics, follower, capture, devices, commands, contexts, timeline, + return new Models(settings, analytics, follower, capture, devices, commands, timeline, resources, state, reports, images, constants, geometries, memory, types, perfetto, profile, status); } diff --git a/gapic/src/main/com/google/gapid/models/Reports.java b/gapic/src/main/com/google/gapid/models/Reports.java index 7ee219b419..d5590f448a 100644 --- a/gapic/src/main/com/google/gapid/models/Reports.java +++ b/gapic/src/main/com/google/gapid/models/Reports.java @@ -16,7 +16,6 @@ package com.google.gapid.models; import com.google.common.util.concurrent.ListenableFuture; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.Service.Report; import com.google.gapid.proto.service.path.Path; @@ -36,30 +35,28 @@ public class Reports extends DeviceDependentModel.ForPath - implements ApiContext.Listener { +public class Timeline extends CaptureDependentModel.ForPath { private static final Logger LOG = Logger.getLogger(Timeline.class.getName()); - private final Capture capture; - private final ApiContext context; - - public Timeline(Shell shell, Analytics analytics, Client client, Capture capture, - Devices devices, ApiContext context) { + public Timeline( + Shell shell, Analytics analytics, Client client, Capture capture, Devices devices) { super(LOG, shell, analytics, client, Listener.class, capture, devices); - this.capture = capture; - this.context = context; - - context.addListener(this); - } - - @Override - public void onContextsLoaded() { - onContextSelected(context.getSelectedContext()); - } - - @Override - public void onContextSelected(FilteringContext ctx) { - load(getSource(capture.getData()), false); } @Override protected Path.Any getSource(Capture.Data data) { - FilteringContext ctx = context.isLoaded() ? context.getSelectedContext() : null; - return (ctx == null) ? null : events(data.path, ctx); + return Paths.events(data.path); } @Override diff --git a/gapic/src/main/com/google/gapid/util/Paths.java b/gapic/src/main/com/google/gapid/util/Paths.java index 7658951115..245f60ebf4 100644 --- a/gapic/src/main/com/google/gapid/util/Paths.java +++ b/gapic/src/main/com/google/gapid/util/Paths.java @@ -18,7 +18,6 @@ import com.google.common.collect.Lists; import com.google.common.primitives.UnsignedLongs; import com.google.gapid.image.Images; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.models.CommandStream.CommandIndex; import com.google.gapid.proto.device.Device; import com.google.gapid.proto.image.Image; @@ -89,18 +88,24 @@ public static Path.Any command(Path.Command command) { .build(); } - public static Path.Any commandTree(Path.Capture capture, FilteringContext context) { - return Path.Any.newBuilder().setCommandTree( - context.commandTree(Path.CommandTree.newBuilder()) + public static Path.Any commandTree(Path.Capture capture) { + return Path.Any.newBuilder() + .setCommandTree(Path.CommandTree.newBuilder() .setCapture(capture) + .setGroupByFrame(true) + .setGroupByDrawCall(true) + .setGroupByTransformFeedback(true) + .setGroupByUserMarkers(true) + .setGroupBySubmission(true) + .setAllowIncompleteFrame(true) .setMaxChildren(2000) .setMaxNeighbours(20)) .build(); } - public static Path.Any events(Path.Capture capture, FilteringContext context) { + public static Path.Any events(Path.Capture capture) { return Path.Any.newBuilder() - .setEvents(context.events(Path.Events.newBuilder()) + .setEvents(Path.Events.newBuilder() .setCapture(capture) .setLastInFrame(true)) .build(); @@ -135,14 +140,14 @@ public static Path.State stateAfter(Path.Command command) { .build(); } - public static Path.Any stateTree(CommandIndex command, FilteringContext context) { + public static Path.Any stateTree(CommandIndex command) { if (command == null) { return null; } return Path.Any.newBuilder() - .setStateTree(context.stateTree(Path.StateTree.newBuilder() + .setStateTree(Path.StateTree.newBuilder() .setState(stateAfter(command.getCommand())) - .setArrayGroupSize(2000))) + .setArrayGroupSize(2000)) .build(); } diff --git a/gapic/src/main/com/google/gapid/views/CommandTree.java b/gapic/src/main/com/google/gapid/views/CommandTree.java index e315418717..86858939d2 100644 --- a/gapic/src/main/com/google/gapid/views/CommandTree.java +++ b/gapic/src/main/com/google/gapid/views/CommandTree.java @@ -27,8 +27,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.models.Analytics.View; -import com.google.gapid.models.ApiContext; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.models.Capture; import com.google.gapid.models.CommandStream; import com.google.gapid.models.CommandStream.CommandIndex; @@ -80,7 +78,7 @@ * API command view displaying the commands with their hierarchy grouping in a tree. */ public class CommandTree extends Composite - implements Tab, Capture.Listener, CommandStream.Listener, ApiContext.Listener { + implements Tab, Capture.Listener, CommandStream.Listener { protected static final Logger LOG = Logger.getLogger(CommandTree.class.getName()); private final Models models; @@ -104,11 +102,9 @@ public CommandTree(Composite parent, Models models, Widgets widgets) { models.capture.addListener(this); models.commands.addListener(this); - models.contexts.addListener(this); addListener(SWT.Dispose, e -> { models.capture.removeListener(this); models.commands.removeListener(this); - models.contexts.removeListener(this); }); search.addListener(Events.Search, e -> search(e.text, (e.detail & Events.REGEX) != 0)); @@ -229,16 +225,6 @@ public void onCommandsSelected(CommandIndex index) { selectionHandler.updateSelectionFromModel(() -> getTreePath(index).get(), tree::setSelection); } - @Override - public void onContextsLoaded() { - updateTree(false); - } - - @Override - public void onContextSelected(FilteringContext context) { - updateTree(false); - } - private void updateTree(boolean assumeLoading) { if (assumeLoading || !models.commands.isLoaded()) { loading.startLoading(); diff --git a/gapic/src/main/com/google/gapid/views/ContextSelector.java b/gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java similarity index 65% rename from gapic/src/main/com/google/gapid/views/ContextSelector.java rename to gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java index fe3c4028c2..ca6217932d 100644 --- a/gapic/src/main/com/google/gapid/views/ContextSelector.java +++ b/gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java @@ -19,7 +19,6 @@ import static com.google.gapid.widgets.Widgets.createLabel; import com.google.gapid.models.Analytics.View; -import com.google.gapid.models.ApiContext; import com.google.gapid.models.Devices; import com.google.gapid.models.Models; import com.google.gapid.proto.device.Device; @@ -36,24 +35,17 @@ import org.eclipse.swt.widgets.Composite; /** - * Shows dropdowns for the replay device and API context selection. + * Shows a dropdown for the replay device selection. */ -public class ContextSelector extends Composite implements ApiContext.Listener, Devices.Listener { +public class ReplayDeviceSelector extends Composite implements Devices.Listener { private final Models models; - private final ComboViewer contextCombo; private final ComboViewer deviceCombo; - public ContextSelector(Composite parent, Models models) { + public ReplayDeviceSelector(Composite parent, Models models) { super(parent, SWT.NONE); this.models = models; - setLayout(new GridLayout(4, false)); - - createLabel(this, "Context:"); - contextCombo = createDropDownViewer(this); - contextCombo.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - contextCombo.setContentProvider(ArrayContentProvider.getInstance()); - contextCombo.setLabelProvider(new LabelProvider()); + setLayout(new GridLayout(2, false)); createLabel(this, "Replay Device:"); deviceCombo = createDropDownViewer(this); @@ -66,20 +58,11 @@ public String getText(Object element) { } }); - models.contexts.addListener(this); models.devices.addListener(this); addListener(SWT.Dispose, e -> { - models.contexts.removeListener(this); models.devices.removeListener(this); }); - contextCombo.getCombo().addListener(SWT.Selection, e -> { - models.analytics.postInteraction(View.ContextSelector, ClientAction.Select); - IStructuredSelection selection = contextCombo.getStructuredSelection(); - if (!selection.isEmpty()) { - models.contexts.selectContext((ApiContext.FilteringContext)selection.getFirstElement()); - } - }); deviceCombo.getCombo().addListener(SWT.Selection, e -> { models.analytics.postInteraction(View.ReplayDeviceSelector, ClientAction.Select); IStructuredSelection selection = deviceCombo.getStructuredSelection(); @@ -89,23 +72,6 @@ public String getText(Object element) { }); } - @Override - public void onContextsLoaded() { - if (!models.contexts.isLoaded()) { - return; - } - - contextCombo.setInput(models.contexts.getData().contexts); - contextCombo.refresh(); - - onContextSelected(models.contexts.getSelectedContext()); - } - - @Override - public void onContextSelected(ApiContext.FilteringContext context) { - contextCombo.setSelection(new StructuredSelection(context)); - } - @Override public void onReplayDevicesLoaded() { if (!models.devices.hasReplayDevice()) { diff --git a/gapic/src/main/com/google/gapid/views/ReportView.java b/gapic/src/main/com/google/gapid/views/ReportView.java index 1f9f400784..f11a81726a 100644 --- a/gapic/src/main/com/google/gapid/views/ReportView.java +++ b/gapic/src/main/com/google/gapid/views/ReportView.java @@ -25,8 +25,6 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; -import com.google.gapid.models.ApiContext; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.models.Capture; import com.google.gapid.models.CommandStream.CommandIndex; import com.google.gapid.models.Models; @@ -67,8 +65,7 @@ /** * View that shows the capture report items in a tree. */ -public class ReportView extends Composite - implements Tab, Capture.Listener, Reports.Listener, ApiContext.Listener { +public class ReportView extends Composite implements Tab, Capture.Listener, Reports.Listener { private final Models models; private final MessageProvider messages = new MessageProvider(); private final LoadablePanel loading; @@ -111,11 +108,9 @@ public ReportView(Composite parent, Models models, Widgets widgets) { models.capture.addListener(this); models.reports.addListener(this); - models.contexts.addListener(this); addListener(SWT.Dispose, e -> { models.capture.removeListener(this); models.reports.removeListener(this); - models.contexts.removeListener(this); }); viewer.getTree().addListener(SWT.MouseMove, e -> { @@ -168,16 +163,6 @@ public void reinitialize() { onReportLoaded(); } - @Override - public void onContextsLoaded() { - clear(); - } - - @Override - public void onContextSelected(FilteringContext context) { - clear(); - } - @Override public void onCaptureLoadingStart(boolean maintainState) { loading.showMessage(Info, Messages.LOADING_CAPTURE); @@ -187,6 +172,8 @@ public void onCaptureLoadingStart(boolean maintainState) { public void onCaptureLoaded(Loadable.Message error) { if (error != null) { loading.showMessage(Error, Messages.CAPTURE_LOAD_FAILURE); + } else { + clear(); } } @@ -205,6 +192,8 @@ public void onReportLoaded() { } else { loading.showMessage(Error, Messages.CAPTURE_LOAD_FAILURE); } + } else { + clear(); } } diff --git a/gapic/src/main/com/google/gapid/views/ShaderView.java b/gapic/src/main/com/google/gapid/views/ShaderView.java index fc4f652291..2ef7097229 100644 --- a/gapic/src/main/com/google/gapid/views/ShaderView.java +++ b/gapic/src/main/com/google/gapid/views/ShaderView.java @@ -88,7 +88,6 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TreeItem; @@ -309,7 +308,6 @@ private static class ShaderPanel extends Composite private final TreeViewer shaderViewer; private final Composite sourceComposite; private final Button pushButton; - private final ViewerFilter currentContextFilter; private ViewerFilter keywordSearchFilter; private SourceViewer shaderSourceViewer; private boolean lastUpdateContainedAllShaders = false; @@ -337,19 +335,12 @@ public ShaderPanel(Composite parent, Models models, Theme theme, Type type) { Settings.SplitterWeights.Programs, splitter.getWeights())); } - SearchBox searchBox = new SearchBox(treeViewerContainer, true, theme); + SearchBox searchBox = new SearchBox(treeViewerContainer, true); searchBox.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); searchBox.addListener(Events.Search, e -> updateSearchFilter(e.text, (e.detail & Events.REGEX) != 0)); - currentContextFilter = createCurrentContextFilter(models); - MenuItem contextFilterSelector = new MenuItem(searchBox.getNestedMenu(), SWT.CHECK); - contextFilterSelector.setText("Include all contexts"); - contextFilterSelector.addListener(SWT.Selection, e -> updateContextFilter(contextFilterSelector.getSelection())); - contextFilterSelector.setSelection(true); - shaderViewer = createShaderSelector(treeViewerContainer); shaderViewer.getTree().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - updateContextFilter(contextFilterSelector.getSelection()); sourceComposite = createComposite(sourcesContainer, new FillLayout(SWT.VERTICAL)); sourceComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); @@ -424,15 +415,6 @@ public boolean select(Viewer viewer, Object parentElement, Object element) { }; } - private static ViewerFilter createCurrentContextFilter(Models models) { - return new ViewerFilter() { - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - return models.contexts.getSelectedContext().matches(((Data)element).info.getContext()); - } - }; - } - private SourceViewer createSourcePanel(Composite parent, Source source) { Group group = createGroup(parent, source.label); SourceViewer viewer = @@ -555,15 +537,6 @@ private void updateSearchFilter(String text, boolean isRegex) { } } - private void updateContextFilter(boolean hasAllContext) { - if (currentContextFilter != null) { - shaderViewer.removeFilter(currentContextFilter); - } - if (!hasAllContext) { - shaderViewer.addFilter(currentContextFilter); - } - } - public static class Source { private static final Source EMPTY_PROGRAM = new Source("Program", "// No shaders attached to this program at this point in the trace."); diff --git a/gapic/src/main/com/google/gapid/views/TextureView.java b/gapic/src/main/com/google/gapid/views/TextureView.java index c3877db609..a8b0d86387 100644 --- a/gapic/src/main/com/google/gapid/views/TextureView.java +++ b/gapic/src/main/com/google/gapid/views/TextureView.java @@ -127,7 +127,6 @@ public TextureView(Composite parent, Models models, Widgets widgets) { Composite options = createComposite(tableAndOption, filling(new RowLayout(SWT.HORIZONTAL), true, false)); Button showDeleted = createCheckbox(options, "Show deleted textures", true); - Button allContexts = createCheckbox(options, "Include all contexts", true); Composite imageAndToolbar = createComposite(splitter, new GridLayout(2, false)); ToolBar toolBar = new ToolBar(imageAndToolbar, SWT.VERTICAL | SWT.FLAT); @@ -170,20 +169,6 @@ public boolean select(Viewer viewer, Object parentElement, Object element) { textureTable.addFilter(filterDeleted); } }); - - ViewerFilter filterContexts = new ViewerFilter() { - @Override - public boolean select(Viewer viewer, Object parentElement, Object element) { - return models.contexts.getSelectedContext().matches(((Data)element).info.getContext()); - } - }; - allContexts.addListener(SWT.Selection, e -> { - if (allContexts.getSelection()) { - textureTable.removeFilter(filterContexts); - } else { - textureTable.addFilter(filterContexts); - } - }); } protected void setImage(FetchedImage result) { diff --git a/gapic/src/main/com/google/gapid/views/ThumbnailScrubber.java b/gapic/src/main/com/google/gapid/views/ThumbnailScrubber.java index 7326b26431..34dbaf241d 100644 --- a/gapic/src/main/com/google/gapid/views/ThumbnailScrubber.java +++ b/gapic/src/main/com/google/gapid/views/ThumbnailScrubber.java @@ -17,13 +17,10 @@ import static com.google.gapid.image.Images.noAlpha; import static com.google.gapid.models.ImagesModel.THUMB_SIZE; -import static com.google.gapid.util.Loadable.MessageType.Error; import static com.google.gapid.util.Loadable.MessageType.Info; import static com.google.gapid.widgets.Widgets.scheduleIfNotDisposed; import com.google.common.collect.Lists; -import com.google.gapid.models.ApiContext; -import com.google.gapid.models.ApiContext.FilteringContext; import com.google.gapid.models.Capture; import com.google.gapid.models.CommandStream; import com.google.gapid.models.CommandStream.CommandIndex; @@ -56,8 +53,8 @@ /** * Scrubber view displaying thumbnails of the frames in the current capture. */ -public class ThumbnailScrubber extends Composite implements Tab, Capture.Listener, - CommandStream.Listener, ApiContext.Listener, Timeline.Listener { +public class ThumbnailScrubber extends Composite + implements Tab, Capture.Listener, CommandStream.Listener, Timeline.Listener { private final Models models; private final LoadablePanel loading; private final Carousel carousel; @@ -81,12 +78,10 @@ public ThumbnailScrubber(Composite parent, Models models, Widgets widgets) { carousel.setCursor(getDisplay().getSystemCursor(SWT.CURSOR_HAND)); models.capture.addListener(this); - models.contexts.addListener(this); models.timeline.addListener(this); models.commands.addListener(this); addListener(SWT.Dispose, e -> { models.capture.removeListener(this); - models.contexts.removeListener(this); models.timeline.removeListener(this); models.commands.removeListener(this); carousel.reset(); @@ -122,20 +117,6 @@ public void onCaptureLoaded(Loadable.Message error) { } } - @Override - public void onContextsLoaded() { - if (!models.contexts.isLoaded()) { - loading.showMessage(Error, Messages.CAPTURE_LOAD_FAILURE); - } else { - updateScrubber(); - } - } - - @Override - public void onContextSelected(FilteringContext context) { - updateScrubber(); - } - @Override public void onTimeLineLoadingStart() { updateScrubber(); From 72a1acb36647108b5e9ff827865a5f90dee80fff Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 17 Mar 2020 09:53:57 -0700 Subject: [PATCH 0161/1218] Use Perfetto Client API in tracing. (#81) Previously we used Perfetto CLI to trace, however, when tracing is started, some ftrace are not set up yet, which results in a gap of empty data at the beginning of the trace. With Perfetto Client API, we now can do deferred start by setting deferred_start field to true, and always make sure we only start the tracing session when things are ready. Bug: b/147490759 --- .../com/google/gapid/views/TracerDialog.java | 7 ++ gapis/perfetto/android/BUILD.bazel | 3 + gapis/perfetto/android/trace.go | 117 ++++++++++++++++-- 3 files changed, 117 insertions(+), 10 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index ea56cf9b3a..08b51ab979 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -1123,6 +1123,13 @@ protected Control createDialogArea(Composite parent) { ErrorDialog.showErrorDialog(getShell(), analytics, getErrorMessage(), error)); errorButton.setVisible(false); + // Make sure the stop signal is issued when the dialog is closed. + getShell().addListener(SWT.Close, e -> { + if (!successful()) { + trace.stop(); + } + }); + update(); Widgets.scheduleUntilDisposed(getShell(), STATUS_INTERVAL_MS, trace::getStatus); diff --git a/gapis/perfetto/android/BUILD.bazel b/gapis/perfetto/android/BUILD.bazel index 3bb23f874d..6a7d273788 100644 --- a/gapis/perfetto/android/BUILD.bazel +++ b/gapis/perfetto/android/BUILD.bazel @@ -24,6 +24,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//core/app:go_default_library", + "//core/app/crash:go_default_library", "//core/event/task:go_default_library", "//core/log:go_default_library", "//core/os/android:go_default_library", @@ -32,7 +33,9 @@ go_library( "//core/os/file:go_default_library", "//core/text:go_default_library", "//gapidapk:go_default_library", + "//gapis/perfetto:go_default_library", "//gapis/service:go_default_library", "//tools/build/third_party/perfetto:config_go_proto", + "@com_github_golang_protobuf//proto:go_default_library", ], ) diff --git a/gapis/perfetto/android/trace.go b/gapis/perfetto/android/trace.go index dd2e242e16..8cd0f5802a 100644 --- a/gapis/perfetto/android/trace.go +++ b/gapis/perfetto/android/trace.go @@ -15,15 +15,19 @@ package android import ( + "bytes" "context" "fmt" "io" "os" "sync/atomic" + "time" perfetto_pb "protos/perfetto/config" + "github.com/golang/protobuf/proto" "github.com/google/gapid/core/app" + "github.com/google/gapid/core/app/crash" "github.com/google/gapid/core/event/task" "github.com/google/gapid/core/log" "github.com/google/gapid/core/os/android" @@ -32,11 +36,13 @@ import ( "github.com/google/gapid/core/os/file" "github.com/google/gapid/core/text" "github.com/google/gapid/gapidapk" + "github.com/google/gapid/gapis/perfetto" "github.com/google/gapid/gapis/service" ) const ( - gpuRenderStagesDataSourceDescriptorName = "gpu.renderstages" + ftraceDataSourceName = "linux.ftrace" + gpuRenderStagesDataSourceName = "gpu.renderstages" // perfettoTraceFile is the location on the device where we'll ask Perfetto // to store the trace data while tracing. @@ -46,14 +52,15 @@ const ( // Process represents a running Perfetto capture. type Process struct { - device adb.Device - config *perfetto_pb.TraceConfig - deferred bool + device adb.Device + config *perfetto_pb.TraceConfig + deferred bool + perfettoClient *perfetto.Client } -func hasRenderStageEnabled(perfettoConfig *perfetto_pb.TraceConfig) bool { +func hasDataSourceEnabled(perfettoConfig *perfetto_pb.TraceConfig, ds string) bool { for _, dataSource := range perfettoConfig.GetDataSources() { - if dataSource.Config.GetName() == gpuRenderStagesDataSourceDescriptorName { + if dataSource.Config.GetName() == ds { return true } } @@ -138,7 +145,7 @@ func Start(ctx context.Context, d adb.Device, a *android.ActivityAction, opts *s if err != nil { return nil, cleanup.Invoke(ctx), err } - hasRenderStages = hasRenderStageEnabled(opts.PerfettoConfig) + hasRenderStages = hasDataSourceEnabled(opts.PerfettoConfig, gpuRenderStagesDataSourceName) } // Setup the profiling layers. @@ -167,15 +174,32 @@ func Start(ctx context.Context, d adb.Device, a *android.ActivityAction, opts *s } } + // With the comsumer protocol, in Android 10 it causes a stall when + // traced_pros writes into file. In this case, don't create perfetto client, + // instead fall back to CLI. + var c *perfetto.Client + if !opts.PerfettoConfig.GetWriteIntoFile() { + c, err = d.ConnectPerfetto(ctx) + if err != nil { + log.W(ctx, "Failed to connect Perfetto through client API: %v, fall back to CLI.", err) + c = nil + } + } + return &Process{ - device: d, - config: opts.PerfettoConfig, - deferred: opts.DeferStart, + device: d, + config: opts.PerfettoConfig, + deferred: opts.DeferStart, + perfettoClient: c, }, cleanup, nil } // Capture starts the perfetto capture. func (p *Process) Capture(ctx context.Context, start task.Signal, stop task.Signal, ready task.Task, w io.Writer, written *int64) (int64, error) { + if p.perfettoClient != nil { + return p.captureWithClientApi(ctx, start, stop, ready, w, written) + } + tmp, err := file.Temp() if err != nil { return 0, log.Err(ctx, err, "Failed to create a temp file") @@ -208,3 +232,76 @@ func (p *Process) Capture(ctx context.Context, start task.Signal, stop task.Sign } return io.Copy(w, fh) } + +func (p *Process) captureWithClientApi(ctx context.Context, start task.Signal, stop task.Signal, ready task.Task, w io.Writer, written *int64) (int64, error) { + defer p.perfettoClient.Close(ctx) + + p.config.DeferredStart = proto.Bool(true) + var buf bytes.Buffer + ts, err := p.perfettoClient.Trace(ctx, p.config, &buf) + if err != nil { + return 0, log.Err(ctx, err, "Failed to setup Perfetto trace") + } + + // TODO(b/150141871) Figure out a robust way to determine whether tracing is + // ready. Setting up ftrace trace points takes time, hence sometimes there's + // a gap at the beginning of the trace. In order to avoid this issue, we + // need to know when ftrace trace points are ready. This workaround checks + // the sysfs node of the ftrace event task_newtask that is always enabled + // regardless of the user selection. Skip if ftrace is not enabled. + if hasDataSourceEnabled(p.config, ftraceDataSourceName) { + sessionReadySignal, sessionReadyFunc := task.NewSignal() + timeout := false + crash.Go(func() { + cnt := 0 + for { + res, _ := p.device.Shell("cat", "/sys/kernel/debug/tracing/events/task/task_newtask/enable").Call(ctx) + if res == "1" { + sessionReadyFunc(ctx) + break + } + cnt += 1 + + // Give up after 1000 tries + if cnt == 1000 { + timeout = true + sessionReadyFunc(ctx) + break + } + time.Sleep(10 * time.Millisecond) + } + }) + + // Signal that we are ready to start. + if !sessionReadySignal.Wait(ctx) { + return 0, log.Err(ctx, nil, "Cancelled") + } + if timeout { + return 0, log.Err(ctx, nil, "Timed out in waiting for trace session ready") + } + } + atomic.StoreInt64(written, 1) + if p.deferred && !start.Wait(ctx) { + ts.Stop(ctx) + return 0, log.Err(ctx, nil, "Cancelled") + } + ts.Start(ctx) + wait := make(chan error, 1) + crash.Go(func() { + wait <- ts.Wait(ctx) + }) + select { + case err = <-wait: + case <-stop: + ts.Stop(ctx) + err = <-wait + } + + if err != nil { + return 0, log.Err(ctx, err, "Failed during tracing session") + } + + numWritten, err := io.Copy(w, &buf) + atomic.StoreInt64(written, numWritten) + return numWritten, err +} From 415445cefb050c487b8788b3239cf9772711104b Mon Sep 17 00:00:00 2001 From: Adam Bodnar Date: Tue, 17 Mar 2020 14:41:39 -0700 Subject: [PATCH 0162/1218] Update "Goto Command" to support following a .-delimited subcommand (#127) * Adjust "Goto Command" box to support specifying a .-delimited subcommand Converts the spinner widget to a textbox and generates a list of subcommand Indices. Bug: b/143735500 * Update "Goto Command" to support following a .-delimited subcommand Update CommandTreeNodeForCommand to generate a full node index for a full SubCmdIdx. Also adds sanity checks to the input logic that disables the "OK" button and presents an error message upon invalid input. Bug: b/143735500 Co-authored-by: Chris Forbes --- .../com/google/gapid/views/GotoCommand.java | 66 +++++++++++++------ gapis/api/sync/BUILD.bazel | 1 + gapis/api/sync/sync.go | 3 + gapis/api/vulkan/vulkan_terminator.go | 2 +- gapis/resolve/command_tree.go | 36 +++++----- 5 files changed, 71 insertions(+), 37 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/GotoCommand.java b/gapic/src/main/com/google/gapid/views/GotoCommand.java index 484c462616..b319e8afb8 100644 --- a/gapic/src/main/com/google/gapid/views/GotoCommand.java +++ b/gapic/src/main/com/google/gapid/views/GotoCommand.java @@ -17,7 +17,7 @@ import static com.google.gapid.widgets.Widgets.createComposite; import static com.google.gapid.widgets.Widgets.createLabel; -import static com.google.gapid.widgets.Widgets.createSpinner; +import static com.google.gapid.widgets.Widgets.createTextbox; import com.google.gapid.models.Analytics.View; import com.google.gapid.models.CommandStream; @@ -33,10 +33,14 @@ import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Spinner; +import org.eclipse.swt.widgets.Text; +import java.util.ArrayList; +import java.util.List; /** * Dialog for the goto command action. @@ -50,7 +54,7 @@ public static void showGotoCommandDialog(Shell shell, Models models) { GotoDialog dialog = new GotoDialog(shell, models.commands); if (dialog.open() == Window.OK) { models.commands.selectCommands(CommandIndex.forCommand(Path.Command.newBuilder() - .addIndices(dialog.value) + .addAllIndices(dialog.value) .setCapture(models.capture.getData().path) .build()), true); } @@ -61,8 +65,9 @@ public static void showGotoCommandDialog(Shell shell, Models models) { */ private static class GotoDialog extends MessageDialog { private final CommandStream commands; - private Spinner spinner; - public int value; + private Text text; + private Label error; + public List value; public GotoDialog(Shell shell, CommandStream commands) { super(shell, Messages.GOTO, null, Messages.GOTO_COMMAND, MessageDialog.CONFIRM, 0, @@ -76,28 +81,47 @@ protected boolean isResizable() { } @Override - protected Control createCustomArea(Composite parent) { - // Although the command ID is a long, we currently only actually support the int range, as - // the commands are stored in an array. So, using an int spinner here is fine. - //TODO limit to max commands - int max = Integer.MAX_VALUE; - CommandIndex selection = commands.getSelectedCommands(); - int current = (selection == null) ? 0 : 0 /*TODO(int)last(selection)*/; + protected void createButtonsForButtonBar(Composite parent) { + super.createButtonsForButtonBar(parent); + Button ok = getButton(IDialogConstants.OK_ID); + ok.setEnabled(false); + } + @Override + protected Control createCustomArea(Composite parent) { Composite container = createComposite(parent, new GridLayout(2, false)); container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createLabel(container, Messages.COMMAND_ID + ":"); - spinner = createSpinner(container, current, 0, max); - spinner.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + text = createTextbox(container, ""); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + error = createLabel(container, ""); + error.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + error.setForeground(parent.getDisplay().getSystemColor(SWT.COLOR_DARK_RED)); + text.addListener(SWT.Modify, evt -> { + String input = text.getText(); + Button button = getButton(IDialogConstants.OK_ID); + error.setVisible(false); + error.setText(""); + if (button != null) { + button.setEnabled(false); + if (input.length() > 0) { + try { + String[] strings = input.split("\\."); + value = new ArrayList(); + for (String s : strings) { + value.add(Long.parseLong(s)); + } + button.setEnabled(true); + } catch (NumberFormatException e) { + error.setText("Invalid index: " + e.getMessage()); + error.setVisible(true); + error.requestLayout(); + } + } + } + }); return container; } - - @Override - protected void buttonPressed(int buttonId) { - // The spinner gets disposed after this. - value = spinner.getSelection(); - super.buttonPressed(buttonId); - } } } diff --git a/gapis/api/sync/BUILD.bazel b/gapis/api/sync/BUILD.bazel index c764371ce8..a8a8c92dba 100644 --- a/gapis/api/sync/BUILD.bazel +++ b/gapis/api/sync/BUILD.bazel @@ -24,6 +24,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//core/app/status:go_default_library", + "//core/log:go_default_library", "//gapis/api:go_default_library", "//gapis/api/transform:go_default_library", "//gapis/capture:go_default_library", diff --git a/gapis/api/sync/sync.go b/gapis/api/sync/sync.go index 9c00459c2a..72d99d4a0d 100644 --- a/gapis/api/sync/sync.go +++ b/gapis/api/sync/sync.go @@ -25,6 +25,7 @@ import ( "fmt" "github.com/google/gapid/core/app/status" + "github.com/google/gapid/core/log" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/api/transform" "github.com/google/gapid/gapis/capture" @@ -109,6 +110,8 @@ func MutationCmdsFor(ctx context.Context, c *path.Capture, data *Data, cmds []ap lastCmd := cmds[len(cmds)-1] if api.CmdID(len(cmds)) > id { lastCmd = cmds[id] + } else { + return nil, log.Errf(ctx, nil, "Requested CmdID %v exceeds range of commands", id) } if sync, ok := lastCmd.API().(SynchronizedAPI); ok { diff --git a/gapis/api/vulkan/vulkan_terminator.go b/gapis/api/vulkan/vulkan_terminator.go index 5e66cc77d1..73003b5e12 100644 --- a/gapis/api/vulkan/vulkan_terminator.go +++ b/gapis/api/vulkan/vulkan_terminator.go @@ -399,7 +399,7 @@ func (t *VulkanTerminator) Transform(ctx context.Context, id api.CmdID, cmd api. // then do that instead of cutting at the derived cutIndex. // It is guaranteed to be safe as long as the requestedSubIndex is // less than the calculated one (i.e. we are cutting more) - if len(t.requestSubIndex) > 1 && t.requestSubIndex[0] == uint64(id) { + if len(t.requestSubIndex) > 1 && t.requestSubIndex[0] == uint64(id) && t.syncData.SubcommandLookup.Value(t.requestSubIndex) != nil { if len(cutIndex) == 0 || !cutIndex.LessThan(t.requestSubIndex[1:]) { cutIndex = t.requestSubIndex[1:] doCut = true diff --git a/gapis/resolve/command_tree.go b/gapis/resolve/command_tree.go index acb30ff5dd..f7f85863e4 100644 --- a/gapis/resolve/command_tree.go +++ b/gapis/resolve/command_tree.go @@ -75,19 +75,30 @@ func (t *commandTree) index(indices []uint64) (api.SpanItem, api.SubCmdIdx) { return group, subCmdRootID } -func (t *commandTree) indices(id api.CmdID) []uint64 { +func (t *commandTree) indices(idx []uint64) []uint64 { out := []uint64{} group := t.root - for { - i := group.IndexOf(id) - out = append(out, i) - switch item := group.Index(i).(type) { - case api.CmdIDGroup: - group = item - default: - return out + + for _, id := range idx { + brk := false + for { + if brk { + break + } + i := group.IndexOf(api.CmdID(id)) + out = append(out, i) + switch item := group.Index(i).(type) { + case api.CmdIDGroup: + group = item + case api.SubCmdRoot: + group = item.SubGroup + brk = true + default: + return out + } } } + return out } // CommandTreeNode resolves the specified command tree node path. @@ -165,14 +176,9 @@ func CommandTreeNodeForCommand(ctx context.Context, p *path.CommandTreeNodeForCo cmdTree := boxed.(*commandTree) - cmdIdx := p.Command.Indices[0] - if len(p.Command.Indices) > 1 { - return nil, fmt.Errorf("Subcommands currently not supported for Command Tree") // TODO: Subcommands - } - return &path.CommandTreeNode{ Tree: p.Tree, - Indices: cmdTree.indices(api.CmdID(cmdIdx)), + Indices: cmdTree.indices(p.Command.Indices), }, nil } From 082432e4d0e398d5edc2364aa05be35f08947bd8 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 17 Mar 2020 16:17:23 -0700 Subject: [PATCH 0163/1218] Bump the minor version for the next release. --- version.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.bzl b/version.bzl index 6140d6dfce..7723a5f838 100644 --- a/version.bzl +++ b/version.bzl @@ -15,7 +15,7 @@ # True source of AGI versions. # Increment these numbers immediately after releasing a new version. AGI_VERSION_MAJOR="0" -AGI_VERSION_MINOR="9" +AGI_VERSION_MINOR="10" AGI_VERSION_POINT="0" # See bazel.rc. Can be overriden on the command line with: From 6fcd90615f434121bfa096900c20196b53f6ce45 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 10 Mar 2020 17:15:44 -0700 Subject: [PATCH 0164/1218] GLES and GVR are dead Long live Vulkan --- cmd/enum_lookup/BUILD.bazel | 18 - cmd/gapis/BUILD.bazel | 1 - cmd/gapis/main.go | 3 - cmd/linearize_trace/BUILD.bazel | 2 - cmd/linearize_trace/main.go | 2 - cmd/verify_gles_api/BUILD.bazel | 37 - cmd/verify_gles_api/main.go | 275 - cmd/verify_gles_api/registry.go | 352 -- gapidapk/android/apk/BUILD.bazel | 1 - gapii/apk/BUILD.bazel | 9 - gapii/cc/BUILD.bazel | 71 +- gapii/cc/android/gles_layer.cpp | 57 - gapii/cc/android/gvr_install.h | 31 - gapii/cc/android/installer.cpp | 224 - gapii/cc/android/installer.h | 38 - gapii/cc/gapii_android.exports | 2 - gapii/cc/gles_context.cpp | 448 -- gapii/cc/gles_exports.h | 30 - gapii/cc/gles_extras.cpp | 709 --- gapii/cc/gles_extras.inc | 31 - gapii/cc/gles_inlines.inc | 18 - gapii/cc/gles_mid_execution.cpp | 1203 ---- gapii/cc/gles_spy_externs.cpp | 117 - gapii/cc/gvr_abi_types.h | 35 - gapii/cc/gvr_extras.cpp | 75 - gapii/cc/gvr_extras.inc | 26 - gapii/cc/gvr_inlines.inc | 18 - gapii/cc/spy.cpp | 367 +- gapii/cc/spy.h | 40 +- gapii/cc/spy_disable_precompiled_shaders.cpp | 260 - gapii/cc/windows/wgl.cpp | 59 - gapii/cc/windows/wgl.h | 38 - gapii/interceptor-lib/cc/BUILD.bazel | 77 - .../interceptor-lib/cc/include/interceptor.h | 58 - .../cc/lib/AArch64/target_aarch64.cpp | 254 - .../cc/lib/AArch64/target_aarch64.h | 54 - .../interceptor-lib/cc/lib/ARM/target_arm.cpp | 402 -- gapii/interceptor-lib/cc/lib/ARM/target_arm.h | 57 - .../interceptor-lib/cc/lib/X86/target_x86.cpp | 184 - gapii/interceptor-lib/cc/lib/X86/target_x86.h | 51 - .../interceptor-lib/cc/lib/code_generator.cpp | 157 - gapii/interceptor-lib/cc/lib/code_generator.h | 110 - .../cc/lib/constant_pool_data_expr.cpp | 98 - .../cc/lib/constant_pool_data_expr.h | 66 - gapii/interceptor-lib/cc/lib/disassembler.cpp | 62 - gapii/interceptor-lib/cc/lib/disassembler.h | 57 - gapii/interceptor-lib/cc/lib/error.cpp | 40 - gapii/interceptor-lib/cc/lib/error.h | 41 - gapii/interceptor-lib/cc/lib/exports.in | 5 - gapii/interceptor-lib/cc/lib/interceptor.cpp | 342 -- .../cc/lib/libinterceptor.exports | 3 - .../interceptor-lib/cc/lib/memory_manager.cpp | 79 - gapii/interceptor-lib/cc/lib/memory_manager.h | 65 - gapii/interceptor-lib/cc/lib/target.cpp | 25 - gapii/interceptor-lib/cc/lib/target.h | 113 - gapil/bapi/BUILD.bazel | 2 - gapil/bapi/bapi_test.go | 2 - gapir/cc/BUILD.bazel | 21 - gapir/cc/android/gles_renderer.cpp | 245 - gapir/cc/context.cpp | 201 +- gapir/cc/context.h | 7 - gapir/cc/gles_renderer.h | 111 - gapir/cc/linux/gles_renderer.cpp | 430 -- gapir/cc/osx/gles_renderer.mm | 226 - gapir/cc/windows/gles_renderer.cpp | 486 -- gapis/api/all/BUILD.bazel | 2 - gapis/api/all/all.go | 2 - gapis/api/gles/BUILD.bazel | 197 - gapis/api/gles/api/android_extension_pack.api | 292 - gapis/api/gles/api/android_native.api | 56 - gapis/api/gles/api/asynchronous_queries.api | 188 - gapis/api/gles/api/buffer_objects.api | 531 -- gapis/api/gles/api/constants.api | 199 - gapis/api/gles/api/debug.api | 365 -- gapis/api/gles/api/draw_commands.api | 533 -- gapis/api/gles/api/egl.api | 503 -- gapis/api/gles/api/eglenum.api | 180 - gapis/api/gles/api/errors.api | 111 - gapis/api/gles/api/extensions.api | 3335 ---------- gapis/api/gles/api/extras.api | 213 - gapis/api/gles/api/fragment_operations.api | 412 -- gapis/api/gles/api/framebuffer.api | 1177 ---- gapis/api/gles/api/gl.api | 56 - gapis/api/gles/api/glbitfield.api | 226 - gapis/api/gles/api/glenum.api | 5470 ----------------- gapis/api/gles/api/image_format.api | 517 -- gapis/api/gles/api/other.api | 336 - gapis/api/gles/api/programs_and_shaders.api | 2457 -------- gapis/api/gles/api/rasterization.api | 158 - gapis/api/gles/api/state_queries.api | 1495 ----- gapis/api/gles/api/synchronization.api | 139 - gapis/api/gles/api/textures_and_samplers.api | 2021 ------ gapis/api/gles/api/transform_feedback.api | 189 - gapis/api/gles/api/util.api | 52 - gapis/api/gles/api/vertex_arrays.api | 710 --- gapis/api/gles/compat.go | 1374 ----- gapis/api/gles/compat_buffers.go | 190 - gapis/api/gles/compat_client.go | 235 - gapis/api/gles/compat_test.go | 159 - gapis/api/gles/context.go | 44 - gapis/api/gles/custom_replay.go | 491 -- gapis/api/gles/datatypes.go | 39 - gapis/api/gles/dead_code_elimination_test.go | 293 - .../dependency_graph_behaviour_provider.go | 648 -- gapis/api/gles/dependencygraph2_test.go | 219 - gapis/api/gles/doc.go | 16 - gapis/api/gles/draw_call.go | 359 -- gapis/api/gles/draw_call_mesh.go | 285 - gapis/api/gles/externs.go | 206 - gapis/api/gles/extras.go | 189 - gapis/api/gles/find_issues.go | 298 - gapis/api/gles/gles.api | 933 --- gapis/api/gles/gles.go | 273 - gapis/api/gles/gles10.api | 1287 ---- gapis/api/gles/gles_pb/BUILD.bazel | 63 - gapis/api/gles/gles_pb/doc.go | 16 - gapis/api/gles/gles_pb/extras.proto | 34 - gapis/api/gles/glsl.go | 40 - gapis/api/gles/graph_visualization.go | 49 - gapis/api/gles/guess_semantics.go | 92 - gapis/api/gles/helpers.go | 235 - gapis/api/gles/image.go | 382 -- gapis/api/gles/importance.go | 43 - gapis/api/gles/issue_whitelist.go | 34 - gapis/api/gles/links.go | 234 - gapis/api/gles/markers.go | 73 - gapis/api/gles/markers_test.go | 25 - gapis/api/gles/math.go | 41 - gapis/api/gles/read_depth.go | 147 - gapis/api/gles/read_framebuffer.go | 452 -- gapis/api/gles/read_texture.go | 156 - gapis/api/gles/replay.go | 495 -- gapis/api/gles/replay.todo | 14 - gapis/api/gles/resolvables.proto | 40 - gapis/api/gles/resources.go | 639 -- gapis/api/gles/state.go | 111 - gapis/api/gles/state_builder.go | 1380 ----- gapis/api/gles/string.go | 64 - gapis/api/gles/stub_program.go | 278 - gapis/api/gles/stub_program_test.go | 138 - gapis/api/gles/synthetic.api | 52 - gapis/api/gles/templates/BUILD.bazel | 31 - gapis/api/gles/templates/api_exports.cpp.tmpl | 115 - gapis/api/gles/templates/api_imports.cpp.tmpl | 61 - gapis/api/gles/texture_compat.go | 473 -- gapis/api/gles/tweaker.go | 514 -- gapis/api/gles/types.api | 54 - gapis/api/gles/undefined_framebuffer.go | 145 - gapis/api/gles/version.go | 96 - gapis/api/gles/wireframe.go | 219 - gapis/api/gvr/BUILD.bazel | 107 - gapis/api/gvr/doc.go | 16 - gapis/api/gvr/extension.go | 239 - gapis/api/gvr/framebindings.go | 112 - gapis/api/gvr/gvr.api | 422 -- gapis/api/gvr/gvr.go | 169 - gapis/api/gvr/gvr_pb/BUILD.bazel | 54 - gapis/api/gvr/gvr_pb/doc.go | 16 - gapis/api/gvr/importance.go | 23 - gapis/api/gvr/resolvables.proto | 25 - gapis/api/gvr/templates/BUILD.bazel | 45 - gapis/api/gvr/templates/api_exports.cpp.tmpl | 62 - gapis/api/gvr/templates/api_exports.h.tmpl | 40 - gapis/api/gvr/templates/api_imports.cpp.tmpl | 45 - gapis/api/gvr/templates/api_install.cpp.tmpl | 63 - gapis/api/gvr/types.api | 244 - gapis/api/service.proto | 1 - gapis/api/templates/api_spy.h.tmpl | 4 - gapis/extensions/unity/BUILD.bazel | 32 - gapis/extensions/unity/state_reset_grouper.go | 237 - gapis/extensions/unity/unity.go | 35 - kokoro/linux/build.sh | 8 +- kokoro/macos/build.sh | 4 +- kokoro/windows/build.bat | 7 - tools/build/workspace.bzl | 9 - 175 files changed, 9 insertions(+), 47433 deletions(-) delete mode 100644 cmd/verify_gles_api/BUILD.bazel delete mode 100644 cmd/verify_gles_api/main.go delete mode 100644 cmd/verify_gles_api/registry.go delete mode 100644 gapii/cc/android/gles_layer.cpp delete mode 100644 gapii/cc/android/gvr_install.h delete mode 100644 gapii/cc/android/installer.cpp delete mode 100644 gapii/cc/android/installer.h delete mode 100644 gapii/cc/gles_context.cpp delete mode 100644 gapii/cc/gles_exports.h delete mode 100644 gapii/cc/gles_extras.cpp delete mode 100644 gapii/cc/gles_extras.inc delete mode 100644 gapii/cc/gles_inlines.inc delete mode 100644 gapii/cc/gles_mid_execution.cpp delete mode 100644 gapii/cc/gles_spy_externs.cpp delete mode 100644 gapii/cc/gvr_abi_types.h delete mode 100644 gapii/cc/gvr_extras.cpp delete mode 100644 gapii/cc/gvr_extras.inc delete mode 100644 gapii/cc/gvr_inlines.inc delete mode 100644 gapii/cc/spy_disable_precompiled_shaders.cpp delete mode 100644 gapii/cc/windows/wgl.cpp delete mode 100644 gapii/cc/windows/wgl.h delete mode 100644 gapii/interceptor-lib/cc/BUILD.bazel delete mode 100644 gapii/interceptor-lib/cc/include/interceptor.h delete mode 100644 gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.h delete mode 100644 gapii/interceptor-lib/cc/lib/ARM/target_arm.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/ARM/target_arm.h delete mode 100644 gapii/interceptor-lib/cc/lib/X86/target_x86.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/X86/target_x86.h delete mode 100644 gapii/interceptor-lib/cc/lib/code_generator.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/code_generator.h delete mode 100644 gapii/interceptor-lib/cc/lib/constant_pool_data_expr.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/constant_pool_data_expr.h delete mode 100644 gapii/interceptor-lib/cc/lib/disassembler.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/disassembler.h delete mode 100644 gapii/interceptor-lib/cc/lib/error.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/error.h delete mode 100644 gapii/interceptor-lib/cc/lib/exports.in delete mode 100644 gapii/interceptor-lib/cc/lib/interceptor.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/libinterceptor.exports delete mode 100644 gapii/interceptor-lib/cc/lib/memory_manager.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/memory_manager.h delete mode 100644 gapii/interceptor-lib/cc/lib/target.cpp delete mode 100644 gapii/interceptor-lib/cc/lib/target.h delete mode 100644 gapir/cc/android/gles_renderer.cpp delete mode 100644 gapir/cc/gles_renderer.h delete mode 100644 gapir/cc/linux/gles_renderer.cpp delete mode 100644 gapir/cc/osx/gles_renderer.mm delete mode 100644 gapir/cc/windows/gles_renderer.cpp delete mode 100644 gapis/api/gles/BUILD.bazel delete mode 100644 gapis/api/gles/api/android_extension_pack.api delete mode 100644 gapis/api/gles/api/android_native.api delete mode 100644 gapis/api/gles/api/asynchronous_queries.api delete mode 100644 gapis/api/gles/api/buffer_objects.api delete mode 100644 gapis/api/gles/api/constants.api delete mode 100644 gapis/api/gles/api/debug.api delete mode 100644 gapis/api/gles/api/draw_commands.api delete mode 100644 gapis/api/gles/api/egl.api delete mode 100644 gapis/api/gles/api/eglenum.api delete mode 100644 gapis/api/gles/api/errors.api delete mode 100644 gapis/api/gles/api/extensions.api delete mode 100644 gapis/api/gles/api/extras.api delete mode 100644 gapis/api/gles/api/fragment_operations.api delete mode 100644 gapis/api/gles/api/framebuffer.api delete mode 100644 gapis/api/gles/api/gl.api delete mode 100644 gapis/api/gles/api/glbitfield.api delete mode 100644 gapis/api/gles/api/glenum.api delete mode 100644 gapis/api/gles/api/image_format.api delete mode 100644 gapis/api/gles/api/other.api delete mode 100644 gapis/api/gles/api/programs_and_shaders.api delete mode 100644 gapis/api/gles/api/rasterization.api delete mode 100644 gapis/api/gles/api/state_queries.api delete mode 100644 gapis/api/gles/api/synchronization.api delete mode 100644 gapis/api/gles/api/textures_and_samplers.api delete mode 100644 gapis/api/gles/api/transform_feedback.api delete mode 100644 gapis/api/gles/api/util.api delete mode 100644 gapis/api/gles/api/vertex_arrays.api delete mode 100644 gapis/api/gles/compat.go delete mode 100644 gapis/api/gles/compat_buffers.go delete mode 100644 gapis/api/gles/compat_client.go delete mode 100644 gapis/api/gles/compat_test.go delete mode 100644 gapis/api/gles/context.go delete mode 100644 gapis/api/gles/custom_replay.go delete mode 100644 gapis/api/gles/datatypes.go delete mode 100644 gapis/api/gles/dead_code_elimination_test.go delete mode 100644 gapis/api/gles/dependency_graph_behaviour_provider.go delete mode 100644 gapis/api/gles/dependencygraph2_test.go delete mode 100644 gapis/api/gles/doc.go delete mode 100644 gapis/api/gles/draw_call.go delete mode 100644 gapis/api/gles/draw_call_mesh.go delete mode 100644 gapis/api/gles/externs.go delete mode 100644 gapis/api/gles/extras.go delete mode 100644 gapis/api/gles/find_issues.go delete mode 100644 gapis/api/gles/gles.api delete mode 100644 gapis/api/gles/gles.go delete mode 100644 gapis/api/gles/gles10.api delete mode 100644 gapis/api/gles/gles_pb/BUILD.bazel delete mode 100644 gapis/api/gles/gles_pb/doc.go delete mode 100644 gapis/api/gles/gles_pb/extras.proto delete mode 100644 gapis/api/gles/glsl.go delete mode 100644 gapis/api/gles/graph_visualization.go delete mode 100644 gapis/api/gles/guess_semantics.go delete mode 100644 gapis/api/gles/helpers.go delete mode 100644 gapis/api/gles/image.go delete mode 100644 gapis/api/gles/importance.go delete mode 100644 gapis/api/gles/issue_whitelist.go delete mode 100644 gapis/api/gles/links.go delete mode 100644 gapis/api/gles/markers.go delete mode 100644 gapis/api/gles/markers_test.go delete mode 100644 gapis/api/gles/math.go delete mode 100644 gapis/api/gles/read_depth.go delete mode 100644 gapis/api/gles/read_framebuffer.go delete mode 100644 gapis/api/gles/read_texture.go delete mode 100644 gapis/api/gles/replay.go delete mode 100644 gapis/api/gles/replay.todo delete mode 100644 gapis/api/gles/resolvables.proto delete mode 100644 gapis/api/gles/resources.go delete mode 100644 gapis/api/gles/state.go delete mode 100644 gapis/api/gles/state_builder.go delete mode 100644 gapis/api/gles/string.go delete mode 100644 gapis/api/gles/stub_program.go delete mode 100644 gapis/api/gles/stub_program_test.go delete mode 100644 gapis/api/gles/synthetic.api delete mode 100644 gapis/api/gles/templates/BUILD.bazel delete mode 100644 gapis/api/gles/templates/api_exports.cpp.tmpl delete mode 100644 gapis/api/gles/templates/api_imports.cpp.tmpl delete mode 100644 gapis/api/gles/texture_compat.go delete mode 100644 gapis/api/gles/tweaker.go delete mode 100644 gapis/api/gles/types.api delete mode 100644 gapis/api/gles/undefined_framebuffer.go delete mode 100644 gapis/api/gles/version.go delete mode 100644 gapis/api/gles/wireframe.go delete mode 100644 gapis/api/gvr/BUILD.bazel delete mode 100644 gapis/api/gvr/doc.go delete mode 100644 gapis/api/gvr/extension.go delete mode 100644 gapis/api/gvr/framebindings.go delete mode 100644 gapis/api/gvr/gvr.api delete mode 100644 gapis/api/gvr/gvr.go delete mode 100644 gapis/api/gvr/gvr_pb/BUILD.bazel delete mode 100644 gapis/api/gvr/gvr_pb/doc.go delete mode 100644 gapis/api/gvr/importance.go delete mode 100644 gapis/api/gvr/resolvables.proto delete mode 100644 gapis/api/gvr/templates/BUILD.bazel delete mode 100644 gapis/api/gvr/templates/api_exports.cpp.tmpl delete mode 100644 gapis/api/gvr/templates/api_exports.h.tmpl delete mode 100644 gapis/api/gvr/templates/api_imports.cpp.tmpl delete mode 100644 gapis/api/gvr/templates/api_install.cpp.tmpl delete mode 100644 gapis/api/gvr/types.api delete mode 100644 gapis/extensions/unity/BUILD.bazel delete mode 100644 gapis/extensions/unity/state_reset_grouper.go delete mode 100644 gapis/extensions/unity/unity.go diff --git a/cmd/enum_lookup/BUILD.bazel b/cmd/enum_lookup/BUILD.bazel index 7401d0d48b..a925e46811 100644 --- a/cmd/enum_lookup/BUILD.bazel +++ b/cmd/enum_lookup/BUILD.bazel @@ -15,22 +15,6 @@ load("//tools/build:rules.bzl", "apic_template", "go_stripped_binary") load("@io_bazel_rules_go//go:def.bzl", "go_library") -apic_template( - name = "gles_lookup", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:enum_lookup.go", - ], -) - -apic_template( - name = "gvr_lookup", - api = "//gapis/api/gvr:api", - templates = [ - "//gapis/api/templates:enum_lookup.go", - ], -) - apic_template( name = "vulkan_lookup", api = "//gapis/api/vulkan:api", @@ -46,8 +30,6 @@ go_library( "main.go", ], embed = [ - ":gles_lookup", # keep - ":gvr_lookup", # keep ":vulkan_lookup", # keep ], importpath = "github.com/google/gapid/cmd/enum_lookup", diff --git a/cmd/gapis/BUILD.bazel b/cmd/gapis/BUILD.bazel index 84f0195f9e..a1312d5807 100644 --- a/cmd/gapis/BUILD.bazel +++ b/cmd/gapis/BUILD.bazel @@ -35,7 +35,6 @@ go_library( "//core/text:go_default_library", "//gapir/client:go_default_library", "//gapis/database:go_default_library", - "//gapis/extensions/unity:go_default_library", "//gapis/replay:go_default_library", "//gapis/server:go_default_library", "//gapis/service:go_default_library", diff --git a/cmd/gapis/main.go b/cmd/gapis/main.go index 8d0b5a14b6..1be9d454f7 100644 --- a/cmd/gapis/main.go +++ b/cmd/gapis/main.go @@ -45,9 +45,6 @@ import ( "github.com/google/gapid/gapis/service/path" "github.com/google/gapid/gapis/stringtable" "github.com/google/gapid/gapis/trace" - - // Extensions - _ "github.com/google/gapid/gapis/extensions/unity" ) var ( diff --git a/cmd/linearize_trace/BUILD.bazel b/cmd/linearize_trace/BUILD.bazel index 33da6f0e77..1823923c25 100644 --- a/cmd/linearize_trace/BUILD.bazel +++ b/cmd/linearize_trace/BUILD.bazel @@ -22,8 +22,6 @@ go_library( deps = [ "//core/app:go_default_library", "//core/log:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/api/gvr:go_default_library", "//gapis/api/vulkan:go_default_library", "//gapis/capture:go_default_library", "//gapis/database:go_default_library", diff --git a/cmd/linearize_trace/main.go b/cmd/linearize_trace/main.go index 2940f5e660..25e94b1ef6 100644 --- a/cmd/linearize_trace/main.go +++ b/cmd/linearize_trace/main.go @@ -25,8 +25,6 @@ import ( "github.com/google/gapid/core/app" log "github.com/google/gapid/core/log" - _ "github.com/google/gapid/gapis/api/gles" - _ "github.com/google/gapid/gapis/api/gvr" _ "github.com/google/gapid/gapis/api/vulkan" "github.com/google/gapid/gapis/capture" "github.com/google/gapid/gapis/database" diff --git a/cmd/verify_gles_api/BUILD.bazel b/cmd/verify_gles_api/BUILD.bazel deleted file mode 100644 index fc701c468e..0000000000 --- a/cmd/verify_gles_api/BUILD.bazel +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "main.go", - "registry.go", - ], - importpath = "github.com/google/gapid/cmd/verify_gles_api", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//core/text/parse/cst:go_default_library", - "//gapil:go_default_library", - "//gapil/semantic:go_default_library", - ], -) - -go_binary( - name = "verify_gles_api", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/cmd/verify_gles_api/main.go b/cmd/verify_gles_api/main.go deleted file mode 100644 index 665a4382f4..0000000000 --- a/cmd/verify_gles_api/main.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "fmt" - "os" - "regexp" - "strconv" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/text/parse/cst" - "github.com/google/gapid/gapil" - "github.com/google/gapid/gapil/semantic" -) - -var ( - apiPath = flag.String("api", "", "Filename of the api file to verify (required)") - cacheDir = flag.String("cache", "", "Directory for caching downloaded files (required)") - apiRoot *semantic.API - mappings *semantic.Mappings - numErrors = 0 -) - -func main() { - app.ShortHelp = "stringgen compiles string table files to string packages and a Go definition file." - app.Run(run) -} - -func run(ctx context.Context) error { - if *apiPath == "" { - app.Usage(ctx, "Mustsupply api path") - } - if *cacheDir == "" { - app.Usage(ctx, "Must supply cache dir") - } - processor := gapil.NewProcessor() - mappings = processor.Mappings - api, errs := processor.Resolve(*apiPath) - if len(errs) > 0 { - for _, err := range errs { - PrintError("%v\n", err.Message) - } - os.Exit(2) - } - apiRoot = api - reg := DownloadRegistry() - VerifyApi(reg) - return nil -} - -func PrintError(format string, a ...interface{}) { - fmt.Fprintf(os.Stderr, format, a...) - numErrors = numErrors + 1 -} - -func VerifyApi(reg *Registry) { - VerifyEnum(reg, false) - VerifyEnum(reg, true) - for _, cmd := range reg.Command { - VerifyCommand(reg, cmd) - } -} - -func VerifyEnum(r *Registry, bitfields bool) { - name := "GLenum" - if bitfields { - name = "GLbitfield" - } - expected := make(map[string]struct{}) - for _, enums := range r.Enums { - if (enums.Type == "bitmask") == bitfields && enums.Namespace == "GL" { - for _, enum := range enums.Enum { - // Boolean values are handles specially (as labels) - if enum.Name == "GL_TRUE" || enum.Name == "GL_FALSE" { - continue - } - // The following 64bit values are not proper GLenum values. - if enum.Name == "GL_TIMEOUT_IGNORED" || enum.Name == "GL_TIMEOUT_IGNORED_APPLE" { - continue - } - if enum.API == "" || enum.API == GLES1API || enum.API == GLES2API { - var value uint32 - if v, err := strconv.ParseUint(enum.Value, 0, 32); err == nil { - value = uint32(v) - } else if v, err := strconv.ParseInt(enum.Value, 0, 32); err == nil { - value = uint32(v) - } else { - PrintError("Failed to parse enum value %v", enum.Value) - continue - } - expected[fmt.Sprintf("%s = 0x%08X", enum.Name, value)] = struct{}{} - } - } - } - } - seen := make(map[string]struct{}) - for _, e := range apiRoot.Enums { - if e.Name() == name { - for _, m := range e.Entries { - seen[fmt.Sprintf("%s = 0x%08X", m.Name(), m.Value)] = struct{}{} - } - } - } - CompareSets(expected, seen, name+": ") -} - -func CompareSets(expected, seen map[string]struct{}, msg_prefix string) { - for k := range expected { - if _, found := seen[k]; !found { - PrintError("%sMissing %s\n", msg_prefix, k) - } - } - for k := range seen { - if _, found := expected[k]; !found { - PrintError("%sUnexpected %s\n", msg_prefix, k) - } - } - return -} - -var re_const_ptr_pre = regexp.MustCompile(`^const (\w+) \*$`) -var re_const_ptr_post = regexp.MustCompile(`^(.+)\bconst\*$`) - -func VerifyType(cmd string, paramIndex int, expected string, seen semantic.Type) bool { - expected = strings.TrimSpace(expected) - name := seen.(semantic.NamedNode).Name() - switch s := seen.(type) { - case *semantic.Pointer: - if s.Const { - if match := re_const_ptr_pre.FindStringSubmatch(expected); match != nil { - return VerifyType(cmd, paramIndex, match[1], s.To) - } - if match := re_const_ptr_post.FindStringSubmatch(expected); match != nil { - return VerifyType(cmd, paramIndex, match[1], s.To) - } - } else { - if strings.HasSuffix(expected, "*") { - return VerifyType(cmd, paramIndex, strings.TrimSuffix(expected, "*"), s.To) - } - } - case *semantic.Pseudonym: - if s.Name() == expected { - return true - } else if expected == "GLDEBUGPROCKHR" && s.Name() == "GLDEBUGPROC" { - return true - } else { - return VerifyType(cmd, paramIndex, expected, s.To) - } - case *semantic.Enum: - if s.Name() == expected { - return true - } - case *semantic.Builtin: - if s.Name() == expected { - return true - } else if expected == "const GLchar *" && s.Name() == "string" { - return true - } - } - PrintError("%s: Param %v: Expected type %s but seen %s (%T)\n", cmd, paramIndex, expected, name, seen) - return false -} - -func UniqueStrings(strs []string) (res []string) { - seen := map[string]struct{}{} - for _, str := range strs { - if _, ok := seen[str]; !ok { - res = append(res, str) - seen[str] = struct{}{} - } - } - return -} - -func VerifyCommand(reg *Registry, cmd *Command) { - cmdName := cmd.Name() - versions := append(reg.GetVersions(GLES1API, cmdName), reg.GetVersions(GLES2API, cmdName)...) - extensions := append(reg.GetExtensions(GLES1API, cmdName), reg.GetExtensions(GLES2API, cmdName)...) - extensions = UniqueStrings(extensions) - if len(versions) == 0 && len(extensions) == 0 { - return // It is not a GLES command. - } - - // Expected annotations. - annots := []string{} - if strings.HasPrefix(cmdName, "glDraw") && !strings.HasPrefix(cmdName, "glDrawBuffers") { - annots = append(annots, "@draw_call") - } - for _, version := range versions { - if version == Version("1.0") && len(versions) > 1 { - continue // TODO: Add those in the api file. - } - url, _ := GetCoreManpage(version, cmdName) - annots = append(annots, fmt.Sprintf(`@doc("%s", Version.GLES%v)`, url, strings.Replace(string(version), ".", "", -1))) - } - for _, extension := range extensions { - url, _ := GetExtensionManpage(extension) - annots = append(annots, fmt.Sprintf(`@doc("%s", Extension.%v)`, url, extension)) - } - if len(versions) != 0 { - cond := fmt.Sprintf(`Version.GLES%v`, strings.Replace(string(versions[0]), ".", "", -1)) - if len(versions) == 1 && versions[0] == Version("1.0") { - cond = "Version.GLES10 && !Version.GLES20" // Deprecated in GLES20 - } - annots = append(annots, fmt.Sprintf(`@if(%v)`, cond)) - } - if len(extensions) != 0 { - conds := []string{} - for _, extension := range extensions { - conds = append(conds, fmt.Sprintf(`Extension.%v`, extension)) - } - annots = append(annots, fmt.Sprintf("@if(%s)", strings.Join(conds, " || "))) - } - - // Find existing API function. - var apiCmd *semantic.Function - for _, apiFunction := range apiRoot.Functions { - if apiFunction.Name() == cmdName { - apiCmd = apiFunction - } - } - - // Print command to stdout if it is missing. - if apiCmd == nil { - params := []string{} - for _, param := range cmd.Param { - params = append(params, param.Type()+" "+param.Name) - } - fmt.Printf("%s\ncmd %s %s(%s) { }\n", strings.Join(annots, "\n"), - cmd.Proto.Type(), cmdName, strings.Join(params, ", ")) - return - } - - // Check documentation strings. - expected := make(map[string]struct{}) - for _, a := range annots { - expected[a] = struct{}{} - } - seen := make(map[string]struct{}) - for _, a := range apiCmd.Annotations { - if a.Name() == "if" || a.Name() == "doc" || a.Name() == "draw_call" { - seen[getSource(mappings.AST.CST(a.AST))] = struct{}{} - } - } - CompareSets(expected, seen, fmt.Sprintf("%s: ", cmdName)) - - // Check parameter types. - if len(cmd.Param) != len(apiCmd.CallParameters()) { - PrintError("%s: Expected %v parameters but seen %v\n", cmdName, len(cmd.Param), len(apiCmd.CallParameters())) - } else { - for i, p := range cmd.Param { - VerifyType(cmdName, i, p.Type(), apiCmd.FullParameters[i].Type) - } - } -} - -func getSource(n cst.Node) string { - return string(n.Tok().Source.Runes[n.Tok().Start:n.Tok().End]) -} diff --git a/cmd/verify_gles_api/registry.go b/cmd/verify_gles_api/registry.go deleted file mode 100644 index c33b7a2438..0000000000 --- a/cmd/verify_gles_api/registry.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "encoding/xml" - "fmt" - "io/ioutil" - "net/http" - "os" - "regexp" - "strings" -) - -const registry_url = "https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml" - -// DownloadRegistry downloads the Khronos XML registry file. -func DownloadRegistry() *Registry { - bytes := Download(registry_url) - if len(bytes) == 0 { - panic(fmt.Errorf("Can not download %s", registry_url)) - } - reg := &Registry{} - if err := xml.Unmarshal(bytes, reg); err != nil { - panic(err.Error()) - } - return reg -} - -type KhronosAPI string -type Version string - -const GLES1API = KhronosAPI("gles1") -const GLES2API = KhronosAPI("gles2") // Includes GLES 3.0 and later - -func (v Version) String() string { return fmt.Sprintf("%s", string(v)) } - -type Registry struct { - Group []*Group `xml:"groups>group"` - Enums []*Enums `xml:"enums"` - Command []*Command `xml:"commands>command"` - Feature []*Feature `xml:"feature"` - Extension []*ExtensionElement `xml:"extensions>extension"` -} - -type NamedElementList []NamedElement -type NamedElement struct { - Name string `xml:"name,attr"` -} - -type Group struct { - NamedElement - Enum NamedElementList `xml:"enum"` -} - -type Enums struct { - Namespace string `xml:"namespace,attr"` - Group string `xml:"group,attr"` - Type string `xml:"type,attr"` // "bitmask" - Comment string `xml:"comment,attr"` - Enum []Enum `xml:"enum"` -} - -type Enum struct { - NamedElement - Value string `xml:"value,attr"` - Type string `xml:"type,attr"` // "u" or "ull" - API KhronosAPI `xml:"api,attr"` - Alias string `xml:"alias,attr"` -} - -type Command struct { - Proto ProtoOrParam `xml:"proto"` - Param []ProtoOrParam `xml:"param"` - Alias NamedElement `xml:"alias"` -} - -type ProtoOrParam struct { - InnerXML string `xml:",innerxml"` - Chardata string `xml:",chardata"` - Group string `xml:"group,attr"` - Length string `xml:"len,attr"` - Ptype string `xml:"ptype"` - Name string `xml:"name"` -} - -type Feature struct { - NamedElement - API KhronosAPI `xml:"api,attr"` - Number Version `xml:"number,attr"` - Require RequireOrRemoveList `xml:"require"` - Remove RequireOrRemoveList `xml:"remove"` -} - -type ExtensionElement struct { - NamedElement - Supported string `xml:"supported,attr"` - Require RequireOrRemoveList `xml:"require"` - Remove RequireOrRemoveList `xml:"remove"` -} - -type RequireOrRemoveList []RequireOrRemove -type RequireOrRemove struct { - API KhronosAPI `xml:"api,attr"` // for extensions only - Profile string `xml:"profile,attr"` - Comment string `xml:"comment,attr"` - Enum NamedElementList `xml:"enum"` - Command NamedElementList `xml:"command"` -} - -func (l NamedElementList) Contains(name string) bool { - for _, v := range l { - if v.Name == name { - return true - } - } - return false -} - -func (r *RequireOrRemove) Contains(name string) bool { - return r.Enum.Contains(name) || r.Command.Contains(name) -} - -func (l RequireOrRemoveList) Contains(name string) bool { - for _, v := range l { - if v.Contains(name) { - return true - } - } - return false -} - -func (e *ExtensionElement) IsSupported(api KhronosAPI) bool { - for _, v := range strings.Split(e.Supported, "|") { - if KhronosAPI(v) == api { - return true - } - } - return false -} - -func (c Command) Name() string { - return c.Proto.Name -} - -func (p ProtoOrParam) Type() string { - name := p.InnerXML - name = name[:strings.Index(name, "")] - name = strings.Replace(name, "", "", 1) - name = strings.Replace(name, "", "", 1) - name = strings.TrimSpace(name) - return name -} - -// ParamsAndResult returns all parameters and return value as -1. -func (cmd *Command) ParamsAndResult() map[int]ProtoOrParam { - result := cmd.Proto - result.Name = "result" - results := map[int]ProtoOrParam{-1: result} - for i, param := range cmd.Param { - results[i] = param - } - return results -} - -// GetVersions returns sorted list of versions which support the given symbol. -func (r *Registry) GetVersions(api KhronosAPI, name string) []Version { - version, found := Version(""), false - for _, feature := range r.Feature { - if feature.API == api { - if feature.Require.Contains(name) { - if found { - panic(fmt.Errorf("redefinition of %s", name)) - } - version, found = feature.Number, true - } - if feature.Remove != nil { - // not used in GLES - panic(fmt.Errorf("remove tag is not supported")) - } - } - } - if found { - switch version { - case "1.0": - return []Version{"1.0"} - case "2.0": - return []Version{"2.0", "3.0", "3.1", "3.2"} - case "3.0": - return []Version{"3.0", "3.1", "3.2"} - case "3.1": - return []Version{"3.1", "3.2"} - case "3.2": - return []Version{"3.2"} - default: - panic(fmt.Errorf("Uknown GLES version: %v", version)) - } - } else { - return nil - } -} - -// GetExtensions returns extensions which define the given symbol. -func (r *Registry) GetExtensions(api KhronosAPI, name string) []string { - var extensions []string -ExtensionLoop: - for _, extension := range r.Extension { - if extension.IsSupported(api) { - for _, require := range extension.Require { - if require.API == "" || require.API == api { - if require.Contains(name) { - extensions = append(extensions, extension.Name) - // sometimes the extension repeats definition - ignore - continue ExtensionLoop - } - } - } - if extension.Remove != nil { - // not used in GLES - panic(fmt.Errorf("remove tag is not supported")) - } - } - } - return extensions -} - -var sufix_re = regexp.MustCompile("(64|)(i_|)(I|)([1-4]|[1-4]x[1-4]|)(x|ub|f|i|ui|fi|i64|)(v|)$") - -func GetCoreManpage(version Version, cmdName string) (url string, data []byte) { - var urlFormat string - switch version { - case "1.0": - urlFormat = "https://www.khronos.org/opengles/sdk/1.1/docs/man/%s.xml" - case "2.0": - urlFormat = "https://www.khronos.org/opengles/sdk/docs/man/xhtml/%s.xml" - case "3.0": - urlFormat = "https://www.khronos.org/opengles/sdk/docs/man3/html/%s.xhtml" - case "3.1": - urlFormat = "https://www.khronos.org/opengles/sdk/docs/man31/html/%s.xhtml" - case "3.2": - urlFormat = "https://www.khronos.org/opengles/sdk/docs/man32/html/%s.xhtml" - default: - panic(fmt.Errorf("Uknown api version: %v", version)) - } - - for _, table := range []struct{ oldPrefix, newPrefix string }{ - {"glDisable", "glEnable"}, - {"glEnd", "glBegin"}, - {"glGetBoolean", "glGet"}, - {"glGetFixed", "glGet"}, - {"glGetFloat", "glGet"}, - {"glGetInteger", "glGet"}, - {"glGetnUniform", "glGetUniform"}, - {"glMemoryBarrierByRegion", "glMemoryBarrier"}, - {"glProgramUniformMatrix", "glProgramUniform"}, - {"glReadnPixels", "glReadPixels"}, - {"glUniformMatrix", "glUniform"}, - {"glUnmapBuffer", "glMapBufferRange"}, - {"glVertexAttribIFormat", "glVertexAttribFormat"}, - {"glVertexAttribIPointer", "glVertexAttribPointer"}, - {"", ""}, // no-op - } { - if strings.HasPrefix(cmdName, table.oldPrefix) { - // Replace prefix - cmdName := table.newPrefix + strings.TrimPrefix(cmdName, table.oldPrefix) - // Try to download URL without suffix - if sufix_re.MatchString(cmdName) { - cmdName := sufix_re.ReplaceAllString(cmdName, "") - url = fmt.Sprintf(urlFormat, cmdName) - if data := Download(url); len(data) > 0 { - return url, data - } - } - // Try to download URL with suffix - url = fmt.Sprintf(urlFormat, cmdName) - if data := Download(url); len(data) > 0 { - return url, data - } - } - } - panic(fmt.Errorf("Failed to find URL for %s", cmdName)) -} - -func GetExtensionManpage(extension string) (url string, data []byte) { - parts := strings.Split(extension, "_") - vendor := parts[1] - page := strings.Join(parts[2:], "_") - url = fmt.Sprintf("https://www.khronos.org/registry/gles/extensions/%s/%s_%s.txt", vendor, vendor, page) - if data := Download(url); len(data) > 0 { - return url, data - } - for _, table := range []struct{ extension, page string }{ - {"GL_NV_coverage_sample", "NV/EGL_NV_coverage_sample.txt"}, - {"GL_NV_depth_nonlinear", "NV/EGL_NV_depth_nonlinear.txt"}, - {"GL_NV_EGL_NV_coverage_sample", "NV/EGL_NV_coverage_sample.txt"}, - {"GL_EXT_separate_shader_objects", "EXT/EXT_separate_shader_objects.gles.txt"}, - } { - if table.extension == extension { - url = fmt.Sprintf("https://www.khronos.org/registry/gles/extensions/%s", table.page) - if data := Download(url); len(data) > 0 { - return url, data - } - } - } - panic(fmt.Errorf("Failed to find URL for %s", extension)) -} - -// Download the given URL. Returns empty slice if the page can not be found (404). -func Download(url string) []byte { - filename := url - filename = strings.TrimPrefix(filename, "https://") - filename = strings.Replace(filename, "/", "-", strings.Count(filename, "/")-1) - filename = strings.Replace(filename, "/", string(os.PathSeparator), 1) - filename = *cacheDir + string(os.PathSeparator) + filename - if bytes, err := ioutil.ReadFile(filename); err == nil { - return bytes - } - resp, err := http.Get(url) - if err != nil { - panic(err) - } - bytes := []byte{} - if resp.StatusCode == 200 { - bytes, err = ioutil.ReadAll(resp.Body) - if err != nil { - panic(err) - } - } else if resp.StatusCode != 404 { - panic(fmt.Errorf("%s: %s", url, resp.Status)) - } - resp.Body.Close() - dir := filename[0:strings.LastIndex(filename, string(os.PathSeparator))] - if err := os.MkdirAll(dir, 0750); err != nil { - panic(err) - } - if err := ioutil.WriteFile(filename, bytes, 0666); err != nil { - panic(err) - } - return bytes -} diff --git a/gapidapk/android/apk/BUILD.bazel b/gapidapk/android/apk/BUILD.bazel index 25a9177a1c..de57682171 100644 --- a/gapidapk/android/apk/BUILD.bazel +++ b/gapidapk/android/apk/BUILD.bazel @@ -21,7 +21,6 @@ _NATIVE_LIBRARIES = { "VkLayer_DebugMarker": "//core/vulkan/vk_debug_marker_layer/apk", "VkLayer_MemoryTracker": "//core/vulkan/vk_memory_tracker_layer/apk", "gapii": "//gapii/apk", - "interceptor": "//gapii/apk", "VkLayer_GraphicsSpy": "//gapii/apk", "gapir": "//cmd/gapir/apk", "vulkan_sample": "//cmd/vulkan_sample/apk", diff --git a/gapii/apk/BUILD.bazel b/gapii/apk/BUILD.bazel index 1ae86bb10f..19bdc6873f 100644 --- a/gapii/apk/BUILD.bazel +++ b/gapii/apk/BUILD.bazel @@ -20,15 +20,6 @@ android_native( deps = ["//gapii/cc:libgapii_android"], ) -android_native( - name = "interceptor", - visibility = ["//visibility:public"], - deps = select({ - "//tools/build:libinterceptor-from-source": ["//gapii/interceptor-lib/cc:libinterceptor"], - "//conditions:default": ["@libinterceptor//:libinterceptor"], - }), -) - android_native( name = "VkLayer_GraphicsSpy", visibility = ["//visibility:public"], diff --git a/gapii/cc/BUILD.bazel b/gapii/cc/BUILD.bazel index 1805082f33..c446220f97 100644 --- a/gapii/cc/BUILD.bazel +++ b/gapii/cc/BUILD.bazel @@ -14,20 +14,6 @@ load("//tools/build:rules.bzl", "android_dynamic_library", "apic_compile", "apic_template", "cc_copts", "cc_dynamic_library") -apic_template( - name = "gles_templated", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:api_imports.h", - "//gapis/api/templates:api_spy.h", - "//gapis/api/templates:api_spy.cpp", - "//gapis/api/templates:api_types.h", - "//gapis/api/templates:api_types.cpp", - "//gapis/api/gles/templates:api_exports.cpp", - "//gapis/api/gles/templates:api_imports.cpp", - ], -) - apic_template( name = "vulkan_templated", api = "//gapis/api/vulkan:api", @@ -43,59 +29,16 @@ apic_template( ], ) -apic_template( - name = "gvr_templated", - api = "//gapis/api/gvr:api", - templates = [ - "//gapis/api/templates:api_imports.h", - "//gapis/api/templates:api_spy.h", - "//gapis/api/templates:api_spy.cpp", - "//gapis/api/templates:api_types.h", - "//gapis/api/templates:api_types.cpp", - "//gapis/api/gvr/templates:api_exports.cpp", - "//gapis/api/gvr/templates:api_exports.h", - "//gapis/api/gvr/templates:api_imports.cpp", - ], -) - apic_compile( name = "apis_compiled", apis = [ - "//gapis/api/gles:api", "//gapis/api/vulkan:api", - "//gapis/api/gvr:api", ], emit = ["encode"], namespace = "gapii", optimize = True, ) -apic_template( - name = "gvr_install", - api = "//gapis/api/gvr:api", - templates = [ - "//gapis/api/gvr/templates:api_install.cpp", - ], -) - -apic_template( - name = "osx_opengl_framework", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:opengl_framework_exports.cpp", - ], -) - -apic_template( - name = "windows_opengl32", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:opengl32_resolve.cpp", - #TODO "//gapis/api/templates:opengl32_exports.def" - #TODO "//gapis/api/templates:opengl32_x64.asm", - ], -) - cc_library( name = "cc", srcs = glob( @@ -108,21 +51,10 @@ cc_library( "*_test.cpp", ], ) + select({ - "//tools/build:linux": [], "//tools/build:darwin": [":osx_opengl_framework"], - "//tools/build:windows": [":windows_opengl32"] + glob([ - "windows/*.cpp", - "windows/*.h", - ]), - # Android - "//conditions:default": glob([ - "android/*.cpp", - "android/*.h", - ]) + [":gvr_install"], + "//conditions:default": [], }) + [ ":apis_compiled", - ":gles_templated", - ":gvr_templated", ":vulkan_templated", ], copts = cc_copts() + select({ @@ -152,7 +84,6 @@ cc_library( "//core/os/device/deviceinfo/cc", "//gapil/runtime/cc", "//gapis/api:api_cc_proto", - "//gapis/api/gles/gles_pb:extras_cc_proto", "//gapis/capture:capture_cc_proto", "//gapis/memory/memory_pb:memory_pb_cc_proto", "@com_google_protobuf//:protobuf", diff --git a/gapii/cc/android/gles_layer.cpp b/gapii/cc/android/gles_layer.cpp deleted file mode 100644 index 8866321f07..0000000000 --- a/gapii/cc/android/gles_layer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2019 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/gles_exports.h" -#include "gapii/cc/spy.h" - -#include "core/cc/get_gles_proc_address.h" - -namespace { - -typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESS)(void*, const char*); - -PFNEGLGETNEXTLAYERPROCADDRESS g_next_layer_proc_addr = nullptr; -void* g_layer_id = nullptr; - -void* get_next_gles_proc_address(const char* name) { - return g_next_layer_proc_addr(g_layer_id, name); -} - -} // anonymous namespace - -extern "C" { - -void AndroidGLESLayer_Initialize( - void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESS get_next_layer_proc_address) { - GAPID_INFO("GLES Layer: InitializeLayer(%p, %p)", layer_id, - get_next_layer_proc_address); - g_layer_id = layer_id; - g_next_layer_proc_addr = get_next_layer_proc_address; - core::GetGlesProcAddress = &get_next_gles_proc_address; -} - -void* AndroidGLESLayer_GetProcAddress(const char* name, void* next) { - GAPID_DEBUG("GLES Layer: GetProcAddress(%s, %p)", name, next); - for (int i = 0; gapii::kGLESExports[i].mName != NULL; ++i) { - if (strcmp(name, gapii::kGLESExports[i].mName) == 0) { - return gapii::kGLESExports[i].mFunc; - } - } - GAPID_WARNING("Unhandled GLES function '%s'", name); - return next; -} - -} // extern "C" diff --git a/gapii/cc/android/gvr_install.h b/gapii/cc/android/gvr_install.h deleted file mode 100644 index c8cf0b4d59..0000000000 --- a/gapii/cc/android/gvr_install.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GAPII_ANDROID_GVR_INSTALL_H -#define GAPII_ANDROID_GVR_INSTALL_H - -namespace gapii { - -class Installer; -class GvrImports; - -// install_gvr installs interceptor hooks into all the GVR functions. -bool install_gvr(Installer* installer, void* gvr_lib, GvrImports* imports); - -} // namespace gapii - -#endif // GAPII_ANDROID_GVR_INSTALL_H diff --git a/gapii/cc/android/installer.cpp b/gapii/cc/android/installer.cpp deleted file mode 100644 index e4f28a064b..0000000000 --- a/gapii/cc/android/installer.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "installer.h" -#include "../gles_exports.h" - -#include "core/cc/assert.h" -#include "core/cc/get_gles_proc_address.h" -#include "core/cc/log.h" - -#include -#include - -#include - -#if defined(__LP64__) -#define SYSTEM_LIB_PATH "/system/lib64/" -#else -#define SYSTEM_LIB_PATH "/system/lib/" -#endif - -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - -extern "C" { -// For this to function on Android the entry-point names for GetDeviceProcAddr -// and GetInstanceProcAddr must be ${layer_name}/Get*ProcAddr. -// This is a bit surprising given that we *MUST* also export -// vkEnumerate*Layers without any prefix. - -extern void gapid_vkGetDeviceProcAddr(); -extern void gapid_vkGetInstanceProcAddr(); -extern void gapid_vkEnumerateInstanceLayerProperties(); -extern void gapid_vkEnumerateInstanceExtensionProperties(); -extern void gapid_vkEnumerateDeviceLayerProperties(); -extern void gapid_vkEnumerateDeviceExtensionProperties(); -} - -namespace { - -// -// Run the installer automatically when the library is loaded. -// -// This is done so the only modification needed to a Java app is a call to -// load library in the main activity: -// -// static { -// System.loadLibrary("libgapii.so"); -// } -// -// As this means that the code runs before main, care needs to be taken to -// avoid using any other load time initialized globals, since they may not -// have been initialized yet. -// - -typedef void*(InitializeInterceptorFunc)(); -typedef void(TerminateInterceptorFunc)(void* interceptor); -typedef bool(InterceptFunctionFunc)(void* interceptor, void* old_function, - const void* new_function, - void** callback_function, - void (*error_callback)(void*, const char*), - void* error_callback_baton); - -InitializeInterceptorFunc* gInitializeInterceptor = nullptr; -TerminateInterceptorFunc* gTerminateInterceptor = nullptr; -void* gInterceptor = nullptr; -InterceptFunctionFunc* gInterceptFunction = nullptr; -std::unordered_map gCallbacks; -const char* gDriverPaths[] = { - SYSTEM_LIB_PATH "libGLES.so", SYSTEM_LIB_PATH "libEGL.so", - SYSTEM_LIB_PATH "libGLESv1_CM.so", SYSTEM_LIB_PATH "libGLESv2.so", - SYSTEM_LIB_PATH "libGLESv3.so", -}; - -void* resolveCallback(const char* name) { - if (void* ptr = gCallbacks[name]) { - return ptr; - } - if (strcmp(name, "gapid_vkGetDeviceProcAddr") == 0) { - return reinterpret_cast(&gapid_vkGetDeviceProcAddr); - } else if (strcmp(name, "gapid_vkGetInstanceProcAddr") == 0) { - return reinterpret_cast(&gapid_vkGetInstanceProcAddr); - } else if (strcmp(name, "gapid_vkEnumerateInstanceLayerProperties") == 0) { - return reinterpret_cast(&gapid_vkEnumerateInstanceLayerProperties); - } else if (strcmp(name, "gapid_vkEnumerateInstanceExtensionProperties") == - 0) { - return reinterpret_cast( - &gapid_vkEnumerateInstanceExtensionProperties); - } else if (strcmp(name, "gapid_vkEnumerateDeviceLayerProperties") == 0) { - return reinterpret_cast(&gapid_vkEnumerateDeviceLayerProperties); - } else if (strcmp(name, "gapid_vkEnumerateDeviceExtensionProperties") == 0) { - return reinterpret_cast(&gapid_vkEnumerateDeviceExtensionProperties); - } - GAPID_WARNING("%s was requested, but cannot be traced.", name); - return nullptr; -} - -void recordInterceptorError(void*, const char* message) { - GAPID_WARNING("Interceptor error: %s", message); -} - -} // anonymous namespace - -namespace gapii { - -Installer::Installer(const char* libInterceptorPath) { - GAPID_INFO("Installing GAPII hooks...") - - auto lib = dlopen(libInterceptorPath, RTLD_NOW); - if (lib == nullptr) { - GAPID_FATAL("Couldn't load interceptor library from: %s: %s", - libInterceptorPath, dlerror()); - } - - gInitializeInterceptor = reinterpret_cast( - dlsym(lib, "InitializeInterceptor")); - gTerminateInterceptor = reinterpret_cast( - dlsym(lib, "TerminateInterceptor")); - gInterceptFunction = - reinterpret_cast(dlsym(lib, "InterceptFunction")); - - if (gInitializeInterceptor == nullptr || gTerminateInterceptor == nullptr || - gInterceptFunction == nullptr) { - GAPID_FATAL( - "Couldn't resolve the interceptor methods. " - "Did you forget to load libinterceptor.so before libgapii.so?\n" - "gInitializeInterceptor = %p\n" - "gTerminateInterceptor = %p\n" - "gInterceptFunction = %p\n", - gInitializeInterceptor, gTerminateInterceptor, gInterceptFunction); - } - - GAPID_INFO("Interceptor functions resolved") - - GAPID_INFO("Calling gInitializeInterceptor at %p...", gInitializeInterceptor); - gInterceptor = gInitializeInterceptor(); - GAPID_ASSERT(gInterceptor != nullptr); - - // Patch the driver to trampoline to the spy for all OpenGL ES functions. - GAPID_INFO("Installing OpenGL ES hooks..."); - install_gles(); - - // Switch to using the callbacks instead of the patched driver functions. - core::GetGlesProcAddress = resolveCallback; - - GAPID_INFO("OpenGL ES hooks successfully installed"); -} - -Installer::~Installer() { gTerminateInterceptor(gInterceptor); } - -void* Installer::install(void* func_import, const void* func_export) { - void* callback = nullptr; - if (!gInterceptFunction(gInterceptor, func_import, func_export, &callback, - &recordInterceptorError, nullptr)) { - return nullptr; - } - return callback; -} - -void Installer::install_gles() { - // Start by loading all the drivers. - void* drivers[NELEM(gDriverPaths)]; - for (int i = 0; i < NELEM(gDriverPaths); ++i) { - drivers[i] = dlopen(gDriverPaths[i], RTLD_NOW | RTLD_LOCAL); - } - - struct func { - const char* name; - void* func_export; - }; - - // Now resolve all the imported functions. We do this early so that - // the function resolver doesn't end up using patched functions. - std::unordered_map functions; - for (int i = 0; gapii::kGLESExports[i].mName != nullptr; ++i) { - const char* name = gapii::kGLESExports[i].mName; - void* func_export = gapii::kGLESExports[i].mFunc; - bool import_found = false; - for (int i = 0; i < NELEM(gDriverPaths); ++i) { - if (void* func_import = dlsym(drivers[i], name)) { - import_found = true; - functions[func_import] = func{name, func_export}; - } - } - if (void* func_import = core::GetGlesProcAddress(name)) { - import_found = true; - functions[func_import] = func{name, func_export}; - } - if (!import_found) { - // Don't export this function if the driver didn't export it. - gapii::kGLESExports[i].mFunc = nullptr; - } - } - - // Now patch each of the functions. - for (auto it : functions) { - void* func_import = it.first; - void* func_export = it.second.func_export; - const char* name = it.second.name; - GAPID_DEBUG("Patching '%s' at %p with %p...", name, func_import, - func_export); - if (auto callback = install(func_import, func_export)) { - GAPID_DEBUG("Replaced function %s at %p with %p (callback %p)", name, - func_import, func_export, callback); - gCallbacks[name] = callback; - } else { - GAPID_ERROR("Couldn't intercept function %s at %p", name, func_import); - } - } -} - -} // namespace gapii diff --git a/gapii/cc/android/installer.h b/gapii/cc/android/installer.h deleted file mode 100644 index 019ac31152..0000000000 --- a/gapii/cc/android/installer.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPII_ANDROID_INSTALLER_H -#define GAPII_ANDROID_INSTALLER_H - -namespace gapii { - -class Installer { - public: - Installer(const char* libInterceptorPath); - ~Installer(); - - // install_function installs a hook into func_import to call func_export. - // The returned function allows func_export to call back to the original - // function that was at func_import. - void* install(void* func_import, const void* func_export); - - private: - void install_gles(); -}; - -} // namespace gapii - -#endif // GAPII_ANDROID_INSTALLER_H diff --git a/gapii/cc/gapii_android.exports b/gapii/cc/gapii_android.exports index 45ed291cab..3444891bc4 100644 --- a/gapii/cc/gapii_android.exports +++ b/gapii/cc/gapii_android.exports @@ -1,6 +1,4 @@ JNI_OnLoad -AndroidGLESLayer_GetProcAddress -AndroidGLESLayer_Initialize gapid_vkGetDeviceProcAddr gapid_vkGetInstanceProcAddr gapid_vkEnumerateInstanceLayerProperties diff --git a/gapii/cc/gles_context.cpp b/gapii/cc/gles_context.cpp deleted file mode 100644 index 5f60bf1d38..0000000000 --- a/gapii/cc/gles_context.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/gles_spy.h" - -#include -#include -#include - -#define GET_SHADER_PRECISION_FORMAT(shader_type, precision_type, format) \ - do { \ - mImports.glGetShaderPrecisionFormat(shader_type, precision_type, \ - &(format).mMinRange, \ - &(format).mPrecision); \ - if (uint32_t err = mImports.glGetError()) { \ - GAPID_WARNING("glGetShaderPrecisionFormat(" #shader_type \ - ", " #precision_type \ - ") " \ - "gave error 0x%x", \ - err); \ - } \ - } while (false) - -#define GET(func, name, ...) \ - do { \ - mImports.func(name, __VA_ARGS__); \ - if (uint32_t err = mImports.glGetError()) { \ - GAPID_WARNING(#func "(" #name ") gave error 0x%x", err); \ - } \ - } while (false) - -#define GET_STRING(name, out) \ - do { \ - auto str = mImports.glGetString(name); \ - if (uint32_t err = mImports.glGetError()) { \ - GAPID_WARNING("glGetString(" #name ") gave error 0x%x", err); \ - } else if (str == nullptr) { \ - GAPID_WARNING("glGetString(" #name ") returned null w/o error"); \ - } else { \ - *out = gapil::String(arena(), reinterpret_cast(str)); \ - } \ - } while (false) - -namespace gapii { - -using namespace gapii::GLenum; - -void GlesSpy::getContextConstants(Constants& out) { - // Get essential constants which we always need regardless of version. - GET_STRING(GL_RENDERER, &out.mRenderer); - GET_STRING(GL_SHADING_LANGUAGE_VERSION, &out.mShadingLanguageVersion); - GET_STRING(GL_VENDOR, &out.mVendor); - GET_STRING(GL_VERSION, &out.mVersion); - - GLint major_version = 0; - GLint minor_version = 0; - if (out.mShadingLanguageVersion.length() == 0) { - major_version = 1; - } else { - mImports.glGetError(); // Clear error state. - mImports.glGetIntegerv(GL_MAJOR_VERSION, &major_version); - mImports.glGetIntegerv(GL_MINOR_VERSION, &minor_version); - if (mImports.glGetError() != GL_NO_ERROR) { - // GL_MAJOR_VERSION/GL_MINOR_VERSION were introduced in GLES 3.0, - // so if the commands returned error we assume it is GLES 2.0. - major_version = 2; - minor_version = 0; - } - } - out.mMajorVersion = major_version; - out.mMinorVersion = minor_version; - - if (major_version >= 3) { - int32_t c; - GET(glGetIntegerv, GL_NUM_EXTENSIONS, &c); - for (int32_t i = 0; i < c; i++) { - auto ext = reinterpret_cast( - mImports.glGetStringi(GL_EXTENSIONS, i)); - out.mExtensions[i] = gapil::String(arena(), ext); - if (uint32_t err = mImports.glGetError()) { - GAPID_WARNING("glGetStringi(GL_EXTENSIONS, %d) gave error 0x%x", i, - err); - } - } - } else { - std::string extensions = - reinterpret_cast(mImports.glGetString(GL_EXTENSIONS)); - if (uint32_t err = mImports.glGetError()) { - GAPID_WARNING("glGetString(GL_EXTENSIONS) gave error 0x%x", err); - } - - std::istringstream iss(extensions); - std::string extension; - while (std::getline(iss, extension, ' ')) { - out.mExtensions[out.mExtensions.count()] = - gapil::String(arena(), extension.c_str()); - } - } - - bool gles20 = major_version >= 2; - bool gles30 = - (major_version > 3) || (major_version == 3 && minor_version >= 0); - bool gles31 = - (major_version > 3) || (major_version == 3 && minor_version >= 1); - bool gles32 = - (major_version > 3) || (major_version == 3 && minor_version >= 2); - - // Constants defined in version 2.0.25 (November 2, 2010) - if (gles20) { - GET(glGetFloatv, GL_ALIASED_LINE_WIDTH_RANGE, out.mAliasedLineWidthRange); - GET(glGetFloatv, GL_ALIASED_POINT_SIZE_RANGE, out.mAliasedPointSizeRange); - GET(glGetIntegerv, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, - &out.mMaxCombinedTextureImageUnits); - GET(glGetIntegerv, GL_MAX_CUBE_MAP_TEXTURE_SIZE, - &out.mMaxCubeMapTextureSize); - GET(glGetIntegerv, GL_MAX_FRAGMENT_UNIFORM_VECTORS, - &out.mMaxFragmentUniformVectors); - GET(glGetIntegerv, GL_MAX_RENDERBUFFER_SIZE, &out.mMaxRenderbufferSize); - GET(glGetIntegerv, GL_MAX_TEXTURE_IMAGE_UNITS, &out.mMaxTextureImageUnits); - GET(glGetIntegerv, GL_MAX_TEXTURE_SIZE, &out.mMaxTextureSize); - GET(glGetIntegerv, GL_MAX_VARYING_VECTORS, &out.mMaxVaryingVectors); - GET(glGetIntegerv, GL_MAX_VERTEX_ATTRIBS, &out.mMaxVertexAttribs); - GET(glGetIntegerv, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, - &out.mMaxVertexTextureImageUnits); - GET(glGetIntegerv, GL_MAX_VERTEX_UNIFORM_VECTORS, - &out.mMaxVertexUniformVectors); - GET(glGetIntegerv, GL_MAX_VIEWPORT_DIMS, out.mMaxViewportDims); - GET(glGetBooleanv, GL_SHADER_COMPILER, &out.mShaderCompiler); - GET(glGetIntegerv, GL_SUBPIXEL_BITS, &out.mSubpixelBits); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_LOW_FLOAT, - out.mVertexShaderPrecisionFormat.mLowFloat); - GET_SHADER_PRECISION_FORMAT(GL_FRAGMENT_SHADER, GL_LOW_FLOAT, - out.mFragmentShaderPrecisionFormat.mLowFloat); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_MEDIUM_FLOAT, - out.mVertexShaderPrecisionFormat.mMediumFloat); - GET_SHADER_PRECISION_FORMAT( - GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, - out.mFragmentShaderPrecisionFormat.mMediumFloat); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_HIGH_FLOAT, - out.mVertexShaderPrecisionFormat.mHighFloat); - GET_SHADER_PRECISION_FORMAT(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, - out.mFragmentShaderPrecisionFormat.mHighFloat); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_LOW_INT, - out.mVertexShaderPrecisionFormat.mLowInt); - GET_SHADER_PRECISION_FORMAT(GL_FRAGMENT_SHADER, GL_LOW_INT, - out.mFragmentShaderPrecisionFormat.mLowInt); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_MEDIUM_INT, - out.mVertexShaderPrecisionFormat.mMediumInt); - GET_SHADER_PRECISION_FORMAT(GL_FRAGMENT_SHADER, GL_MEDIUM_INT, - out.mFragmentShaderPrecisionFormat.mMediumInt); - GET_SHADER_PRECISION_FORMAT(GL_VERTEX_SHADER, GL_HIGH_INT, - out.mVertexShaderPrecisionFormat.mHighInt); - GET_SHADER_PRECISION_FORMAT(GL_FRAGMENT_SHADER, GL_HIGH_INT, - out.mFragmentShaderPrecisionFormat.mHighInt); - - GLint count = 0; - std::vector buf; - GET(glGetIntegerv, GL_NUM_COMPRESSED_TEXTURE_FORMATS, &count); - buf.resize(count); - GET(glGetIntegerv, GL_COMPRESSED_TEXTURE_FORMATS, &buf[0]); - for (GLint i = 0; i < count; i++) { - out.mCompressedTextureFormats[i] = buf[i]; - } - - count = 0; - GET(glGetIntegerv, GL_NUM_SHADER_BINARY_FORMATS, &count); - buf.resize(count); - GET(glGetIntegerv, GL_SHADER_BINARY_FORMATS, &buf[0]); - for (GLint i = 0; i < count; i++) { - out.mShaderBinaryFormats[i] = buf[i]; - } - } - - // Constants defined in version 3.0.4 (August 27, 2014) - if (gles30) { - GET(glGetIntegerv, GL_MAX_3D_TEXTURE_SIZE, &out.mMax3dTextureSize); - GET(glGetIntegerv, GL_MAX_ARRAY_TEXTURE_LAYERS, - &out.mMaxArrayTextureLayers); - GET(glGetIntegerv, GL_MAX_COLOR_ATTACHMENTS, &out.mMaxColorAttachments); - GET(glGetInteger64v, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, - &out.mMaxCombinedFragmentUniformComponents); - GET(glGetIntegerv, GL_MAX_COMBINED_UNIFORM_BLOCKS, - &out.mMaxCombinedUniformBlocks); - GET(glGetInteger64v, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, - &out.mMaxCombinedVertexUniformComponents); - GET(glGetIntegerv, GL_MAX_DRAW_BUFFERS, &out.mMaxDrawBuffers); - GET(glGetIntegerv, GL_MAX_ELEMENTS_INDICES, &out.mMaxElementsIndices); - GET(glGetIntegerv, GL_MAX_ELEMENTS_VERTICES, &out.mMaxElementsVertices); - GET(glGetInteger64v, GL_MAX_ELEMENT_INDEX, &out.mMaxElementIndex); - GET(glGetIntegerv, GL_MAX_FRAGMENT_INPUT_COMPONENTS, - &out.mMaxFragmentInputComponents); - GET(glGetIntegerv, GL_MAX_FRAGMENT_UNIFORM_BLOCKS, - &out.mMaxFragmentUniformBlocks); - GET(glGetIntegerv, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, - &out.mMaxFragmentUniformComponents); - GET(glGetIntegerv, GL_MAX_PROGRAM_TEXEL_OFFSET, - &out.mMaxProgramTexelOffset); - GET(glGetInteger64v, GL_MAX_SERVER_WAIT_TIMEOUT, - &out.mMaxServerWaitTimeout); - GET(glGetFloatv, GL_MAX_TEXTURE_LOD_BIAS, &out.mMaxTextureLodBias); - GET(glGetIntegerv, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, - &out.mMaxTransformFeedbackInterleavedComponents); - GET(glGetIntegerv, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, - &out.mMaxTransformFeedbackSeparateAttribs); - GET(glGetIntegerv, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, - &out.mMaxTransformFeedbackSeparateComponents); - GET(glGetInteger64v, GL_MAX_UNIFORM_BLOCK_SIZE, &out.mMaxUniformBlockSize); - GET(glGetIntegerv, GL_MAX_UNIFORM_BUFFER_BINDINGS, - &out.mMaxUniformBufferBindings); - GET(glGetIntegerv, GL_MAX_VARYING_COMPONENTS, &out.mMaxVaryingComponents); - GET(glGetIntegerv, GL_MAX_VERTEX_OUTPUT_COMPONENTS, - &out.mMaxVertexOutputComponents); - GET(glGetIntegerv, GL_MAX_VERTEX_UNIFORM_BLOCKS, - &out.mMaxVertexUniformBlocks); - GET(glGetIntegerv, GL_MAX_VERTEX_UNIFORM_COMPONENTS, - &out.mMaxVertexUniformComponents); - GET(glGetIntegerv, GL_MIN_PROGRAM_TEXEL_OFFSET, - &out.mMinProgramTexelOffset); - GET(glGetIntegerv, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, - &out.mUniformBufferOffsetAlignment); - - GLint count = 0; - std::vector buf; - GET(glGetIntegerv, GL_NUM_PROGRAM_BINARY_FORMATS, &count); - buf.resize(count); - GET(glGetIntegerv, GL_PROGRAM_BINARY_FORMATS, &buf[0]); - for (GLint i = 0; i < count; i++) { - out.mProgramBinaryFormats[i] = buf[i]; - } - } - - // Constants defined in version 3.1 (April 29, 2015) - if (gles31) { - GET(glGetIntegerv, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, - &out.mMaxAtomicCounterBufferBindings); - GET(glGetIntegerv, GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, - &out.mMaxAtomicCounterBufferSize); - GET(glGetIntegerv, GL_MAX_COLOR_TEXTURE_SAMPLES, - &out.mMaxColorTextureSamples); - GET(glGetIntegerv, GL_MAX_COMBINED_ATOMIC_COUNTERS, - &out.mMaxCombinedAtomicCounters); - GET(glGetIntegerv, GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, - &out.mMaxCombinedAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, - &out.mMaxCombinedComputeUniformComponents); - GET(glGetIntegerv, GL_MAX_COMBINED_IMAGE_UNIFORMS, - &out.mMaxCombinedImageUniforms); - GET(glGetIntegerv, GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, - &out.mMaxCombinedShaderOutputResources); - GET(glGetIntegerv, GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, - &out.mMaxCombinedShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_COMPUTE_ATOMIC_COUNTERS, - &out.mMaxComputeAtomicCounters); - GET(glGetIntegerv, GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, - &out.mMaxComputeAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_COMPUTE_IMAGE_UNIFORMS, - &out.mMaxComputeImageUniforms); - GET(glGetIntegerv, GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, - &out.mMaxComputeShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, - &out.mMaxComputeSharedMemorySize); - GET(glGetIntegerv, GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, - &out.mMaxComputeTextureImageUnits); - GET(glGetIntegerv, GL_MAX_COMPUTE_UNIFORM_BLOCKS, - &out.mMaxComputeUniformBlocks); - GET(glGetIntegerv, GL_MAX_COMPUTE_UNIFORM_COMPONENTS, - &out.mMaxComputeUniformComponents); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, - &out.mMaxComputeWorkGroupCount[0]); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, - &out.mMaxComputeWorkGroupCount[1]); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, - &out.mMaxComputeWorkGroupCount[2]); - GET(glGetIntegerv, GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, - &out.mMaxComputeWorkGroupInvocations); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, - &out.mMaxComputeWorkGroupSize[0]); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, - &out.mMaxComputeWorkGroupSize[1]); - GET(glGetIntegeri_v, GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, - &out.mMaxComputeWorkGroupSize[2]); - GET(glGetIntegerv, GL_MAX_DEPTH_TEXTURE_SAMPLES, - &out.mMaxDepthTextureSamples); - GET(glGetIntegerv, GL_MAX_FRAGMENT_ATOMIC_COUNTERS, - &out.mMaxFragmentAtomicCounters); - GET(glGetIntegerv, GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, - &out.mMaxFragmentAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_FRAGMENT_IMAGE_UNIFORMS, - &out.mMaxFragmentImageUniforms); - GET(glGetIntegerv, GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, - &out.mMaxFragmentShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_FRAMEBUFFER_HEIGHT, &out.mMaxFramebufferHeight); - GET(glGetIntegerv, GL_MAX_FRAMEBUFFER_SAMPLES, &out.mMaxFramebufferSamples); - GET(glGetIntegerv, GL_MAX_FRAMEBUFFER_WIDTH, &out.mMaxFramebufferWidth); - GET(glGetIntegerv, GL_MAX_IMAGE_UNITS, &out.mMaxImageUnits); - GET(glGetIntegerv, GL_MAX_INTEGER_SAMPLES, &out.mMaxIntegerSamples); - GET(glGetIntegerv, GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, - &out.mMaxProgramTextureGatherOffset); - GET(glGetIntegerv, GL_MAX_SAMPLE_MASK_WORDS, &out.mMaxSampleMaskWords); - GET(glGetInteger64v, GL_MAX_SHADER_STORAGE_BLOCK_SIZE, - &out.mMaxShaderStorageBlockSize); - GET(glGetIntegerv, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, - &out.mMaxShaderStorageBufferBindings); - GET(glGetIntegerv, GL_MAX_UNIFORM_LOCATIONS, &out.mMaxUniformLocations); - GET(glGetIntegerv, GL_MAX_VERTEX_ATOMIC_COUNTERS, - &out.mMaxVertexAtomicCounters); - GET(glGetIntegerv, GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, - &out.mMaxVertexAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_VERTEX_ATTRIB_BINDINGS, - &out.mMaxVertexAttribBindings); - GET(glGetIntegerv, GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, - &out.mMaxVertexAttribRelativeOffset); - GET(glGetIntegerv, GL_MAX_VERTEX_ATTRIB_STRIDE, - &out.mMaxVertexAttribStride); - GET(glGetIntegerv, GL_MAX_VERTEX_IMAGE_UNIFORMS, - &out.mMaxVertexImageUniforms); - GET(glGetIntegerv, GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, - &out.mMaxVertexShaderStorageBlocks); - GET(glGetIntegerv, GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, - &out.mMinProgramTextureGatherOffset); - GET(glGetIntegerv, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, - &out.mShaderStorageBufferOffsetAlignment); - } - - // Constants defined in version 3.2 (June 15, 2016) - if (gles32) { - GET(glGetIntegerv, GL_CONTEXT_FLAGS, &out.mContextFlags); - GET(glGetIntegerv, GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, - &out.mFragmentInterpolationOffsetBits); - GET(glGetIntegerv, GL_LAYER_PROVOKING_VERTEX, - reinterpret_cast(&out.mLayerProvokingVertex)); - GET(glGetIntegerv, GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS, - &out.mMaxCombinedGeometryUniformComponents); - GET(glGetIntegerv, GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS, - &out.mMaxCombinedTessControlUniformComponents); - GET(glGetIntegerv, GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS, - &out.mMaxCombinedTessEvaluationUniformComponents); - GET(glGetIntegerv, GL_MAX_DEBUG_GROUP_STACK_DEPTH, - &out.mMaxDebugGroupStackDepth); - GET(glGetIntegerv, GL_MAX_DEBUG_LOGGED_MESSAGES, - &out.mMaxDebugLoggedMessages); - GET(glGetIntegerv, GL_MAX_DEBUG_MESSAGE_LENGTH, - &out.mMaxDebugMessageLength); - GET(glGetFloatv, GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, - &out.mMaxFragmentInterpolationOffset); - GET(glGetIntegerv, GL_MAX_FRAMEBUFFER_LAYERS, &out.mMaxFramebufferLayers); - GET(glGetIntegerv, GL_MAX_GEOMETRY_ATOMIC_COUNTERS, - &out.mMaxGeometryAtomicCounters); - GET(glGetIntegerv, GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS, - &out.mMaxGeometryAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_GEOMETRY_IMAGE_UNIFORMS, - &out.mMaxGeometryImageUniforms); - GET(glGetIntegerv, GL_MAX_GEOMETRY_INPUT_COMPONENTS, - &out.mMaxGeometryInputComponents); - GET(glGetIntegerv, GL_MAX_GEOMETRY_OUTPUT_COMPONENTS, - &out.mMaxGeometryOutputComponents); - GET(glGetIntegerv, GL_MAX_GEOMETRY_OUTPUT_VERTICES, - &out.mMaxGeometryOutputVertices); - GET(glGetIntegerv, GL_MAX_GEOMETRY_SHADER_INVOCATIONS, - &out.mMaxGeometryShaderInvocations); - GET(glGetIntegerv, GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, - &out.mMaxGeometryShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, - &out.mMaxGeometryTextureImageUnits); - GET(glGetIntegerv, GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, - &out.mMaxGeometryTotalOutputComponents); - GET(glGetIntegerv, GL_MAX_GEOMETRY_UNIFORM_BLOCKS, - &out.mMaxGeometryUniformBlocks); - GET(glGetIntegerv, GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, - &out.mMaxGeometryUniformComponents); - GET(glGetIntegerv, GL_MAX_LABEL_LENGTH, &out.mMaxLabelLength); - GET(glGetIntegerv, GL_MAX_PATCH_VERTICES, &out.mMaxPatchVertices); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, - &out.mMaxTessControlAtomicCounters); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS, - &out.mMaxTessControlAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, - &out.mMaxTessControlImageUniforms); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_INPUT_COMPONENTS, - &out.mMaxTessControlInputComponents); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS, - &out.mMaxTessControlOutputComponents); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, - &out.mMaxTessControlShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS, - &out.mMaxTessControlTextureImageUnits); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS, - &out.mMaxTessControlTotalOutputComponents); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, - &out.mMaxTessControlUniformBlocks); - GET(glGetIntegerv, GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS, - &out.mMaxTessControlUniformComponents); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, - &out.mMaxTessEvaluationAtomicCounters); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS, - &out.mMaxTessEvaluationAtomicCounterBuffers); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, - &out.mMaxTessEvaluationImageUniforms); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS, - &out.mMaxTessEvaluationInputComponents); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS, - &out.mMaxTessEvaluationOutputComponents); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, - &out.mMaxTessEvaluationShaderStorageBlocks); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS, - &out.mMaxTessEvaluationTextureImageUnits); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, - &out.mMaxTessEvaluationUniformBlocks); - GET(glGetIntegerv, GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS, - &out.mMaxTessEvaluationUniformComponents); - GET(glGetIntegerv, GL_MAX_TESS_GEN_LEVEL, &out.mMaxTessGenLevel); - GET(glGetIntegerv, GL_MAX_TESS_PATCH_COMPONENTS, - &out.mMaxTessPatchComponents); - GET(glGetIntegerv, GL_MAX_TEXTURE_BUFFER_SIZE, &out.mMaxTextureBufferSize); - GET(glGetFloatv, GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, - &out.mMinFragmentInterpolationOffset); - GET(glGetFloatv, GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY, - &out.mMultisampleLineWidthGranularity); - GET(glGetFloatv, GL_MULTISAMPLE_LINE_WIDTH_RANGE, - out.mMultisampleLineWidthRange); - GET(glGetBooleanv, GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED, - &out.mPrimitiveRestartForPatchesSupported); - GET(glGetIntegerv, GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, - &out.mTextureBufferOffsetAlignment); - GET(glGetIntegerv, GL_RESET_NOTIFICATION_STRATEGY, - &out.mResetNotificationStrategy); - } - - // Constants defined in extensions - GET(glGetFloatv, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, - &out.mMaxTextureMaxAnisotropyExt); - GET(glGetIntegerv, GL_MAX_VIEWS_OVR, &out.mMaxViewsExt); -} - -} // namespace gapii diff --git a/gapii/cc/gles_exports.h b/gapii/cc/gles_exports.h deleted file mode 100644 index 5ddf980463..0000000000 --- a/gapii/cc/gles_exports.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPII_GLES_EXPORTS_H -#define GAPII_GLES_EXPORTS_H - -namespace gapii { - -struct Symbol { - const char* mName; - void* mFunc; -}; - -extern Symbol kGLESExports[]; -} // namespace gapii - -#endif diff --git a/gapii/cc/gles_extras.cpp b/gapii/cc/gles_extras.cpp deleted file mode 100644 index 664e064890..0000000000 --- a/gapii/cc/gles_extras.cpp +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/gles_exports.h" -#include "gapii/cc/gles_spy.h" -#include "gapii/cc/gles_types.h" - -#include "gapis/api/gles/gles_pb/extras.pb.h" - -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif // __STDC_FORMAT_MACROS -#include - -#define ANDROID_NATIVE_MAKE_CONSTANT(a, b, c, d) \ - (((unsigned)(a) << 24) | ((unsigned)(b) << 16) | ((unsigned)(c) << 8) | \ - (unsigned)(d)) - -#define ANDROID_NATIVE_WINDOW_MAGIC \ - ANDROID_NATIVE_MAKE_CONSTANT('_', 'w', 'n', 'd') - -#define ANDROID_NATIVE_BUFFER_MAGIC \ - ANDROID_NATIVE_MAKE_CONSTANT('_', 'b', 'f', 'r') - -namespace gapii { - -// Handles GLES 2.0 and GLES 3.0 (the old reflection API) -static void GetProgramReflectionInfo_GLES20(GlesSpy* spy, - LinkProgramExtra* extra, - Program* p) { - using namespace GLenum; - auto resources = gapil::Ref::create(spy->arena()); - - const GLuint program = extra->mID; - const bool gles30 = - spy->mState.Version != nullptr && spy->mState.Version->mGLES30; - const auto& imports = spy->imports(); - - // Helper method to get property of program - auto getProgramiv = [&](uint32_t pname) { - GLint value = 0; - imports.glGetProgramiv(program, pname, &value); - return value; - }; - - // Allocate temporary buffer large enough to hold any of the returned strings. - int32_t maxLength = 0; - maxLength = std::max(maxLength, getProgramiv(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH)); - maxLength = std::max(maxLength, getProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH)); - if (gles30) { - maxLength = std::max(maxLength, - getProgramiv(GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH)); - } - maxLength += 16; // extra space for appending of array suffix - std::vector buffer(maxLength); - - auto getActiveUniformsiv = [&](GLuint i, uint32_t pname) { - GLint value = 0; - imports.glGetActiveUniformsiv(program, 1, &i, pname, &value); - return value; - }; - - int32_t activeUniforms = getProgramiv(GL_ACTIVE_UNIFORMS); - for (int32_t i = 0; i < activeUniforms; i++) { - auto res = gapil::Ref::create(spy->arena()); - - int32_t nameLength = 0; - imports.glGetActiveUniform(program, i, buffer.size(), &nameLength, - &res->mArraySize, &res->mType, buffer.data()); - res->mName = gapil::String(spy->arena(), buffer.data(), nameLength); - - if (gles30) { - res->mBlockIndex = getActiveUniformsiv(i, GL_UNIFORM_BLOCK_INDEX); - } else { - res->mBlockIndex = -1; - } - - if (res->mBlockIndex == -1) { - res->mLocations[0] = imports.glGetUniformLocation(program, buffer.data()); - if (nameLength >= 3 && - strcmp(buffer.data() + nameLength - 3, "[0]") == 0) { - nameLength -= 3; // Remove the "[0]" suffix of array - } - for (int32_t j = 1; j < res->mArraySize; j++) { - sprintf(buffer.data() + nameLength, "[%i]", j); // Append array suffix - res->mLocations[j] = - imports.glGetUniformLocation(program, buffer.data()); - } - } else { - auto layout = gapil::Ref::create(spy->arena()); - layout->mOffset = getActiveUniformsiv(i, GL_UNIFORM_OFFSET); - layout->mArrayStride = getActiveUniformsiv(i, GL_UNIFORM_ARRAY_STRIDE); - layout->mMatrixStride = getActiveUniformsiv(i, GL_UNIFORM_MATRIX_STRIDE); - layout->mIsRowMajor = getActiveUniformsiv(i, GL_UNIFORM_IS_ROW_MAJOR); - res->mLayout = std::move(layout); - } - - resources->mUniforms[i] = std::move(res); - } - - int32_t activeAttributes = 0; - activeAttributes = getProgramiv(GL_ACTIVE_ATTRIBUTES); - for (int32_t i = 0; i < activeAttributes; i++) { - auto res = gapil::Ref::create(spy->arena()); - - int32_t nameLength = 0; - imports.glGetActiveAttrib(program, i, buffer.size(), &nameLength, - &res->mArraySize, &res->mType, buffer.data()); - res->mName = gapil::String(spy->arena(), buffer.data(), nameLength); - res->mLocations[0] = imports.glGetAttribLocation(program, buffer.data()); - - resources->mProgramInputs[i] = std::move(res); - } - - int32_t activeUniformBlocks = 0; - if (gles30) { - auto getUniformBlockiv = [&](GLuint i, uint32_t pname) { - GLint value = 0; - imports.glGetActiveUniformBlockiv(program, i, pname, &value); - return value; - }; - - activeUniformBlocks = getProgramiv(GL_ACTIVE_UNIFORM_BLOCKS); - for (int32_t i = 0; i < activeUniformBlocks; i++) { - auto block = gapil::Ref::create(spy->arena()); - - int32_t nameLength = 0; - imports.glGetActiveUniformBlockName(program, i, buffer.size(), - &nameLength, buffer.data()); - block->mName = gapil::String(spy->arena(), buffer.data(), nameLength); - - block->mBinding = getUniformBlockiv(i, GL_UNIFORM_BLOCK_BINDING); - block->mDataSize = getUniformBlockiv(i, GL_UNIFORM_BLOCK_DATA_SIZE); - - auto usedBy = gapil::Ref::create(spy->arena()); - usedBy->mVertexShader = - getUniformBlockiv(i, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER); - usedBy->mFragmentShader = - getUniformBlockiv(i, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER); - block->mReferencedBy = std::move(usedBy); - - resources->mUniformBlocks[i] = std::move(block); - } - } - - extra->mActiveResources = std::move(resources); -} - -// Handles GLES 3.1 and GLES 3.2 (the new reflection API) -static void GetProgramReflectionInfo_GLES31(GlesSpy* spy, - LinkProgramExtra* extra, - Program* p) { - using namespace GLenum; - - const GLuint program = extra->mID; - const auto& imports = spy->imports(); - - const bool hasGeometryShader = p->mShaders.contains(GL_GEOMETRY_SHADER); - const bool hasTessControlShader = - p->mShaders.contains(GL_TESS_CONTROL_SHADER); - const bool hasTessEvaluationShader = - p->mShaders.contains(GL_TESS_EVALUATION_SHADER); - const bool hasComputeShader = p->mShaders.contains(GL_COMPUTE_SHADER); - - std::vector buffer; // Temporary buffer for getting string. - const int bufferSuffixSize = - 16; // Allocate a bit more extra space so we can append integer to name. - - // Helper method to get property of program - auto getProgramiv = [&](uint32_t pname) { - GLint value = 0; - imports.glGetProgramiv(program, pname, &value); - return value; - }; - - // Helper method to get property of program interface - auto getInterfaceiv = [&](uint32_t interface, uint32_t pname) { - GLint value = 0; - imports.glGetProgramInterfaceiv(program, interface, pname, &value); - return value; - }; - - // Helper method to get property of program resource - auto getResourceiv = [&](uint32_t interface, GLuint i, uint32_t pname) { - GLint value = 0; - imports.glGetProgramResourceiv(program, interface, i, 1, &pname, 1, nullptr, - &value); - return value; - }; - - // Helper method to get name of program resource - auto getResourceName = [&](uint32_t interface, GLuint i) { - GAPID_ASSERT(getResourceiv(interface, i, GL_NAME_LENGTH) <= - (int32_t)buffer.size()); - GLsizei length = 0; - imports.glGetProgramResourceName(program, interface, i, buffer.size(), - &length, buffer.data()); - return gapil::String(spy->arena(), buffer.data(), length); - }; - - // Helper method to get all locations of program resource - auto getResourceLocations = [&](uint32_t interface, const gapil::String& name, - GLint arraySize) { - U32ToGLint locations(spy->arena()); - locations[0] = imports.glGetProgramResourceLocation( - program, interface, reinterpret_cast(name.c_str())); - if (arraySize > 1) { - // Copy the array base name (without the [0] suffix) to the temporary - // buffer - size_t baseLength = name.length(); - if (baseLength >= 3 && - strcmp(name.c_str() + baseLength - 3, "[0]") == 0) { - baseLength -= 3; // Remove the "[0]" suffix of array - } - GAPID_ASSERT(baseLength + bufferSuffixSize <= buffer.size()); - memcpy(buffer.data(), name.c_str(), baseLength); - // Get location for each array element. - for (int32_t j = 1; j < arraySize; j++) { - snprintf(buffer.data() + baseLength, buffer.size(), "[%i]", - j); // Append array suffix - locations[j] = imports.glGetProgramResourceLocation(program, interface, - buffer.data()); - } - } - return locations; - }; - - // Helper method to get all referenced-by properties - auto getResourceUses = [&](uint32_t interface, GLuint i) { - auto usedBy = gapil::Ref::create(spy->arena()); - usedBy->mVertexShader = - getResourceiv(interface, i, GL_REFERENCED_BY_VERTEX_SHADER) != 0; - if (hasTessControlShader) { - usedBy->mTessControlShader = - getResourceiv(interface, i, GL_REFERENCED_BY_TESS_CONTROL_SHADER) != - 0; - } - if (hasTessEvaluationShader) { - usedBy->mTessEvaluationShader = - getResourceiv(interface, i, - GL_REFERENCED_BY_TESS_EVALUATION_SHADER) != 0; - } - if (hasGeometryShader) { - usedBy->mGeometryShader = - getResourceiv(interface, i, GL_REFERENCED_BY_GEOMETRY_SHADER) != 0; - } - usedBy->mFragmentShader = - getResourceiv(interface, i, GL_REFERENCED_BY_FRAGMENT_SHADER) != 0; - usedBy->mComputeShader = - getResourceiv(interface, i, GL_REFERENCED_BY_COMPUTE_SHADER) != 0; - return usedBy; - }; - - // Helper method to get all resource blocks of given type - auto getResourceBlocks = [&](uint32_t interface) { - U32ToProgramResourceBlock__R blocks(spy->arena()); - GLint count = getInterfaceiv(interface, GL_ACTIVE_RESOURCES); - if (interface != GL_ATOMIC_COUNTER_BUFFER) { - buffer.resize(getInterfaceiv(interface, GL_MAX_NAME_LENGTH) + - bufferSuffixSize); - } - for (int i = 0; i < count; i++) { - auto block = gapil::Ref::create(spy->arena()); - if (interface != GL_ATOMIC_COUNTER_BUFFER) { - block->mName = getResourceName(interface, i); - } - block->mBinding = getResourceiv(interface, i, GL_BUFFER_BINDING); - block->mDataSize = getResourceiv(interface, i, GL_BUFFER_DATA_SIZE); - block->mReferencedBy = getResourceUses(interface, i); - blocks[i] = std::move(block); - } - return blocks; - }; - - // Helper method to get all resources of given type - auto getResources = [&](uint32_t interface) { - // Helper flags for determining if property is applicable to this interface. - // Trying to get a property on the wrong interface will result in GL error. - const bool pi = (interface == GL_PROGRAM_INPUT); - const bool po = (interface == GL_PROGRAM_OUTPUT); - const bool u = (interface == GL_UNIFORM); - const bool bv = (interface == GL_BUFFER_VARIABLE); - - U32ToProgramResource__R resources(spy->arena()); - GLint count = getInterfaceiv(interface, GL_ACTIVE_RESOURCES); - buffer.resize(getInterfaceiv(interface, GL_MAX_NAME_LENGTH) + - bufferSuffixSize); - for (int i = 0; i < count; i++) { - auto resource = gapil::Ref::create(spy->arena()); - resource->mName = getResourceName(interface, i); - resource->mType = getResourceiv(interface, i, GL_TYPE); - resource->mArraySize = getResourceiv(interface, i, GL_ARRAY_SIZE); - - bool backedByBufferObject = false; - if (bv || u) { - resource->mBlockIndex = getResourceiv(interface, i, GL_BLOCK_INDEX); - backedByBufferObject |= (resource->mBlockIndex != -1); - } - if (u) { - resource->mAtomicCounterBufferIndex = - getResourceiv(interface, i, GL_ATOMIC_COUNTER_BUFFER_INDEX); - backedByBufferObject |= (resource->mAtomicCounterBufferIndex != -1); - } - if (bv || pi || po || u) { - resource->mReferencedBy = getResourceUses(interface, i); - } - if (backedByBufferObject) { - auto layout = gapil::Ref::create(spy->arena()); - if (bv || u) { - layout->mOffset = getResourceiv(interface, i, GL_OFFSET); - layout->mArrayStride = getResourceiv(interface, i, GL_ARRAY_STRIDE); - layout->mMatrixStride = getResourceiv(interface, i, GL_MATRIX_STRIDE); - layout->mIsRowMajor = getResourceiv(interface, i, GL_IS_ROW_MAJOR); - } - if (bv) { - layout->mTopLevelArraySize = - getResourceiv(interface, i, GL_TOP_LEVEL_ARRAY_SIZE); - layout->mTopLevelArrayStride = - getResourceiv(interface, i, GL_TOP_LEVEL_ARRAY_STRIDE); - } - resource->mLayout = std::move(layout); - } else { - if (pi || po || u) { - resource->mLocations = getResourceLocations( - interface, resource->mName, resource->mArraySize); - } - } - if ((pi || po) && (hasTessControlShader || hasTessEvaluationShader)) { - resource->mIsPerPatch = getResourceiv(interface, i, GL_IS_PER_PATCH); - } - - resources[i] = std::move(resource); - } - return resources; - }; - - /////////////////////////////////////////////////////////////////// - // Get the program state using the helper methods above // - /////////////////////////////////////////////////////////////////// - - // Get all active resources. - { - auto resources = gapil::Ref::create(spy->arena()); - resources->mProgramInputs = getResources(GL_PROGRAM_INPUT); - resources->mProgramOutputs = getResources(GL_PROGRAM_OUTPUT); - resources->mUniforms = getResources(GL_UNIFORM); - resources->mUniformBlocks = getResourceBlocks(GL_UNIFORM_BLOCK); - resources->mAtomicCounterBuffers = - getResourceBlocks(GL_ATOMIC_COUNTER_BUFFER); - resources->mBufferVariables = getResources(GL_BUFFER_VARIABLE); - resources->mShaderStorageBlocks = - getResourceBlocks(GL_SHADER_STORAGE_BLOCK); - resources->mTransformFeedbackVaryings = - getResources(GL_TRANSFORM_FEEDBACK_VARYING); - extra->mActiveResources = std::move(resources); - } - - // Get global layout qualifiers from shaders. - { - auto layout = gapil::Ref::create(spy->arena()); - - if (hasGeometryShader) { - layout->mGeometryVerticesOut = getProgramiv(GL_GEOMETRY_VERTICES_OUT); - layout->mGeometryInputType = getProgramiv(GL_GEOMETRY_INPUT_TYPE); - layout->mGeometryOutputType = getProgramiv(GL_GEOMETRY_OUTPUT_TYPE); - layout->mGeometryShaderInvocations = - getProgramiv(GL_GEOMETRY_SHADER_INVOCATIONS); - } - if (hasTessControlShader) { - layout->mTessControlOutputVertices = - getProgramiv(GL_TESS_CONTROL_OUTPUT_VERTICES); - } - if (hasTessEvaluationShader) { - layout->mTessGenMode = getProgramiv(GL_TESS_GEN_MODE); - layout->mTessGenSpacing = getProgramiv(GL_TESS_GEN_SPACING); - layout->mTessGenVertexOrder = getProgramiv(GL_TESS_GEN_VERTEX_ORDER); - layout->mTessGenPointMode = getProgramiv(GL_TESS_GEN_POINT_MODE); - } - if (hasComputeShader) { - GLint computeWorkGroupSize[3]; - imports.glGetProgramiv(program, GL_COMPUTE_WORK_GROUP_SIZE, - computeWorkGroupSize); - layout->mComputeWorkGroupSize[0] = computeWorkGroupSize[0]; - layout->mComputeWorkGroupSize[1] = computeWorkGroupSize[1]; - layout->mComputeWorkGroupSize[2] = computeWorkGroupSize[2]; - } - - extra->mShaderLayout = std::move(layout); - } -} - -// GetLinkProgramExtra is called by glLinkProgram and glProgramBinary -gapil::Ref GlesSpy::GetLinkProgramExtra( - CallObserver* observer, gapil::Ref ctx, gapil::Ref p, - gapil::Ref binary) { - using namespace GLenum; - - // TODO: It is kind of evil to call glGetError, as it modifies the driver - // state. - GlesSpy::mImports.glGetError(); // Clear error. - - const GLuint program = p->mID; - const bool gles31 = mState.Version != nullptr && mState.Version->mGLES31; - - // Helper method to get property of program - auto getProgramiv = [&](uint32_t pname) { - GLint value = 0; - mImports.glGetProgramiv(program, pname, &value); - return value; - }; - - auto extra = gapil::Ref::create(arena()); - extra->mID = program; - extra->mLinkStatus = getProgramiv(GL_LINK_STATUS); - - // Get info log string - std::vector buffer; // Temporary buffer for getting string. - buffer.resize(getProgramiv( - GL_INFO_LOG_LENGTH)); // Returned length includes null-terminator. - GLint infoLogLength = - 0; // Returned length by the command below excludes null-terminator. - mImports.glGetProgramInfoLog(program, buffer.size(), &infoLogLength, - buffer.data()); - extra->mInfoLog = gapil::String(arena(), buffer.data(), infoLogLength); - - // Get meta-data about the active resources generated by the compiler. - if (extra->mLinkStatus) { - // The API changed radically in GLES 3.1, so we need two distinct versions. - if (gles31) { - GetProgramReflectionInfo_GLES31(this, extra.get(), p.get()); - } else { - GetProgramReflectionInfo_GLES20(this, extra.get(), p.get()); - } - - // Add resources to the resource blocks that own them, for convenience. - auto* resources = extra->mActiveResources.get(); - for (auto& kvp : resources->mUniforms) { - auto& id = kvp.first; - auto& u = kvp.second; - if (u->mBlockIndex != -1) { - GAPID_ASSERT(resources->mUniformBlocks.contains(u->mBlockIndex)); - resources->mUniformBlocks[u->mBlockIndex]->mResources[id] = u; - } else { - resources->mDefaultUniformBlock[id] = u; - } - if (u->mAtomicCounterBufferIndex != -1) { - GAPID_ASSERT(resources->mAtomicCounterBuffers.contains( - u->mAtomicCounterBufferIndex)); - resources->mAtomicCounterBuffers[u->mAtomicCounterBufferIndex] - ->mResources[id] = u; - } - } - for (auto& kvp : resources->mBufferVariables) { - auto& id = kvp.first; - auto& u = kvp.second; - if (u->mBlockIndex != -1) { - GAPID_ASSERT(resources->mShaderStorageBlocks.contains(u->mBlockIndex)); - resources->mShaderStorageBlocks[u->mBlockIndex]->mResources[id] = u; - } - } - } - - // TODO: It is kind of evil to call glGetError, as it modifies the driver - // state. - // But if we omit it, and cause an error, it would be even more - // confusing. The ideal solution is probably to create shared context - // sibling, and query all the state from there (maybe even in parallel - // on other thread). - auto err = GlesSpy::mImports.glGetError(); - if (err) { - GAPID_ERROR("Failed to get reflection data for program %i: Error 0x%x", - program, err); - } - - // Include snapshot of the current state (i.e. the inputs of the operation) - for (auto it : p->mShaders) { - if (it.second != nullptr) { - extra->mShaders[it.first] = it.second->mCompileExtra; - } - } - extra->mBinary = binary; - extra->mAttributeBindings = p->mAttributeBindings.clone(); - extra->mTransformFeedbackVaryings = p->mTransformFeedbackVaryings.clone(); - extra->mTransformFeedbackBufferMode = p->mTransformFeedbackBufferMode; - extra->mSeparable = p->mSeparable; - extra->mBinaryRetrievableHint = p->mBinaryRetrievableHint; - - observer->encode(*extra.get()); - return extra; -} - -// GetCompileShaderExtra is called by glCompileShader and glShaderBinary -gapil::Ref GlesSpy::GetCompileShaderExtra( - CallObserver* observer, gapil::Ref ctx, gapil::Ref p, - gapil::Ref binary) { - using namespace GLenum; - auto extra = gapil::Ref::create(arena()); - GLuint shader = p->mID; - extra->mID = shader; - - GLint compileStatus = 0; - mImports.glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); - extra->mCompileStatus = compileStatus; - - GLint logLength = 0; - mImports.glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength); - std::vector buffer(logLength + 1); - mImports.glGetShaderInfoLog(shader, buffer.size(), &logLength, buffer.data()); - extra->mInfoLog = gapil::String(arena(), buffer.data(), logLength); - - // Make snapshot of the inputs. - extra->mSource = p->mSource; - extra->mBinary = binary; - - observer->encode(*extra.get()); - return extra; -} - -// GetValidateProgramExtra is called by glValidateProgram -gapil::Ref GlesSpy::GetValidateProgramExtra( - CallObserver* observer, gapil::Ref ctx, gapil::Ref p) { - using namespace GLenum; - auto extra = gapil::Ref::create(arena()); - GLuint program = p->mID; - extra->mID = program; - - GLint validateStatus = 0; - mImports.glGetProgramiv(program, GL_VALIDATE_STATUS, &validateStatus); - extra->mValidateStatus = validateStatus; - - GLint infoLogLength = 0; - mImports.glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); - std::vector buffer(infoLogLength + 1); - mImports.glGetProgramInfoLog(program, buffer.size(), &infoLogLength, - buffer.data()); - extra->mInfoLog = gapil::String(arena(), buffer.data(), infoLogLength); - - observer->encode(*extra.get()); - return extra; -} - -// GetValidateProgramPipelineExtra is called by glValidateProgramPipeline -gapil::Ref -GlesSpy::GetValidateProgramPipelineExtra(CallObserver* observer, - gapil::Ref ctx, - gapil::Ref p) { - using namespace GLenum; - auto extra = gapil::Ref::create(arena()); - GLuint pipe = p->mID; - extra->mID = pipe; - - GLint validateStatus = 0; - mImports.glGetProgramPipelineiv(pipe, GL_VALIDATE_STATUS, &validateStatus); - extra->mValidateStatus = validateStatus; - - GLint infoLogLength = 0; - mImports.glGetProgramPipelineiv(pipe, GL_INFO_LOG_LENGTH, &infoLogLength); - std::vector buffer(infoLogLength + 1); - mImports.glGetProgramPipelineInfoLog(pipe, buffer.size(), &infoLogLength, - buffer.data()); - extra->mInfoLog = gapil::String(arena(), buffer.data(), infoLogLength); - - observer->encode(*extra.get()); - - return extra; -} - -gapil::Ref GlesSpy::GetAndroidNativeBufferExtra( - CallObserver* observer, void* ptr) { -#if TARGET_OS == GAPID_OS_ANDROID - struct android_native_base_t { - int magic; - int version; - void* reserved[4]; - void (*incRef)(android_native_base_t* base); - void (*decRef)(android_native_base_t* base); - }; - - struct ANativeWindowBuffer { - android_native_base_t common; - int width; - int height; - int stride; - int format; - int usage; - uintptr_t layer_count; - void* reserved; - void* handle; - void* reserved_proc[8]; - }; - - auto buffer = reinterpret_cast(ptr); - - if (buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) { - GAPID_WARNING("Unknown EGLClientBuffer with magic: 0x%x", - buffer->common.magic); - return nullptr; - } - - auto android_version_major = - device_instance()->configuration().os().major_version(); - - bool use_layer_count = android_version_major >= 8; // Android O - - auto extra = gapil::Ref::create( - arena(), buffer->width, buffer->height, buffer->stride, buffer->format, - buffer->usage, use_layer_count ? buffer->layer_count : 0); - - GAPID_INFO( - "Created AndroidNativeBufferExtra: os_version:%i, width=%i, height=%i, " - "layers=%" PRIx64, - (int)android_version_major, buffer->width, buffer->height, - (uint64_t)buffer->layer_count); - - observer->encode(*extra.get()); - return extra; -#else - return nullptr; -#endif // TARGET_OS == GAPID_OS_ANDROID -} - -// TODO: When gfx api macros produce functions instead of inlining, move this -// logic to the gles.api file. -bool GlesSpy::getFramebufferAttachmentSize(CallObserver* observer, - uint32_t* width, uint32_t* height) { - gapil::Ref ctx = mState.Contexts[observer->getCurrentThread()]; - if (ctx == nullptr) { - return false; - } - - auto framebuffer = ctx->mBound.mReadFramebuffer; - if (framebuffer == nullptr) { - return false; - } - - return getFramebufferAttachmentSize(observer, framebuffer.get(), width, - height); -} - -bool GlesSpy::getFramebufferAttachmentSize(CallObserver* observer, - Framebuffer* framebuffer, - uint32_t* width, uint32_t* height) { - auto attachment = framebuffer->mColorAttachments.find(0); - if (attachment == framebuffer->mColorAttachments.end()) { - return false; - } - - switch (attachment->second.mType) { - case GLenum::GL_TEXTURE: { - auto t = attachment->second.mTexture; - auto level = t->mLevels.find(attachment->second.mTextureLevel); - if (level == t->mLevels.end()) { - return false; - } - auto layer = level->second.mLayers.find(attachment->second.mTextureLayer); - if (layer == level->second.mLayers.end()) { - return false; - } - auto image = layer->second; - if (image == nullptr) { - return false; - } - *width = uint32_t(image->mWidth); - *height = uint32_t(image->mHeight); - return true; - } - case GLenum::GL_RENDERBUFFER: { - auto image = attachment->second.mRenderbuffer->mImage; - if (image == nullptr) { - return false; - } - *width = uint32_t(image->mWidth); - *height = uint32_t(image->mHeight); - return true; - } - } - return false; -} - -bool GlesSpy::observeFramebuffer(CallObserver* observer, uint32_t* w, - uint32_t* h, std::vector* data) { - if (!getFramebufferAttachmentSize(observer, w, h)) { - return false; // Could not get the framebuffer size. - } - data->resize((*w) * (*h) * 4); - GlesSpy::mImports.glReadPixels(0, 0, int32_t(*w), int32_t(*h), - GLenum::GL_RGBA, GLenum::GL_UNSIGNED_BYTE, - data->data()); - return true; -} - -} // namespace gapii - -#undef ANDROID_NATIVE_MAKE_CONSTANT -#undef ANDROID_NATIVE_WINDOW_MAGIC -#undef ANDROID_NATIVE_BUFFER_MAGIC diff --git a/gapii/cc/gles_extras.inc b/gapii/cc/gles_extras.inc deleted file mode 100644 index 297ddde34a..0000000000 --- a/gapii/cc/gles_extras.inc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Note this file is included in context in gles_spy.h: -// -// namespace gapii { -// -// class GlesSpy { -// public: - -// Declared in gles_context.cpp. -void getContextConstants(Constants&); - -bool getFramebufferAttachmentSize(CallObserver* observer, uint32_t* width, uint32_t* height); - -bool getFramebufferAttachmentSize(CallObserver* observer, Framebuffer* framebuffer, uint32_t* width, uint32_t* height); - -void serializeGPUBuffers(StateSerializer* serializer); diff --git a/gapii/cc/gles_inlines.inc b/gapii/cc/gles_inlines.inc deleted file mode 100644 index 2e86fd217c..0000000000 --- a/gapii/cc/gles_inlines.inc +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is intended to be included by gles_spy.h inside -// of the gapid namespace. diff --git a/gapii/cc/gles_mid_execution.cpp b/gapii/cc/gles_mid_execution.cpp deleted file mode 100644 index 56c723ed41..0000000000 --- a/gapii/cc/gles_mid_execution.cpp +++ /dev/null @@ -1,1203 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gapii/cc/gles_spy.h" -#include "gapii/cc/gles_types.h" -#include "gapii/cc/spy.h" -#include "gapii/cc/state_serializer.h" - -#include "gapis/api/gles/gles_pb/extras.pb.h" - -namespace { -using namespace gapii; -using namespace gapii::GLenum; -using namespace gapii::GLbitfield; -using namespace gapii::EGLenum; - -struct ImageData { - std::unique_ptr> data; - uint32_t width; - uint32_t height; - GLint sizedFormat; - GLint dataFormat; - GLint dataType; -}; - -class TempObject { - public: - TempObject(uint64_t id, const std::function& deleteId) - : mId(id), mDeleteId(deleteId) {} - - TempObject(TempObject&& other) { - mId = other.mId; - mDeleteId = other.mDeleteId; - other.mDeleteId = nullptr; - } - - ~TempObject() { - if (mDeleteId) { - mDeleteId(); - } - } - - uint64_t id() { return mId; } - - private: - TempObject(const TempObject&) = delete; - TempObject& operator=(const TempObject&) = delete; - - uint64_t mId; - std::function mDeleteId; -}; - -struct swizzle { - GLint r, g, b, a; -}; - -struct index { - GLint level, layer; -}; - -class Sampler { - public: - enum ESVersion { ES20, ES30, ES31 }; - Sampler() {} - - virtual ESVersion getESVersion() const { return ES20; } - - virtual std::string getExtensions() const = 0; - virtual std::string getUniform() const = 0; - virtual std::string getFragmentPreamble() const { return ""; } - virtual std::string getSamplingExpression() const = 0; -}; - -class Sampler2D : public Sampler { - public: - Sampler2D() {} - - virtual std::string getExtensions() const { return ""; } - - virtual std::string getUniform() const { return "uniform sampler2D tex;"; } - - virtual std::string getSamplingExpression() const { - return "texture2D(tex, texcoord)"; - } - - static const Sampler& get() { - static const Sampler2D instance; - return instance; - } -}; - -class Sampler2DArray : public Sampler { - public: - Sampler2DArray(int layer) : mLayer(layer) {} - - virtual ESVersion getESVersion() const { return ES30; } - - virtual std::string getExtensions() const { return ""; } - - virtual std::string getUniform() const { - return "uniform sampler2DArray tex;"; - } - - virtual std::string getSamplingExpression() const { - std::ostringstream r; - r << "texture(tex, vec3(texcoord, " << mLayer << ".0))"; - return r.str(); - } - - private: - GLint mLayer; -}; - -class SamplerExternal : public Sampler { - public: - SamplerExternal() {} - - virtual std::string getExtensions() const { - return "#extension GL_OES_EGL_image_external : require\n"; - } - - virtual std::string getUniform() const { - return "uniform samplerExternalOES tex;"; - } - - virtual std::string getSamplingExpression() const { - return "texture2D(tex, texcoord)"; - } - - static const Sampler& get() { - static const SamplerExternal instance; - return instance; - } -}; - -class Sampler3D : public Sampler { - public: - Sampler3D(float z) : mZ(z) {} - - virtual std::string getExtensions() const { - return "#extension GL_OES_texture_3D : require\n"; - } - - virtual std::string getUniform() const { return "uniform sampler3D tex;"; } - - virtual std::string getSamplingExpression() const { - std::ostringstream r; - r << "texture3D(tex, vec3(texcoord, " << mZ << "))"; - return r.str(); - } - - private: - float mZ; -}; - -class SamplerCube : public Sampler { - public: - SamplerCube(GLint face) : mFace(face) {} - - virtual std::string getExtensions() const { return ""; } - - virtual std::string getUniform() const { return "uniform samplerCube tex;"; } - - virtual std::string getFragmentPreamble() const { - // uv.xy is texcoord expanded to [-1, 1]. - // uv.zw is -uv.xy. - return "vec4 uv = vec4(-1.0 + 2.0 * texcoord, 1.0 - 2.0 * texcoord);"; - } - - virtual std::string getSamplingExpression() const { - switch (mFace) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - return "textureCube(tex, vec3(1.0, uv.wz))"; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - return "textureCube(tex, vec3(-1.0, uv.wx))"; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - return "textureCube(tex, vec3(uv.x, 1.0, uv.y))"; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - return "textureCube(tex, vec3(uv.x, -1.0, uv.w))"; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - return "textureCube(tex, vec3(uv.xw, 1.0))"; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - return "textureCube(tex, vec3(uv.zw, -1.0))"; - default: - GAPID_FATAL("MEC: unexpected cube face: 0x%x", mFace); - return ""; - } - } - - private: - GLint mFace; -}; - -class SamplerCubeArray : public Sampler { - public: - SamplerCubeArray(int layer, GLint face) : mLayer(layer), mFace(face) {} - - virtual ESVersion getESVersion() const { return ES31; } - - virtual std::string getExtensions() const { - return "#extension GL_EXT_texture_cube_map_array : require\n"; - } - - virtual std::string getUniform() const { - return "uniform samplerCubeArray tex;"; - } - - virtual std::string getFragmentPreamble() const { - // uv.xy is texcoord expanded to [-1, 1]. - // uv.zw is -uv.xy. - return "vec4 uv = vec4(-1.0 + 2.0 * texcoord, 1.0 - 2.0 * texcoord);"; - } - - virtual std::string getSamplingExpression() const { - std::ostringstream r; - r << "texture(tex, vec4("; - - switch (mFace) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - r << "1.0, uv.wz"; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - r << "-1.0, uv.wx"; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - r << "uv.x, 1.0, uv.y"; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - r << "uv.x, -1.0, uv.w"; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - r << "uv.xw, 1.0"; - break; - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - r << "uv.xw, 1.0"; - break; - default: - GAPID_FATAL("MEC: unexpected cube face: 0x%x", mFace); - return ""; - } - - r << ", " << mLayer << ".0))"; - return r.str(); - } - - private: - int mLayer; - GLint mFace; -}; - -struct texture_state { - swizzle swiz; - GLint compMode; - GLint minFilter, magFilter; - GLint baseLevel, maxLevel; - GLfloat minLod, maxLod; -}; - -struct texture { - uint64_t id; - uint32_t kind; - GLsizei w, h, d; - - void bind(const GlesImports& i) const { i.glBindTexture(kind, id); } - - // Gets the current state of the texture. - texture_state getState(const GlesImports& i) const { - texture_state r; - i.glGetTexParameteriv(kind, GL_TEXTURE_SWIZZLE_R, &r.swiz.r); - i.glGetTexParameteriv(kind, GL_TEXTURE_SWIZZLE_G, &r.swiz.g); - i.glGetTexParameteriv(kind, GL_TEXTURE_SWIZZLE_B, &r.swiz.b); - i.glGetTexParameteriv(kind, GL_TEXTURE_SWIZZLE_A, &r.swiz.a); - i.glGetTexParameteriv(kind, GL_TEXTURE_COMPARE_MODE, &r.compMode); - i.glGetTexParameteriv(kind, GL_TEXTURE_MIN_FILTER, &r.minFilter); - i.glGetTexParameteriv(kind, GL_TEXTURE_MAG_FILTER, &r.magFilter); - i.glGetTexParameteriv(kind, GL_TEXTURE_BASE_LEVEL, &r.baseLevel); - i.glGetTexParameteriv(kind, GL_TEXTURE_MAX_LEVEL, &r.maxLevel); - i.glGetTexParameterfv(kind, GL_TEXTURE_MIN_LOD, &r.minLod); - i.glGetTexParameterfv(kind, GL_TEXTURE_MAX_LOD, &r.maxLod); - return r; - } - - // Modifes the texture's state so it can be savely used to read from. Make - // sure to call setState() after, with a previously saved state. - void prepareToRead(const GlesImports& i, GLint level, swizzle swizzle) const { - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_R, swizzle.r); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_G, swizzle.g); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_B, swizzle.b); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_A, swizzle.a); - i.glTexParameteri(kind, GL_TEXTURE_COMPARE_MODE, GL_NONE); - i.glTexParameteri(kind, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - i.glTexParameteri(kind, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - i.glTexParameteri(kind, GL_TEXTURE_BASE_LEVEL, level); - i.glTexParameteri(kind, GL_TEXTURE_MAX_LEVEL, level); - i.glTexParameterf(kind, GL_TEXTURE_MIN_LOD, -1000.0f); - i.glTexParameterf(kind, GL_TEXTURE_MAX_LOD, 1000.0f); - } - - // Modifies the texture's state to match the given state. - void setState(const GlesImports& i, const texture_state& state) const { - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_R, state.swiz.r); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_G, state.swiz.g); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_B, state.swiz.b); - i.glTexParameteri(kind, GL_TEXTURE_SWIZZLE_A, state.swiz.a); - i.glTexParameteri(kind, GL_TEXTURE_COMPARE_MODE, state.compMode); - i.glTexParameteri(kind, GL_TEXTURE_MIN_FILTER, state.minFilter); - i.glTexParameteri(kind, GL_TEXTURE_MAG_FILTER, state.magFilter); - i.glTexParameteri(kind, GL_TEXTURE_BASE_LEVEL, state.baseLevel); - i.glTexParameteri(kind, GL_TEXTURE_MAX_LEVEL, state.maxLevel); - i.glTexParameterf(kind, GL_TEXTURE_MIN_LOD, state.minLod); - i.glTexParameterf(kind, GL_TEXTURE_MAX_LOD, state.maxLod); - } -}; - -class Reader { - public: - Reader(const GlesImports& imports) : imports(imports) {} - - TempObject CreateAndBindFramebuffer(uint32_t target); - TempObject CreateAndBindTexture2D(GLint w, GLint h, uint32_t sizedFormat); - TempObject CreateAndBindTextureExternal(EGLImageKHR handle); - TempObject CreateAndBindContext(EGLContext sharedContext, EGLint version); - - ImageData ReadTexture(const texture& tex, index index, uint32_t format); - ImageData ReadRenderbuffer(Renderbuffer* rb); - ImageData ReadExternal(EGLImageKHR handle, GLsizei w, GLsizei h); - - private: - ImageData ReadTextureViaDrawQuad(const texture& tex, index index, - uint32_t format, const char* name, - swizzle swizzle); - ImageData ReadTextureViaDrawQuad(const Sampler& sampler, const texture& tex, - index index, uint32_t format, - swizzle swizzle); - - inline ImageData ReadTextureViaDrawQuad(const texture& tex, index index, - uint32_t format, const char* name, - uint32_t originalFormat, - GLint rSwizzle) { - ImageData result = ReadTextureViaDrawQuad( - tex, index, format, name, {rSwizzle, GL_ZERO, GL_ZERO, GL_ONE}); - // Restore original format, so it doesn't show up as GL_RED in the UI. - result.dataFormat = originalFormat; - return result; - } - - inline ImageData ReadTextureViaDrawQuad(const texture& tex, index index, - uint32_t format, const char* name, - uint32_t originalFormat, - GLint rSwizzle, GLint gSwizzle) { - ImageData result = ReadTextureViaDrawQuad( - tex, index, format, name, {rSwizzle, gSwizzle, GL_ZERO, GL_ONE}); - // Restore original format, so it doesn't show up as GL_RG in the UI. - result.dataFormat = originalFormat; - return result; - } - - inline ImageData ReadCompressedTexture(const texture& tex, index index, - uint32_t format, swizzle swizzle) { - ImageData result = - ReadTextureViaDrawQuad(tex, index, format, "compressed", swizzle); - // Override the internal format to the uncompressed format of the data. - result.sizedFormat = format; - return result; - } - - void DrawTexturedQuad(const Sampler& sampler, GLsizei w, GLsizei h); - ImageData ReadPixels(GLsizei w, GLsizei h); - - const GlesImports& imports; -}; - -TempObject Reader::CreateAndBindFramebuffer(uint32_t target) { - GLuint fb = 0; - imports.glGenFramebuffers(1, &fb); - imports.glBindFramebuffer(target, fb); - return TempObject(fb, [=] { - GLuint id = fb; - imports.glDeleteFramebuffers(1, &id); - }); -} - -TempObject Reader::CreateAndBindTexture2D(GLint w, GLint h, uint32_t format) { - GLuint tex = 0; - imports.glGenTextures(1, &tex); - imports.glBindTexture(GL_TEXTURE_2D, tex); - imports.glTexStorage2D(GL_TEXTURE_2D, 1, format, w, h); - return TempObject(tex, [=] { - GLuint id = tex; - imports.glDeleteTextures(1, &id); - }); -} - -TempObject Reader::CreateAndBindTextureExternal(EGLImageKHR handle) { - GLuint tex = 0; - imports.glGenTextures(1, &tex); - imports.glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); - imports.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, handle); - imports.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, - GL_NEAREST); - imports.glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, - GL_NEAREST); - return TempObject(tex, [=] { - GLuint id = tex; - imports.glDeleteTextures(1, &id); - }); -} - -#define EGL_WARNING(FORMAT, ...) \ - GAPID_WARNING(FORMAT ": 0x%x", ##__VA_ARGS__, imports.eglGetError()) -#define EGL_FATAL(FORMAT, ...) \ - GAPID_FATAL(FORMAT ": 0x%x", ##__VA_ARGS__, imports.eglGetError()) - -#define CHECK_GL_ERROR(FORMAT, ...) \ - do { \ - GLint err = imports.glGetError(); \ - if (err) { \ - GAPID_FATAL(FORMAT ": 0x%x", err); \ - } \ - } while (false) - -#define CHECK_FB_COMPLETE(FB, FORMAT, ...) \ - do { \ - GLint status = imports.glCheckFramebufferStatus(FB); \ - if (status != GL_FRAMEBUFFER_COMPLETE) { \ - GAPID_FATAL(FORMAT ": 0x%x", status); \ - } \ - } while (false) - -// Attempts to create a context sharing the given context, by querying the -// share context for its EGLConfig ID. -EGLContext CreateEglContextForSharedContext(const GlesImports& imports, - EGLDisplay dsp, EGLContext share, - EGLint* ctxAtr) { - EGLint id = 42; - if (!imports.eglQueryContext(dsp, share, EGL_CONFIG_ID, &id)) { - EGL_WARNING("MEC: Failed to query the config ID of the context"); - return nullptr; - } - - EGLint cfgAtr[] = {EGL_CONFIG_ID, id, EGL_NONE}; - EGLConfig cfg; - int one = 1; - if (!imports.eglChooseConfig(dsp, cfgAtr, &cfg, 1, &one) || one != 1) { - EGL_WARNING("MEC: Failed to choose EGLConfig by id %d", id); - return nullptr; - } - - EGLContext ctx; - if ((ctx = imports.eglCreateContext(dsp, cfg, share, ctxAtr)) == nullptr) { - EGL_WARNING("MEC: Failed to create EGL context"); - } - return ctx; -} - -// Creates temporary GL context which shares objects with the given application -// context. This makes it easier to do a lot of work without worrying about -// corrupting the state. For example, calling glGetError would be otherwise -// technically invalid without hacks. -TempObject Reader::CreateAndBindContext(EGLContext share, EGLint version) { - // Save old state. - auto dsp = imports.eglGetCurrentDisplay(); - auto draw = imports.eglGetCurrentSurface(EGL_DRAW); - auto read = imports.eglGetCurrentSurface(EGL_READ); - auto oldCtx = imports.eglGetCurrentContext(); - - // Find an EGL config. - EGLConfig cfg; - EGLint cfgAtr[] = {EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE}; - int one = 1; - if (!imports.eglChooseConfig(dsp, cfgAtr, &cfg, 1, &one) || one != 1) { - EGL_FATAL("MEC: Failed to choose EGLConfig"); - } - - // Create an EGL context. - EGLContext ctx; - EGLint ctxAtr[] = {EGL_CONTEXT_CLIENT_VERSION, version, EGL_NONE}; - if ((ctx = imports.eglCreateContext(dsp, cfg, share, ctxAtr)) == nullptr) { - EGLint error = imports.eglGetError(); - if (share == nullptr || error != EGL_BAD_MATCH) { - GAPID_WARNING("MEC: Failed to create EGL context: 0x%x", error); - } else { - GAPID_WARNING("MEC: BAD_MATCH creating shared context. Querying config."); - ctx = CreateEglContextForSharedContext(imports, dsp, share, ctxAtr); - } - } - - if (ctx == nullptr) { - return TempObject(reinterpret_cast(ctx), [=] { - if (!imports.eglMakeCurrent(dsp, draw, read, oldCtx)) { - EGL_FATAL("MEC: Failed to restore old EGL context"); - } - }); - } - - // Create an EGL surface. - EGLSurface surf; - EGLint surfAtr[] = {EGL_WIDTH, 16, EGL_HEIGHT, 16, EGL_NONE}; - if ((surf = imports.eglCreatePbufferSurface(dsp, cfg, surfAtr)) == nullptr) { - EGL_FATAL("MEC: Failed to create EGL surface"); - } - - // Bind the EGL context. - if (!imports.eglMakeCurrent(dsp, surf, surf, ctx)) { - EGL_FATAL("MEC: Failed to bind new EGL context"); - } - - // Setup desirable default state for reading data. - imports.glPixelStorei(GL_PACK_ALIGNMENT, 1); - imports.glPixelStorei(GL_PACK_ROW_LENGTH, 0); - imports.glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - imports.glPixelStorei(GL_PACK_SKIP_ROWS, 0); - - return TempObject(reinterpret_cast(ctx), [=] { - if (!imports.eglMakeCurrent(dsp, draw, read, oldCtx)) { - EGL_FATAL("MEC: Failed to restore old EGL context"); - } - imports.eglDestroySurface(dsp, surf); - imports.eglDestroyContext(dsp, ctx); - }); -} - -#define GLSL_VERSION(version) \ - (version == Sampler::ES30 \ - ? "#version 300 es\n" \ - : version == Sampler::ES31 ? "#version 310 es\n" : "") - -void Reader::DrawTexturedQuad(const Sampler& sampler, GLsizei w, GLsizei h) { - CHECK_GL_ERROR("MEC: Entered DrawTexturedQuad in error state"); - CHECK_FB_COMPLETE(GL_DRAW_FRAMEBUFFER, "MEC: Draw framebuffer incomplete"); - - Sampler::ESVersion version = sampler.getESVersion(); - std::string vsSource; - if (version != Sampler::ES20) { - vsSource += GLSL_VERSION(version); - vsSource += "#define attribute in\n"; - vsSource += "#define varying out\n"; - } - vsSource += "precision highp float;\n"; - vsSource += "attribute vec2 position;\n"; - vsSource += "varying vec2 texcoord;\n"; - vsSource += "void main() {\n"; - vsSource += " gl_Position = vec4(position, 0.5, 1.0);\n"; - vsSource += " texcoord = position * vec2(0.5) + vec2(0.5);\n"; - vsSource += "}\n"; - - std::string fsSource; - fsSource += GLSL_VERSION(version); - fsSource += sampler.getExtensions(); - fsSource += "precision highp float;\n"; - if (version != Sampler::ES20) { - fsSource += "#define varying in\n"; - fsSource += "out vec4 fragColor;\n"; - } else { - fsSource += "#define fragColor gl_FragColor\n"; - } - fsSource += sampler.getUniform(); - fsSource += "varying vec2 texcoord;\n"; - fsSource += "void main() {\n"; - fsSource += sampler.getFragmentPreamble(); - fsSource += " fragColor = " + sampler.getSamplingExpression() + ";\n"; - fsSource += "}\n"; - - auto prog = imports.glCreateProgram(); - - auto vs = imports.glCreateShader(GL_VERTEX_SHADER); - char* vsSources[] = {const_cast(vsSource.data())}; - imports.glShaderSource(vs, 1, vsSources, nullptr); - imports.glCompileShader(vs); - imports.glAttachShader(prog, vs); - - auto fs = imports.glCreateShader(GL_FRAGMENT_SHADER); - char* fsSources[] = {const_cast(fsSource.data())}; - imports.glShaderSource(fs, 1, fsSources, nullptr); - imports.glCompileShader(fs); - imports.glAttachShader(prog, fs); - - imports.glBindAttribLocation(prog, 0, "position"); - imports.glLinkProgram(prog); - CHECK_GL_ERROR("MEC: Failed to create program"); - - GLint linkStatus = 0; - imports.glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus); - if (linkStatus == 0) { - char log[1024]; - imports.glGetProgramInfoLog(prog, sizeof(log), nullptr, log); - GAPID_ERROR("Vertex Shader:\n%s\n\nFragment Shader:\n%s", vsSource.c_str(), - fsSource.c_str()); - GAPID_FATAL("MEC: Failed to compile program:\n%s", log); - } - - imports.glDisable(GL_CULL_FACE); - imports.glDisable(GL_DEPTH_TEST); - imports.glViewport(0, 0, w, h); - imports.glClearColor(0.0, 0.0, 0.0, 0.0); - imports.glClear(GLbitfield::GL_COLOR_BUFFER_BIT); - imports.glUseProgram(prog); - GLfloat vb[] = { - -1.0f, +1.0f, // 2--4 - -1.0f, -1.0f, // |\ | - +1.0f, +1.0f, // | \| - +1.0f, -1.0f, // 1--3 - }; - imports.glEnableVertexAttribArray(0); - imports.glVertexAttribPointer(0, 2, GL_FLOAT, 0, 0, vb); - imports.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - CHECK_GL_ERROR("MEC: Failed to draw quad"); - - imports.glDeleteShader(vs); - imports.glDeleteShader(fs); - imports.glDeleteProgram(prog); -} - -ImageData Reader::ReadPixels(GLsizei w, GLsizei h) { - CHECK_FB_COMPLETE(GL_READ_FRAMEBUFFER, "ReadPixels: Framebuffer incomplete"); - - ImageData img; - - // Ask the driver what is the ideal format/type for reading the pixels. - imports.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &img.dataFormat); - imports.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &img.dataType); - CHECK_GL_ERROR("ReadPixels: Failed to get data format/type"); - GAPID_DEBUG("ReadPixels: fmt 0x%x type 0x%x", img.dataFormat, img.dataType); - - auto spy = Spy::get(); - auto observer = spy->enter("subUncompressedImageSize", GlesSpy::kApiIndex); - auto size = spy->subUncompressedImageSize(observer, [] {}, w, h, - img.dataFormat, img.dataType); - spy->exit(); - - img.sizedFormat = GL_NONE; - img.width = w; - img.height = h; - img.data.reset(new std::vector(size)); - GAPID_DEBUG("ReadPixels: Reading %dx%d at %d bytes", w, h, size); - if (imports.glReadnPixels) { - imports.glReadnPixels(0, 0, w, h, img.dataFormat, img.dataType, - img.data->size(), img.data->data()); - } else { - imports.glReadPixels(0, 0, w, h, img.dataFormat, img.dataType, - img.data->data()); - } - CHECK_GL_ERROR("ReadPixels: Failed to read pixels"); - return img; -} - -#define CUBE_FACE(layer) (GL_TEXTURE_CUBE_MAP_POSITIVE_X + (layer)) - -ImageData Reader::ReadTextureViaDrawQuad(const texture& tex, index idx, - uint32_t format, const char* name, - swizzle swizzle) { - switch (tex.kind) { - case GL_TEXTURE_2D: - return ReadTextureViaDrawQuad(Sampler2D::get(), tex, idx, format, - swizzle); - case GL_TEXTURE_2D_ARRAY: { - Sampler2DArray sampler(idx.layer); - return ReadTextureViaDrawQuad(sampler, tex, idx, format, swizzle); - } - case GL_TEXTURE_3D: { - Sampler3D sampler(1.0f / (2.0f * tex.d) + (float)idx.layer / tex.d); - return ReadTextureViaDrawQuad(sampler, tex, idx, format, swizzle); - } - case GL_TEXTURE_CUBE_MAP: { - SamplerCube sampler(CUBE_FACE(idx.layer)); - return ReadTextureViaDrawQuad(sampler, tex, idx, format, swizzle); - } - case GL_TEXTURE_CUBE_MAP_ARRAY: { - SamplerCubeArray sampler(idx.layer / 6, CUBE_FACE(idx.layer % 6)); - return ReadTextureViaDrawQuad(sampler, tex, idx, format, swizzle); - } - default: - // TODO: Copy the layer/level to temporary 2D texture. - GAPID_WARNING("MEC: Reading of %s data, target 0x%x is not yet supported", - name, tex.kind); - return ImageData{}; - } -} - -ImageData Reader::ReadTexture(const texture& tex, index idx, uint32_t format) { - GAPID_DEBUG("MEC: Reading texture %" PRIu64 " kind 0x%x %dx%d format 0x%x", - tex.id, tex.kind, tex.w, tex.h, format); - switch (format) { - /* depth and stencil */ - case GL_STENCIL_INDEX8: - GAPID_WARNING("MEC: Reading of stencil data is not yet supported"); - break; - case GL_DEPTH24_STENCIL8: - case GL_DEPTH32F_STENCIL8: - GAPID_WARNING("MEC: Reading of depth stencil data is not yet supported"); - break; - case GL_DEPTH_COMPONENT16: - case GL_DEPTH_COMPONENT24: - case GL_DEPTH_COMPONENT32: - case GL_DEPTH_COMPONENT32F: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_R32F, "depth", - GL_DEPTH_COMPONENT, GL_RED); - // Override the internal format to the format of the data. - r.sizedFormat = GL_DEPTH_COMPONENT32F; - return r; - } - /* alpha and luminance */ - case GL_ALPHA8_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R8, "alpha", GL_ALPHA, - GL_ALPHA); - case GL_ALPHA16F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R16F_EXT, "alpha", GL_ALPHA, - GL_ALPHA); - case GL_ALPHA32F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R32F, "alpha", GL_ALPHA, - GL_ALPHA); - case GL_LUMINANCE8_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R8, "luminance", GL_LUMINANCE, - GL_RED); - case GL_LUMINANCE16F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R16F_EXT, "luminance", - GL_LUMINANCE, GL_RED); - case GL_LUMINANCE32F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_R32F, "luminance", - GL_LUMINANCE, GL_RED); - case GL_LUMINANCE8_ALPHA8_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_RG8, "luminance alpha", - GL_LUMINANCE_ALPHA, GL_RED, GL_ALPHA); - case GL_LUMINANCE_ALPHA16F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_RG16F_EXT, "luminance alpha", - GL_LUMINANCE_ALPHA, GL_RED, GL_ALPHA); - case GL_LUMINANCE_ALPHA32F_EXT: - return ReadTextureViaDrawQuad(tex, idx, GL_RG32F, "luminance alpha", - GL_LUMINANCE_ALPHA, GL_RED, GL_ALPHA); - /* RGB */ - case GL_RGB32F: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA32F, "RGB32F", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA32F; - return r; - } - case GL_RGB16F: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16F, "RGB16F", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16F; - return r; - } - case GL_RGB9_E5: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16F, "RGB9_E5", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16F; - return r; - } - case GL_RGB8I: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA8I, "RGB8I", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA8I; - return r; - } - case GL_RGB8UI: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA8UI, "RGB8UI", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA8UI; - return r; - } - case GL_RGB16I: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16I, "RGB16I", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16I; - return r; - } - case GL_RGB16UI: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16UI, "RGB16UI", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16UI; - return r; - } - case GL_RGB32I: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16I, "RGB32I", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA32I; - return r; - } - case GL_RGB32UI: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16UI, "RGB32UI", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA32UI; - return r; - } - /* SRGB */ - case GL_SRGB8: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_SRGB8_ALPHA8, "srgb", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_SRGB8_ALPHA8; - return r; - } - /* signed normalized */ - // TODO: Draw to a regular R/RG/RGB/RGBA 8bit texture with a shader that - // will map [-1, 1] to the correct values. - case GL_R8_SNORM: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_R16F, "R8_SNORM", - {GL_RED, GL_ZERO, GL_ZERO, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_R16F; - return r; - } - case GL_RG8_SNORM: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RG16F, "RG8_SNORM", - {GL_RED, GL_GREEN, GL_ZERO, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RG16F; - return r; - } - case GL_RGB8_SNORM: { - ImageData r = ReadTextureViaDrawQuad(tex, idx, GL_RGBA16F, "RGB8_SNORM", - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16F; - return r; - } - case GL_RGBA8_SNORM: { - ImageData r = - ReadTextureViaDrawQuad(tex, idx, GL_RGBA16F, "RGBGBA8_SNORM", - {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}); - // Override the internal format to the format of the data. - r.sizedFormat = GL_RGBA16F; - return r; - } - /* compressed 8bit RGB */ - case GL_COMPRESSED_RGB8_ETC2: - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - case GL_ATC_RGB_AMD: - case GL_ETC1_RGB8_OES: - return ReadCompressedTexture(tex, idx, GL_RGBA8, - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - /* compressed 8bit RGBA */ - case GL_COMPRESSED_RGBA_ASTC_4x4: - case GL_COMPRESSED_RGBA_ASTC_5x4: - case GL_COMPRESSED_RGBA_ASTC_5x5: - case GL_COMPRESSED_RGBA_ASTC_6x5: - case GL_COMPRESSED_RGBA_ASTC_6x6: - case GL_COMPRESSED_RGBA_ASTC_8x5: - case GL_COMPRESSED_RGBA_ASTC_8x6: - case GL_COMPRESSED_RGBA_ASTC_8x8: - case GL_COMPRESSED_RGBA_ASTC_10x5: - case GL_COMPRESSED_RGBA_ASTC_10x6: - case GL_COMPRESSED_RGBA_ASTC_10x8: - case GL_COMPRESSED_RGBA_ASTC_10x10: - case GL_COMPRESSED_RGBA_ASTC_12x10: - case GL_COMPRESSED_RGBA_ASTC_12x12: - case GL_COMPRESSED_RGBA8_ETC2_EAC: - case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: - case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: - return ReadCompressedTexture(tex, idx, GL_RGBA8, - {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}); - /* compressed 8bit SRGB */ - case GL_COMPRESSED_SRGB8_ETC2: - // GL_SRGB8 (i.e. without alpha) is not color renderable. - return ReadCompressedTexture(tex, idx, GL_SRGB8_ALPHA8, - {GL_RED, GL_GREEN, GL_BLUE, GL_ONE}); - /* compressed 8bit SRGBA */ - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10: - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12: - case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - return ReadCompressedTexture(tex, idx, GL_SRGB8_ALPHA8, - {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}); - /* compressed 11bit R - Half floats have 11bit mantissa. */ - case GL_COMPRESSED_R11_EAC: - case GL_COMPRESSED_SIGNED_R11_EAC: - return ReadCompressedTexture(tex, idx, GL_R16F, - {GL_RED, GL_ZERO, GL_ZERO, GL_ONE}); - /* compressed 11 bit RG - Half floats have 11bit mantissa. */ - case GL_COMPRESSED_RG11_EAC: - case GL_COMPRESSED_SIGNED_RG11_EAC: - return ReadCompressedTexture(tex, idx, GL_RG16F, - {GL_RED, GL_GREEN, GL_ZERO, GL_ONE}); - /* formats that can be used as render targets */ - default: { - // Need to use GL_FRAMEBUFFER (GL_READ_FRAMEBUFFER fails) due to - // driver bug b/115574126. - auto readFb = CreateAndBindFramebuffer(GL_FRAMEBUFFER); - if (tex.kind == GL_TEXTURE_CUBE_MAP) { - uint32_t face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (idx.layer % 6); - imports.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - face, tex.id, idx.level); - } else if (idx.layer == 0) { - imports.glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex.id, idx.level); - } else { - imports.glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex.id, idx.level, idx.layer); - } - return ReadPixels(tex.w, tex.h); - } - } - return ImageData{}; -} - -ImageData Reader::ReadTextureViaDrawQuad(const Sampler& sampler, - const texture& tex, index idx, - uint32_t format, swizzle swizzle) { - GAPID_DEBUG("MEC: Drawing quad to format 0x%x", format); - CHECK_GL_ERROR("MEC: Entered ReadTextureViaDrawQuad in error state"); - - auto drawFb = CreateAndBindFramebuffer(GL_DRAW_FRAMEBUFFER); - auto tmpTex = CreateAndBindTexture2D(tex.w, tex.h, format); - imports.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tmpTex.id(), 0); - tex.bind(imports); - CHECK_GL_ERROR("MEC: Failed to create framebuffer"); - - auto savedState = tex.getState(imports); - CHECK_GL_ERROR("MEC: Failed querying texture state"); - - tex.prepareToRead(imports, idx.level, swizzle); - CHECK_GL_ERROR("MEC: Failed setting texture state"); - - DrawTexturedQuad(sampler, tex.w, tex.h); - - tex.setState(imports, savedState); - CHECK_GL_ERROR("MEC: Failed restoring texture state", err); - - texture res = { - .id = tmpTex.id(), - .kind = GL_TEXTURE_2D, - .w = tex.w, - .h = tex.h, - }; - return ReadTexture(res, {0, 0}, format); -} - -ImageData Reader::ReadRenderbuffer(Renderbuffer* rb) { - auto img = rb->mImage; - auto w = img->mWidth; - auto h = img->mHeight; - auto format = img->mSizedFormat; - uint32_t attach = GL_COLOR_ATTACHMENT0; - switch (img->mDataFormat) { - case GL_DEPTH_COMPONENT: - attach = GL_DEPTH_ATTACHMENT; - break; - case GL_DEPTH_STENCIL: - attach = GL_DEPTH_STENCIL_ATTACHMENT; - break; - case GL_STENCIL_INDEX: - attach = GL_STENCIL_ATTACHMENT; - break; - } - GAPID_DEBUG( - "MEC: Reading renderbuffer %d format 0x%x type 0x%x sized 0x%x at 0x%x", - rb->mID, img->mDataFormat, img->mDataType, format, attach); - if (attach == GL_COLOR_ATTACHMENT0) { - // Need to use GL_FRAMEBUFFER (GL_READ_FRAMEBUFFER fails) due to - // driver bug b/115574126. - auto readFb = CreateAndBindFramebuffer(GL_FRAMEBUFFER); - imports.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, rb->mID); - return ReadPixels(w, h); - } else { - // Copy the renderbuffer data to temporary texture and then use the texture - // reading path. - auto readFb = CreateAndBindFramebuffer(GL_READ_FRAMEBUFFER); - auto drawFb = CreateAndBindFramebuffer(GL_DRAW_FRAMEBUFFER); - auto tmpTex = CreateAndBindTexture2D(w, h, format); - imports.glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, attach, - GL_RENDERBUFFER, rb->mID); - imports.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attach, tmpTex.id(), 0); - uint32_t mask = - GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - imports.glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST); - - texture res = { - .id = tmpTex.id(), - .kind = GL_TEXTURE_2D, - .w = w, - .h = h, - }; - return ReadTexture(res, {0, 0}, format); - } -} - -ImageData Reader::ReadExternal(EGLImageKHR handle, GLsizei w, GLsizei h) { - GAPID_DEBUG("MEC: Reading external texture 0x%p", handle); - auto extTex = CreateAndBindTextureExternal(handle); - auto tmpTex = CreateAndBindTexture2D(w, h, GL_RGBA8); - auto fb = CreateAndBindFramebuffer(GL_FRAMEBUFFER); - imports.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tmpTex.id(), 0); - DrawTexturedQuad(SamplerExternal::get(), w, h); - return ReadPixels(w, h); -} - -void SerializeAndUpdate(StateSerializer* serializer, - gapil::Ref current, - const ImageData& read) { - if (read.data) { - serializer->encodeBuffer( - read.data->size(), ¤t->mData, - [serializer, &read](memory::Observation* obs) { - serializer->sendData(obs, false, read.data->data(), - read.data->size()); - }); - current->mDataFormat = read.dataFormat; - current->mDataType = read.dataType; - if (read.sizedFormat) { - current->mSizedFormat = read.sizedFormat; - } - } -} - -void SerializeRenderBuffer(Reader& r, StateSerializer* serializer, - gapil::Ref rb) { - auto img = rb->mImage; - if (img != nullptr) { - auto newImg = r.ReadRenderbuffer(rb.get()); - SerializeAndUpdate(serializer, img, newImg); - } -} - -void SerializeTexture(Reader& r, StateSerializer* serializer, - gapil::Ref tex) { - texture out{ - .id = tex->mID, - .kind = tex->mKind, - }; - for (auto it : tex->mLevels) { - auto level = it.first; - out.d = it.second.mLayers.count(); - for (auto it2 : it.second.mLayers) { - auto layer = it2.first; - auto img = it2.second; - if (img->mSamples != 0) { - GAPID_WARNING("MEC: Reading multisample textures is not yet supported"); - continue; - } - out.w = img->mWidth; - out.h = img->mHeight; - auto newImg = r.ReadTexture(out, {level, layer}, img->mSizedFormat); - SerializeAndUpdate(serializer, img, newImg); - } - } -} - -} // anonymous namespace - -namespace gapii { -using namespace GLenum; -using namespace GLbitfield; -using namespace EGLenum; - -void GlesSpy::GetEGLImageData(CallObserver* observer, EGLImageKHR handle, - GLsizei width, GLsizei height) { - if (!should_trace(kApiIndex)) { - return; - } - Reader read(mImports); - - GAPID_DEBUG("MEC: Get EGLImage data: 0x%p x%xx%x", handle, width, height); - auto tmpCtx = read.CreateAndBindContext(nullptr, 2); - if (tmpCtx.id() == EGL_NO_CONTEXT) { - return; - } - - auto img = read.ReadExternal(handle, width, height); - - if (!img.data->empty()) { - auto resIndex = sendResource(kApiIndex, img.data->data(), img.data->size()); - gles_pb::EGLImageData extra; - extra.set_res_index(resIndex); - extra.set_size(img.data->size()); - extra.set_width(width); - extra.set_height(height); - extra.set_format(img.dataFormat); - extra.set_type(img.dataType); - observer->encode_message(&extra); - } -} - -void GlesSpy::serializeGPUBuffers(StateSerializer* serializer) { - // Ensure we process shared objects only once. - std::unordered_set seen; - auto once = [&](const void* ptr) { return seen.emplace(ptr).second; }; - - Reader r(mImports); - for (auto& it : mState.EGLContexts) { - auto handle = it.first; - auto ctx = it.second; - if (ctx->mOther.mDestroyed) { - continue; - } - GAPID_DEBUG("MEC: processing context %d thread %s", ctx->mIdentifier, - ctx->mOther.mThreadName.c_str()); - - auto tmpCtx = r.CreateAndBindContext(handle, 3); - if (tmpCtx.id() == EGL_NO_CONTEXT) { - continue; - } - - if (once(ctx->mObjects.mRenderbuffers.instance_ptr())) { - for (auto& it : ctx->mObjects.mRenderbuffers) { - SerializeRenderBuffer(r, serializer, it.second); - } - } - if (once(ctx->mObjects.mTextures.instance_ptr())) { - for (auto& it : ctx->mObjects.mTextures) { - auto ext = it.second->mEGLImage.get(); - if (ext != nullptr) { - if (once(ext)) { - for (auto& it : ext->mImages) { - auto img = it.second; - auto newImg = r.ReadExternal(ext->mID, img->mWidth, img->mHeight); - SerializeAndUpdate(serializer, img, newImg); - } - } - } else { - SerializeTexture(r, serializer, it.second); - } - } - } - /* TODO: read buffers from GPU. Currently disabled due to buffer data - being required by draw calls. Need to be able to determine, - which buffers have been written to by the GPU. - if (once(ctx->mObjects.mBuffers.instance_ptr())) { - for (auto& it : ctx->mObjects.mBuffers) { - auto buffer = it.second; - size_t size = buffer->mSize; - if (size == 0) { - continue; - } - GAPID_DEBUG("MEC: Reading buffer %d size %zu", buffer->mID, size); - - void* data; - const uint32_t target = GL_ARRAY_BUFFER; - if (buffer->mMapped) { - if (buffer->mMapOffset != 0 || - static_cast(buffer->mMapLength) != size) { - // TODO: Implement - We can not unmap and remap since the - // application has the existing pointer, and we can't copy the - // buffer since copy is not allowed for mapped buffers. - // Proposed solution: change glMapBuffer* to always map the whole - // buffer, and return pointer inside that buffer to the user. - GAPID_WARNING("MEC: Can not read partially mapped buffer") - continue; - } - GAPID_DEBUG("MEC: buffer is application mapped"); - data = buffer->mMapPointer; - } else { - mImports.glBindBuffer(target, buffer->mID); - data = mImports.glMapBufferRange(target, 0, size, GL_MAP_READ_BIT); - } - buffer->mData = serializer->encodeBuffer( - size, [=](memory::Observation* obs) { - serializer->sendData(obs, false, data, size); - }); - if (!buffer->mMapped) { - mImports.glUnmapBuffer(target); - } - } - } - */ - } - - GAPID_INFO("MEC: done"); -} - -} // namespace gapii diff --git a/gapii/cc/gles_spy_externs.cpp b/gapii/cc/gles_spy_externs.cpp deleted file mode 100644 index 336f448aa0..0000000000 --- a/gapii/cc/gles_spy_externs.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/call_observer.h" -#include "gapii/cc/gles_spy.h" - -namespace gapii { - -template -T inline min(T a, T b) { - return (a < b) ? a : b; -} -template -T inline max(T a, T b) { - return (a > b) ? a : b; -} - -// Externs not implemented in GAPII. -void GlesSpy::mapMemory(CallObserver*, gapil::Slice) {} -void GlesSpy::unmapMemory(CallObserver*, gapil::Slice) {} -MsgID GlesSpy::newMsg(CallObserver*, uint32_t, const char*) { return 0; } -void GlesSpy::addTag(CallObserver*, uint32_t, const char*) {} - -u32Limits GlesSpy::IndexLimits(CallObserver*, gapil::Slice indices, - int32_t sizeof_index) { - uint32_t low = ~(uint32_t)0; - uint32_t high = 0; - switch (sizeof_index) { - case 1: { - for (auto i : indices.as()) { - low = min(low, i); - high = max(high, i); - } - break; - } - case 2: { - for (auto i : indices.as()) { - low = min(low, i); - high = max(high, i); - } - break; - } - case 4: { - for (auto i : indices.as()) { - low = min(low, i); - high = max(high, i); - } - break; - } - default: { GAPID_FATAL("Invalid index size"); } - } - if (low <= high) { - return u32Limits(low, high + 1 - low); - } else { - return u32Limits(0, 0); - } -} - -void GlesSpy::onGlError(CallObserver* observer, GLenum_Error err) { - const char* current_cmd_name = observer->getCurrentCommandName(); - switch (err) { - case GLenum::GL_INVALID_ENUM: - GAPID_WARNING("Error calling %s: GL_INVALID_ENUM", current_cmd_name); - break; - case GLenum::GL_INVALID_VALUE: - GAPID_WARNING("Error calling %s: GL_INVALID_VALUE", current_cmd_name); - break; - case GLenum::GL_INVALID_OPERATION: - GAPID_WARNING("Error calling %s: GL_INVALID_OPERATION", current_cmd_name); - break; - case GLenum::GL_STACK_OVERFLOW: - GAPID_WARNING("Error calling %s: GL_STACK_OVERFLOW", current_cmd_name); - break; - case GLenum::GL_STACK_UNDERFLOW: - GAPID_WARNING("Error calling %s: GL_STACK_UNDERFLOW", current_cmd_name); - break; - case GLenum::GL_OUT_OF_MEMORY: - GAPID_WARNING("Error calling %s: GL_OUT_OF_MEMORY", current_cmd_name); - break; - case GLenum::GL_INVALID_FRAMEBUFFER_OPERATION: - GAPID_WARNING("Error calling %s: GL_INVALID_FRAMEBUFFER_OPERATION", - current_cmd_name); - break; - case GLenum::GL_CONTEXT_LOST: - GAPID_WARNING("Error calling %s: GL_CONTEXT_LOST", current_cmd_name); - break; - default: - GAPID_WARNING("Error calling %s: %d", current_cmd_name, err); - break; - } - - // Set error only if has not been previously set - if (observer->getError() == GLenum::GL_NO_ERROR) { - observer->setError(err); - } -} - -gapil::Slice GlesSpy::ReadGPUTextureData(CallObserver* observer, - gapil::Ref texture, - GLint level, GLint layer) { - return gapil::Slice(); // Not currently required for gapii. -} - -} // namespace gapii diff --git a/gapii/cc/gvr_abi_types.h b/gapii/cc/gvr_abi_types.h deleted file mode 100644 index a4e3272eda..0000000000 --- a/gapii/cc/gvr_abi_types.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPII_GVR_ABI_TYPES_H -#define GAPII_GVR_ABI_TYPES_H - -#include - -namespace gapii { - -struct gvr_mat4_abi : core::CStaticArray {}; - -gvr_mat4f::gvr_mat4f(gvr_mat4_abi const& abi) : mm(abi) {} -gvr_mat4f::operator gvr_mat4_abi() const { - gvr_mat4_abi out; - memcpy(&out, &this->mm, sizeof(out)); - return out; -} - -} // namespace gapii - -#endif // GAPII_GVR_ABI_TYPES_H diff --git a/gapii/cc/gvr_extras.cpp b/gapii/cc/gvr_extras.cpp deleted file mode 100644 index bfbc9a1582..0000000000 --- a/gapii/cc/gvr_extras.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/spy.h" - -namespace gapii { - -bool GvrSpy::observeFramebuffer(CallObserver* observer, uint32_t* w, - uint32_t* h, std::vector* data) { - auto spy = static_cast(this); - auto gles_state = static_cast(spy)->mState; - - auto contextIt = gles_state.Contexts.find(observer->getCurrentThread()); - if (contextIt == gles_state.Contexts.end() || contextIt->second == nullptr) { - GAPID_WARNING("No GLES context bound to thread"); - return false; - } - auto context = contextIt->second; - - constexpr int frameIndex = 0; // TODO: other indices. - auto framebufferId = mImports.gvr_frame_get_framebuffer_object( - mLastSubmittedFrame, frameIndex); - - GAPID_INFO("frame=%p, framebufferId=%d", mLastSubmittedFrame, framebufferId); - - auto framebufferIt = context->mObjects.mFramebuffers.find(framebufferId); - if (framebufferIt == context->mObjects.mFramebuffers.end()) { - GAPID_WARNING("Framebuffer %d not found", framebufferId); - return false; - } - auto framebuffer = framebufferIt->second; - - if (!spy->GlesSpy::getFramebufferAttachmentSize(observer, framebuffer.get(), - w, h)) { - GAPID_WARNING("Could not get the framebuffer size"); - return false; - } - - auto gles = spy->GlesSpy::imports(); - - // Get current framebuffer state. - GLint prevFramebufferId = 0; - GLint prevReadBuffer = 0; - gles.glGetIntegerv(GLenum::GL_READ_FRAMEBUFFER_BINDING, &prevFramebufferId); - gles.glGetIntegerv(GLenum::GL_READ_BUFFER, &prevReadBuffer); - - // Bind submitted framebuffer for reading. - gles.glBindFramebuffer(GLenum::GL_READ_FRAMEBUFFER, framebufferId); - gles.glReadBuffer(GLenum::GL_COLOR_ATTACHMENT0); - - // Do the read. - data->resize((*w) * (*h) * 4); - gles.glReadPixels(0, 0, int32_t(*w), int32_t(*h), GLenum::GL_RGBA, - GLenum::GL_UNSIGNED_BYTE, data->data()); - - // Restore previous state. - gles.glBindFramebuffer(GLenum::GL_READ_FRAMEBUFFER, prevFramebufferId); - gles.glReadBuffer(prevReadBuffer); - return true; -} - -} // namespace gapii \ No newline at end of file diff --git a/gapii/cc/gvr_extras.inc b/gapii/cc/gvr_extras.inc deleted file mode 100644 index 164e0cffce..0000000000 --- a/gapii/cc/gvr_extras.inc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Note this file is included in context in gvr_spy.h: -// -// namespace gapii { -// -// class GvrSpy { -// public: - -typedef int FramebufferId; - -gvr_frame* mLastSubmittedFrame; \ No newline at end of file diff --git a/gapii/cc/gvr_inlines.inc b/gapii/cc/gvr_inlines.inc deleted file mode 100644 index 2e86fd217c..0000000000 --- a/gapii/cc/gvr_inlines.inc +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is intended to be included by gles_spy.h inside -// of the gapid namespace. diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index 22f134ec89..f0d066b3a0 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -22,7 +22,6 @@ #include "gapil/runtime/cc/runtime.h" -#include "gapii/cc/gles_exports.h" #include "gapii/cc/spy.h" #include "core/cc/gl/formats.h" @@ -34,7 +33,6 @@ #include "core/cc/timer.h" #include "core/os/device/deviceinfo/cc/query.h" -#include "gapis/api/gles/gles_pb/extras.pb.h" #include "gapis/capture/capture.pb.h" #include "gapis/memory/memory_pb/memory.pb.h" @@ -44,19 +42,11 @@ #include #include -#if TARGET_OS == GAPID_OS_WINDOWS -#include "windows/wgl.h" -#endif // TARGET_OS == GAPID_OS_WINDOWS - #if TARGET_OS == GAPID_OS_ANDROID -#include "gapii/cc/android/gvr_install.h" -#include "gapii/cc/android/installer.h" #include #include -static std::unique_ptr gInstaller; - extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { GAPID_INFO("JNI_OnLoad() was called. vm = %p", vm); gapii::Spy::get(); // Construct the spy. @@ -64,32 +54,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { } #endif // TARGET_OS == GAPID_OS_ANDROID -using namespace gapii::GLenum; - namespace { -typedef uint32_t EGLint; - -const EGLint EGL_TRUE = 0x0001; -const EGLint EGL_ALPHA_SIZE = 0x3021; -const EGLint EGL_BLUE_SIZE = 0x3022; -const EGLint EGL_GREEN_SIZE = 0x3023; -const EGLint EGL_RED_SIZE = 0x3024; -const EGLint EGL_DEPTH_SIZE = 0x3025; -const EGLint EGL_STENCIL_SIZE = 0x3026; -const EGLint EGL_CONFIG_ID = 0x3028; -const EGLint EGL_NONE = 0x3038; -const EGLint EGL_HEIGHT = 0x3056; -const EGLint EGL_WIDTH = 0x3057; -const EGLint EGL_SWAP_BEHAVIOR = 0x3093; -const EGLint EGL_BUFFER_PRESERVED = 0x3094; - -const EGLint EGL_CONTEXT_MAJOR_VERSION_KHR = 0x3098; -const EGLint EGL_CONTEXT_MINOR_VERSION_KHR = 0x30FB; -const EGLint EGL_CONTEXT_FLAGS_KHR = 0x30FC; -const EGLint EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR = 0x0001; -const EGLint EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR = 0x30FD; - const uint32_t kMaxFramebufferObservationWidth = 3840; const uint32_t kMaxFramebufferObservationHeight = 2560; @@ -106,10 +72,6 @@ struct spy_creator { GAPID_LOGGER_INIT(LOG_LEVEL_INFO, "gapii", nullptr); GAPID_INFO("Constructing spy..."); m_spy.reset(new Spy()); - GAPID_INFO("Registering spy symbols..."); - for (int i = 0; kGLESExports[i].mName != NULL; ++i) { - m_spy->RegisterSymbol(kGLESExports[i].mName, kGLESExports[i].mFunc); - } } std::unique_ptr m_spy; }; @@ -128,7 +90,6 @@ Spy::Spy() mObserveFrameFrequency(0), mObserveDrawFrequency(0), mDisablePrecompiledShaders(false), - mRecordGLErrorState(false), mNestedFrameStart(0), mNestedFrameEnd(0), mFrameNumber(0) { @@ -173,8 +134,6 @@ Spy::Spy() mObserveDrawFrequency = header.mObserveDrawFrequency; mDisablePrecompiledShaders = (header.mFlags & ConnectionHeader::FLAG_DISABLE_PRECOMPILED_SHADERS) != 0; - mRecordGLErrorState = - (header.mFlags & ConnectionHeader::FLAG_RECORD_ERROR_STATE) != 0; SpyBase::mHideUnknownExtensions = (header.mFlags & ConnectionHeader::FLAG_HIDE_UNKNOWN_EXTENSIONS) != 0; SpyBase::mDisableCoherentMemoryTracker = @@ -216,19 +175,7 @@ Spy::Spy() GAPID_ERROR("Failed at writing trace header."); } -#if TARGET_OS == GAPID_OS_ANDROID - if (strlen(header.mLibInterceptorPath) > 0) { - gInstaller = - std::unique_ptr(new Installer(header.mLibInterceptorPath)); - } - if (header.mGvrHandle != 0) { - auto gvr_lib = reinterpret_cast(header.mGvrHandle); - install_gvr(gInstaller.get(), gvr_lib, &this->GvrSpy::mImports); - } -#endif // TARGET_OS == GAPID_OS_ANDROID - auto context = enter("init", 0); - GlesSpy::init(); VulkanSpy::init(); SpyBase::init(context); exit(); @@ -278,7 +225,7 @@ Spy::~Spy() { endTraceIfRequested(); } -void Spy::resolveImports() { GlesSpy::mImports.resolve(); } +void Spy::resolveImports() {} CallObserver* Spy::enter(const char* name, uint32_t api) { lock(); @@ -295,200 +242,6 @@ void Spy::exit() { unlock(); } -EGLBoolean Spy::eglInitialize(CallObserver* observer, EGLDisplay dpy, - EGLint* major, EGLint* minor) { - EGLBoolean res = GlesSpy::eglInitialize(observer, dpy, major, minor); - if (res != 0) { - resolveImports(); // Imports may have changed. Re-resolve. - } - return res; -} - -EGLContext Spy::eglCreateContext(CallObserver* observer, EGLDisplay display, - EGLConfig config, EGLContext share_context, - EGLint* attrib_list) { - // Read attrib list - std::map attribs; - while (attrib_list != nullptr && *attrib_list != EGL_NONE) { - EGLint key = *(attrib_list++); - EGLint val = *(attrib_list++); - attribs[key] = val; - } - - // Modify attrib list - if (mRecordGLErrorState) { - attribs[EGL_CONTEXT_FLAGS_KHR] |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; - } - - // Write attrib list - std::vector attrib_vector; - for (auto it : attribs) { - attrib_vector.push_back(it.first); - attrib_vector.push_back(it.second); - } - attrib_vector.push_back(EGL_NONE); - attrib_vector.push_back(EGL_NONE); - - auto res = GlesSpy::eglCreateContext(observer, display, config, share_context, - attrib_vector.data()); - - // NB: The getters modify the std::map, so this log must be last. - GAPID_INFO( - "eglCreateContext requested: GL %i.%i, profile 0x%x, flags 0x%x -> %p", - attribs[EGL_CONTEXT_MAJOR_VERSION_KHR], - attribs[EGL_CONTEXT_MINOR_VERSION_KHR], - attribs[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR], - attribs[EGL_CONTEXT_FLAGS_KHR], res); - return res; -} - -static void STDCALL DebugCallback(uint32_t source, uint32_t type, uint32_t id, - uint32_t severity, uint32_t length, - const char* message, void* user_param) { - if (type == GL_DEBUG_TYPE_PUSH_GROUP || type == GL_DEBUG_TYPE_POP_GROUP) { - return; // Ignore - } else if (type == GL_DEBUG_TYPE_ERROR || - severity == GL_DEBUG_SEVERITY_HIGH) { - GAPID_ERROR("KHR_debug: %s", message); - } else { - GAPID_INFO("KHR_debug: %s", message); - } - // TODO: We should store the message in the trace. -} - -EGLBoolean Spy::eglMakeCurrent(CallObserver* observer, EGLDisplay display, - EGLSurface draw, EGLSurface read, - EGLContext context) { - EGLBoolean res = - GlesSpy::eglMakeCurrent(observer, display, draw, read, context); - auto& ext = GlesSpy::mState.Extension; - if (mRecordGLErrorState && ext != nullptr && ext->mGL_KHR_debug) { - void* old_callback = nullptr; - void* new_callback = reinterpret_cast(&DebugCallback); - GlesSpy::mImports.glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, &old_callback); - if (old_callback != new_callback) { - GlesSpy::mImports.glDebugMessageCallback(new_callback, this); - GlesSpy::mImports.glEnable(GL_DEBUG_OUTPUT); - GlesSpy::mImports.glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - GAPID_INFO("KHR_debug extension enabled"); - } - } - return res; -} - -gapil::Ref GlesSpy::GetEGLStaticContextState( - CallObserver* observer, EGLDisplay display, EGLContext context) { - Constants constants(arena()); - getContextConstants(constants); - - gapil::String threadName; -#if TARGET_OS == GAPID_OS_ANDROID - char buffer[256] = {0}; - prctl(PR_GET_NAME, (unsigned long)buffer, 0, 0, 0); - threadName = gapil::String(arena(), buffer); -#endif - - auto out = - gapil::Ref::create(arena(), constants, threadName); - - observer->encode(*out.get()); - - return out; -} - -#define EGL_QUERY_SURFACE(name, draw, var) \ - if (GlesSpy::mImports.eglQuerySurface(display, draw, name, var) != \ - EGL_TRUE) { \ - GAPID_WARNING("eglQuerySurface(0x%p, 0x%p, " #name ", " #var ") failed", \ - display, draw); \ - } -#define EGL_GET_CONFIG_ATTRIB(name, var) \ - if (GlesSpy::mImports.eglGetConfigAttrib(display, config, name, var) != \ - EGL_TRUE) { \ - GAPID_WARNING("eglGetConfigAttrib(0x%p, 0x%p, " #name ", " #var \ - ") failed", \ - display, config); \ - } - -gapil::Ref GlesSpy::GetEGLDynamicContextState( - CallObserver* observer, EGLDisplay display, EGLSurface draw, - EGLContext context) { - EGLint width = 0; - EGLint height = 0; - EGLint swapBehavior = 0; - if (draw != nullptr) { - EGL_QUERY_SURFACE(EGL_WIDTH, draw, &width); - EGL_QUERY_SURFACE(EGL_HEIGHT, draw, &height); - EGL_QUERY_SURFACE(EGL_SWAP_BEHAVIOR, draw, &swapBehavior); - } - - // Get the backbuffer formats. - uint32_t backbufferColorFmt = GL_RGBA8; - uint32_t backbufferDepthFmt = GL_DEPTH24_STENCIL8; - uint32_t backbufferStencilFmt = GL_DEPTH24_STENCIL8; - - EGLint configId = 0; - EGLint r = 0, g = 0, b = 0, a = 0, d = 0, s = 0; - if (GlesSpy::mImports.eglQueryContext(display, context, EGL_CONFIG_ID, - &configId) == EGL_TRUE) { - if (configId != 0) { // EGL_NO_CONFIG_KHR. See EGL_KHR_no_config_context - EGLint attribs[] = {EGL_CONFIG_ID, configId, EGL_NONE}; - EGLConfig config; - EGLint count = 0; - if (GlesSpy::mImports.eglChooseConfig(display, attribs, &config, 1, - &count) == EGL_TRUE) { - EGL_GET_CONFIG_ATTRIB(EGL_RED_SIZE, &r); - EGL_GET_CONFIG_ATTRIB(EGL_GREEN_SIZE, &g); - EGL_GET_CONFIG_ATTRIB(EGL_BLUE_SIZE, &b); - EGL_GET_CONFIG_ATTRIB(EGL_ALPHA_SIZE, &a); - EGL_GET_CONFIG_ATTRIB(EGL_DEPTH_SIZE, &d); - EGL_GET_CONFIG_ATTRIB(EGL_STENCIL_SIZE, &s); - GAPID_INFO("Framebuffer config: R%d G%d B%d A%d D%d S%d", r, g, b, a, d, - s); - - // Get the formats from the bit depths. - if (!core::gl::getColorFormat(r, g, b, a, backbufferColorFmt)) { - GAPID_WARNING("getColorFormat(%d, %d, %d, %d) failed", r, g, b, a); - } - if (!core::gl::getDepthStencilFormat(d, s, backbufferDepthFmt, - backbufferStencilFmt)) { - GAPID_WARNING("getDepthStencilFormat(%d, %d) failed", d, s); - } - } else { - GAPID_WARNING( - "eglChooseConfig() failed for config ID %d. Assuming defaults.", - configId); - } - } // TODO: Try getting dynamic context state for EGL_NO_CONFIG_KHR? - } else { - GAPID_WARNING( - "eglQueryContext(0x%p, 0x%p, EGL_CONFIG_ID, &configId) failed. " - "Assuming defaults.", - display, context); - } - - bool preserveBuffersOnSwap = swapBehavior == EGL_BUFFER_PRESERVED; - - auto out = gapil::Ref::create( - arena(), width, height, backbufferColorFmt, backbufferDepthFmt, - backbufferStencilFmt, preserveBuffersOnSwap, r, g, b, a, d, s); - - // Store the DynamicContextState as an extra. - observer->encode(*out.get()); - - return out; -} - -#undef EGL_QUERY_SURFACE -#undef EGL_GET_CONFIG_ATTRIB - -void Spy::gvr_frame_submit(CallObserver* observer, gvr_frame** frame, - const gvr_buffer_viewport_list* list, - gvr_mat4_abi head_space_from_start_space) { - GvrSpy::mLastSubmittedFrame = (frame != nullptr) ? (*frame) : nullptr; - GvrSpy::gvr_frame_submit(observer, frame, list, head_space_from_start_space); -} - void Spy::endTraceIfRequested() { if (!is_suspended() && mCaptureFrames < 0) { GAPID_DEBUG("Ended capture"); @@ -547,7 +300,6 @@ void Spy::saveInitialState() { mEncoder->object(×tamp); } - saveInitialStateForApi("gles-initial-state"); saveInitialStateForApi("vulkan-initial-state"); if (should_record_timestamps()) { capture::TraceMessage timestamp; @@ -695,21 +447,11 @@ void Spy::observeFramebuffer(CallObserver* observer, uint8_t api) { uint32_t h = 0; std::vector data; switch (api) { - case GlesSpy::kApiIndex: - if (!GlesSpy::observeFramebuffer(observer, &w, &h, &data)) { - return; - } - break; case VulkanSpy::kApiIndex: if (!VulkanSpy::observeFramebuffer(observer, &w, &h, &data)) { return; } break; - case GvrSpy::kApiIndex: - if (!GvrSpy::observeFramebuffer(observer, &w, &h, &data)) { - return; - } - break; } uint32_t downsampledW, downsampledH; @@ -728,112 +470,7 @@ void Spy::observeFramebuffer(CallObserver* observer, uint8_t api) { } void Spy::onPostFence(CallObserver* observer) { - if (mRecordGLErrorState) { - auto traceErr = GlesSpy::mImports.glGetError(); - - // glGetError() cleared the error in the driver. - // Fake it the next time the user calls glGetError(). - if (traceErr != 0) { - setFakeGlError(observer, traceErr); - } - - gles_pb::ErrorState es; - es.set_trace_drivers_gl_error(traceErr); - es.set_interceptors_gl_error(observer->getError()); - observer->encode_message(&es); - } -} - -void Spy::setFakeGlError(CallObserver* observer, GLenum_Error error) { - auto ctx = this->GlesSpy::mState.Contexts[observer->getCurrentThread()]; - if (ctx) { - GLenum_Error& fakeGlError = this->mFakeGlError[ctx->mIdentifier]; - if (fakeGlError == 0) { - fakeGlError = error; - } - } -} - -uint32_t Spy::glGetError(CallObserver* observer) { - auto ctx = this->GlesSpy::mState.Contexts[observer->getCurrentThread()]; - if (ctx) { - GLenum_Error& fakeGlError = this->mFakeGlError[ctx->mIdentifier]; - if (fakeGlError != 0) { - observer->encode(cmd::glGetError{observer->getCurrentThread()}); - GLenum_Error err = fakeGlError; - fakeGlError = 0; - return err; - } - } - return GlesSpy::glGetError(observer); -} - -EGLint Spy::eglGetError(CallObserver* observer) { - // Ignore any (probably nested) eglGetError calls when recording state. - if (is_recording_state()) { - return GlesSpy::mImports.eglGetError(); - } - return GlesSpy::eglGetError(observer); -} - -#if 0 // NON-EGL CONTEXTS ARE CURRENTLY NOT SUPPORTED -gapil::Ref Spy::getWGLContextState(CallObserver*, HDC hdc, HGLRC hglrc) { - if (hglrc == nullptr) { - return nullptr; - } - -#if TARGET_OS == GAPID_OS_WINDOWS - wgl::FramebufferInfo info; - wgl::getFramebufferInfo(hdc, info); - return getContextState(info.width, info.height, - info.colorFormat, info.depthFormat, info.stencilFormat, - /* resetViewportScissor */ true, - /* preserveBuffersOnSwap */ false); -#else // TARGET_OS - return nullptr; -#endif // TARGET_OS -} - -gapil::Ref Spy::getCGLContextState(CallObserver* observer, CGLContextObj ctx) { - if (ctx == nullptr) { - return nullptr; - } - - CGSConnectionID cid; - CGSWindowID wid; - CGSSurfaceID sid; - double bounds[4] = {0, 0, 0, 0}; - - if (GlesSpy::mImports.CGLGetSurface(ctx, &cid, &wid, &sid) == 0) { - GlesSpy::mImports.CGSGetSurfaceBounds(cid, wid, sid, bounds); - } else { - GAPID_WARNING("Could not get CGL surface"); - } - int width = bounds[2] - bounds[0]; // size.x - origin.x - int height = bounds[3] - bounds[1]; // size.y - origin.y - - // TODO: Probe formats - return getContextState(width, height, - GL_RGBA8, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8, - /* resetViewportScissor */ true, - /* preserveBuffersOnSwap */ false); -} - -gapil::Ref Spy::getGLXContextState(CallObserver* observer, void* display, GLXDrawable draw, GLXDrawable read, GLXContext ctx) { - if (display == nullptr) { - return nullptr; - } - int width = 0; - int height = 0; - GlesSpy::mImports.glXQueryDrawable(display, draw, GLX_WIDTH, &width); - GlesSpy::mImports.glXQueryDrawable(display, draw, GLX_HEIGHT, &height); - - // TODO: Probe formats - return getContextState(width, height, - GL_RGBA8, GL_DEPTH_COMPONENT16, GL_STENCIL_INDEX8, - /* resetViewportScissor */ true, - /* preserveBuffersOnSwap */ false); + // TODO: consider removing, this only did GLES error faking } -#endif // #if 0 } // namespace gapii diff --git a/gapii/cc/spy.h b/gapii/cc/spy.h index e0946cb3e9..3c736da6a7 100644 --- a/gapii/cc/spy.h +++ b/gapii/cc/spy.h @@ -18,8 +18,6 @@ #define GAPII_SPY_H #include "core/cc/thread.h" -#include "gapii/cc/gles_spy.h" -#include "gapii/cc/gvr_spy.h" #include "gapii/cc/vulkan_spy.h" #include @@ -29,7 +27,7 @@ namespace gapii { struct spy_creator; class ConnectionStream; -class Spy : public GlesSpy, public GvrSpy, public VulkanSpy { +class Spy : public VulkanSpy { public: // get lazily constructs and returns the singleton instance to the spy. static Spy* get(); @@ -42,36 +40,6 @@ class Spy : public GlesSpy, public GvrSpy, public VulkanSpy { CallObserver* enter(const char* name, uint32_t api); void exit(); - EGLBoolean eglInitialize(CallObserver* observer, EGLDisplay dpy, - EGLint* major, EGLint* minor); - EGLContext eglCreateContext(CallObserver* observer, EGLDisplay display, - EGLConfig config, EGLContext share_context, - EGLint* attrib_list); - EGLBoolean eglMakeCurrent(CallObserver* observer, EGLDisplay display, - EGLSurface draw, EGLSurface read, - EGLContext context); - - // Intercepted GLES methods to optionally fake no support for precompiled - // shaders. - void glProgramBinary(CallObserver* observer, uint32_t program, - uint32_t binary_format, const void* binary, - int32_t binary_size); - void glProgramBinaryOES(CallObserver* observer, uint32_t program, - uint32_t binary_format, const void* binary, - int32_t binary_size); - void glShaderBinary(CallObserver* observer, int32_t count, - const uint32_t* shaders, uint32_t binary_format, - const void* binary, int32_t binary_size); - void glGetInteger64v(CallObserver* observer, uint32_t param, int64_t* values); - void glGetIntegerv(CallObserver* observer, uint32_t param, int32_t* values); - const GLubyte* glGetString(CallObserver* observer, uint32_t name); - const GLubyte* glGetStringi(CallObserver* observer, uint32_t name, - GLuint index); - - void gvr_frame_submit(CallObserver* observer, gvr_frame** frame, - const gvr_buffer_viewport_list* list, - gvr_mat4_abi head_space_from_start_space); - void endTraceIfRequested() override; void onPostDrawCall(CallObserver* observer, uint8_t api) override; @@ -90,10 +58,6 @@ class Spy : public GlesSpy, public GvrSpy, public VulkanSpy { return (symbol == mSymbols.end()) ? nullptr : symbol->second; } - void setFakeGlError(CallObserver* observer, GLenum_Error error); - uint32_t glGetError(CallObserver* observer); - EGLint eglGetError(CallObserver* observer); - private: Spy(); @@ -133,13 +97,11 @@ class Spy : public GlesSpy, public GvrSpy, public VulkanSpy { int mObserveFrameFrequency; int mObserveDrawFrequency; bool mDisablePrecompiledShaders; - bool mRecordGLErrorState; // These keep track of nested frame start/end callbacks. int mNestedFrameStart; int mNestedFrameEnd; uint64_t mFrameNumber; - std::unordered_map mFakeGlError; std::unique_ptr mMessageReceiverJob; friend struct spy_creator; diff --git a/gapii/cc/spy_disable_precompiled_shaders.cpp b/gapii/cc/spy_disable_precompiled_shaders.cpp deleted file mode 100644 index 253038d29a..0000000000 --- a/gapii/cc/spy_disable_precompiled_shaders.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapii/cc/call_observer.h" -#include "gapii/cc/spy.h" - -#include "gapis/api/gfxtrace.pb.h" - -#include "core/cc/id.h" - -// This file contains a number of GLES method 'overrides' to optionally lie to -// the application about the driver not supporting precompiled shaders or -// programs. - -namespace { - -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - -const char* kProgramBinaryExtensions[] = { - "OES_get_program_binary", - "ARB_get_program_binary", -}; - -const char* kProgramBinaryReplacements[] = { - // These *must* match the length of each string in kProgramBinaryExtensions - "__GAPID_PCS_DISABLED__", - "__GAPID_PCS_DISABLED__", -}; - -static_assert( - NELEM(kProgramBinaryExtensions) == NELEM(kProgramBinaryReplacements), - "length of kProgramBinaryExtensions must match kProgramBinaryReplacements"); - -// HACK: Workaround for devices that do not check the error status after calling -// glProgramBinary() or glProgramBinaryOES(). As the error is not checked, this -// can cause logic later on in the application to fail, sometimes leading to -// application termination. -// See https://github.com/google/gapid/issues/1456#issuecomment-349611106 for -// more information. -const core::Id kProgramHashesForNoError[] = { - // https://github.com/google/gapid/issues/1456 - // 0xe14cc04bd723f9c2c46eeef948b08a379f090235 - {{0xe1, 0x4c, 0xc0, 0x4b, 0xd7, 0x23, 0xf9, 0xc2, 0xc4, 0x6e, - 0xee, 0xf9, 0x48, 0xb0, 0x8a, 0x37, 0x9f, 0x09, 0x02, 0x35}}, - - // 0xc231a3a4b597f45244a4745fecdcba918bb8eacc - {{0xc2, 0x31, 0xa3, 0xa4, 0xb5, 0x97, 0xf4, 0x52, 0x44, 0xa4, - 0x74, 0x5f, 0xec, 0xdc, 0xba, 0x91, 0x8b, 0xb8, 0xea, 0xcc}}, - - // 0x55626b9bc73964f52fd5bcf6710659df97997d83 - {{0x55, 0x62, 0x6b, 0x9b, 0xc7, 0x39, 0x64, 0xf5, 0x2f, 0xd5, - 0xbc, 0xf6, 0x71, 0x06, 0x59, 0xdf, 0x97, 0x99, 0x7d, 0x83}}, - - // https://github.com/google/gapid/issues/1525 - // 0xc6b9efad92959f4af5f6fb67a21d94b22f746838 - {{0xc6, 0xb9, 0xef, 0xad, 0x92, 0x95, 0x9f, 0x4a, 0xf5, 0xf6, - 0xfb, 0x67, 0xa2, 0x1d, 0x94, 0xb2, 0x2f, 0x74, 0x68, 0x38}}, -}; - -bool shouldErrorForProgram(const core::Id& id) { - for (size_t i = 0; i < NELEM(kProgramHashesForNoError); i++) { - if (id == kProgramHashesForNoError[i]) { - GAPID_WARNING("Not setting error for program with ID (blacklisted): %s", - id.string().c_str()); - return false; - } - } - GAPID_INFO("Program ID: %s", id.string().c_str()); - return true; -} - -} // anonymous namespace - -using namespace gapii::GLenum; - -namespace gapii { - -void Spy::glProgramBinary(CallObserver* observer, uint32_t program, - uint32_t binary_format, const void* binary, - int32_t binary_size) { - if (mDisablePrecompiledShaders) { - GAPID_WARNING("glProgramBinary(%" PRIu32 ", 0x%X, %p, %" PRId32 - ") " - "called when precompiled shaders are disabled", - program, binary_format, binary, binary_size); - - // GL_INVALID_ENUM is generated if binaryformat is not a supported format - // returned in GL_SHADER_BINARY_FORMATS. - auto id = core::Id::Hash(binary, binary_size); - if (shouldErrorForProgram(id)) { - setFakeGlError(observer, GL_INVALID_ENUM); - } - - observer->enter(cmd::glProgramBinary{observer->getCurrentThread(), program, - binary_format, binary, binary_size}); - - observer->read(binary, binary_size); - observer->observePending(); - api::CmdCall call; - observer->encode_message(&call); - observer->exit(); - } else { - GlesSpy::glProgramBinary(observer, program, binary_format, binary, - binary_size); - } -} - -void Spy::glProgramBinaryOES(CallObserver* observer, uint32_t program, - uint32_t binary_format, const void* binary, - int32_t binary_size) { - if (mDisablePrecompiledShaders) { - GAPID_WARNING("glProgramBinaryOES(%" PRIu32 ", 0x%X, %p, %" PRId32 - ") " - "called when precompiled shaders are disabled", - program, binary_format, binary, binary_size); - - // GL_INVALID_ENUM is generated if binaryformat is not a supported format - // returned in GL_SHADER_BINARY_FORMATS. - auto id = core::Id::Hash(binary, binary_size); - if (shouldErrorForProgram(id)) { - setFakeGlError(observer, GL_INVALID_ENUM); - } - - observer->enter(cmd::glProgramBinaryOES{observer->getCurrentThread(), - program, binary_format, binary, - binary_size}); - - observer->read(binary, binary_size); - observer->observePending(); - - api::CmdCall call; - observer->encode_message(&call); - observer->exit(); - } else { - GlesSpy::glProgramBinaryOES(observer, program, binary_format, binary, - binary_size); - } -} - -void Spy::glShaderBinary(CallObserver* observer, int32_t count, - const uint32_t* shaders, uint32_t binary_format, - const void* binary, int32_t binary_size) { - if (mDisablePrecompiledShaders) { - GAPID_WARNING("glShaderBinary(%" PRId32 ", %p, 0x%X, %p, %" PRId32 - ") " - "called when precompiled shaders are disabled", - count, shaders, binary_format, binary, binary_size); - - // GL_INVALID_ENUM is generated if binaryFormat is not a value recognized by - // the implementation. - setFakeGlError(observer, GL_INVALID_ENUM); - - observer->enter(cmd::glShaderBinary{observer->getCurrentThread(), count, - shaders, binary_format, binary, - binary_size}); - - observer->read(slice(shaders, (uint64_t)((GLsizei)(0)), (uint64_t)(count))); - observer->read( - slice(binary, (uint64_t)((GLsizei)(0)), (uint64_t)(binary_size))); - observer->observePending(); - - api::CmdCall call; - observer->encode_message(&call); - observer->exit(); - } else { - GlesSpy::glShaderBinary(observer, count, shaders, binary_format, binary, - binary_size); - } -} - -void Spy::glGetInteger64v(CallObserver* observer, uint32_t param, - int64_t* values) { - if (mDisablePrecompiledShaders && (param == GL_NUM_SHADER_BINARY_FORMATS || - param == GL_NUM_PROGRAM_BINARY_FORMATS)) { - values[0] = 0; - - observer->enter( - cmd::glGetInteger64v{observer->getCurrentThread(), param, values}); - - api::CmdCall call; - observer->encode_message(&call); - - observer->write(slice(values, 0, 1)); - observer->observePending(); - observer->exit(); - } else { - GlesSpy::glGetInteger64v(observer, param, values); - } -} - -void Spy::glGetIntegerv(CallObserver* observer, uint32_t param, - int32_t* values) { - if (mDisablePrecompiledShaders && (param == GL_NUM_SHADER_BINARY_FORMATS || - param == GL_NUM_PROGRAM_BINARY_FORMATS)) { - values[0] = 0; - - observer->enter( - cmd::glGetIntegerv{observer->getCurrentThread(), param, values}); - - api::CmdCall call; - observer->encode_message(&call); - - observer->write(slice(values, 0, 1)); - observer->observePending(); - observer->exit(); - } else { - GlesSpy::glGetIntegerv(observer, param, values); - } -} - -const GLubyte* Spy::glGetString(CallObserver* observer, uint32_t name) { - if (mDisablePrecompiledShaders && name == GL_EXTENSIONS) { - if (auto exts = reinterpret_cast( - GlesSpy::mImports.glGetString(name))) { - std::string list = reinterpret_cast(exts); - for (size_t i = 0; i < NELEM(kProgramBinaryExtensions); i++) { - size_t start = list.find(kProgramBinaryExtensions[i]); - if (start != std::string::npos) { - static std::string copy = list; - copy.replace(start, strlen(kProgramBinaryExtensions[i]), - kProgramBinaryReplacements[i]); - // TODO: write command. - return reinterpret_cast(const_cast(copy.c_str())); - } - } - } - } - return GlesSpy::glGetString(observer, name); -} - -const GLubyte* Spy::glGetStringi(CallObserver* observer, uint32_t name, - GLuint index) { - if (mDisablePrecompiledShaders && (name == GL_EXTENSIONS)) { - const char* extension = reinterpret_cast( - GlesSpy::mImports.glGetStringi(name, index)); - for (size_t i = 0; i < NELEM(kProgramBinaryExtensions); i++) { - if (strcmp(extension, kProgramBinaryExtensions[i]) == 0) { - // TODO: write command. - return reinterpret_cast( - const_cast(kProgramBinaryReplacements[i])); - } - } - } - return GlesSpy::glGetStringi(observer, name, index); -} - -} // namespace gapii diff --git a/gapii/cc/windows/wgl.cpp b/gapii/cc/windows/wgl.cpp deleted file mode 100644 index 45f10653ef..0000000000 --- a/gapii/cc/windows/wgl.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wgl.h" -#include "gapii/cc/gles_types.h" - -#include - -namespace gapii { -namespace wgl { - -void getFramebufferInfo(void* hdcUntyped, FramebufferInfo& info) { - const ::HDC hdc = reinterpret_cast<::HDC>(hdcUntyped); - const HWND hWnd = WindowFromDC(hdc); - RECT rect; - GetClientRect(hWnd, &rect); - info.width = rect.right - rect.left; - info.height = rect.bottom - rect.top; - - PIXELFORMATDESCRIPTOR pfd; - DescribePixelFormat(hdc, GetPixelFormat(hdc), sizeof(pfd), &pfd); - - int r = pfd.cRedBits; - int g = pfd.cGreenBits; - int b = pfd.cBlueBits; - int a = pfd.cAlphaBits; - - if (r == 8 && g == 8 && b == 8 && a == 8) { - info.colorFormat = GLenum::GL_RGBA8; - } else if (r == 4 && g == 4 && b == 4 && a == 4) { - info.colorFormat = GLenum::GL_RGBA4; - } else if (r == 5 && g == 5 && b == 5 && a == 1) { - info.colorFormat = GLenum::GL_RGB5_A1; - } else if (r == 5 && g == 6 && b == 5 && a == 0) { - info.colorFormat = GLenum::GL_RGB565; - } else { - info.colorFormat = GLenum::GL_RGBA8; - } - - // No options for these yet. - info.stencilFormat = GLenum::GL_DEPTH24_STENCIL8; - info.depthFormat = GLenum::GL_DEPTH24_STENCIL8; -} - -} // namespace wgl -} // namespace gapii diff --git a/gapii/cc/windows/wgl.h b/gapii/cc/windows/wgl.h deleted file mode 100644 index eca8e3cf88..0000000000 --- a/gapii/cc/windows/wgl.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPII_WGL_H -#define GAPII_WGL_H - -#include - -namespace gapii { -namespace wgl { - -struct FramebufferInfo { - int width; - int height; - uint32_t colorFormat; - uint32_t depthFormat; - uint32_t stencilFormat; -}; - -void getFramebufferInfo(void* hdc, FramebufferInfo& info); - -} // namespace wgl -} // namespace gapii - -#endif // GAPII_WGL_H diff --git a/gapii/interceptor-lib/cc/BUILD.bazel b/gapii/interceptor-lib/cc/BUILD.bazel deleted file mode 100644 index 00a7323dc2..0000000000 --- a/gapii/interceptor-lib/cc/BUILD.bazel +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("//tools/build:rules.bzl", "android_dynamic_library", "cc_copts") - -cc_library( - name = "cc", - srcs = glob([ - "lib/*.cpp", - "lib/*.h", - ]) + select({ - "//tools/build:android-armeabi-v7a": glob([ - "lib/ARM/*.cpp", - "lib/ARM/*.h", - ]), - "//tools/build:android-arm64-v8a": glob([ - "lib/AArch64/*.cpp", - "lib/AArch64/*.h", - ]), - "//tools/build:android-x86": glob([ - "lib/X86/*.cpp", - "lib/X86/*.h", - ]), - "//conditions:default": [], - }), - hdrs = glob(["include/*.h"]), - copts = cc_copts() + [ - "-fno-rtti", - "-fno-exceptions", - ], - includes = ["lib"], - linkopts = select({ - "//tools/build:linux": [], - "//tools/build:darwin": [], - "//tools/build:windows": [], - # Android - "//conditions:default": [ - "-ldl", - "-lm", - "-llog", - "-lz", - ], - }), - strip_include_prefix = "include", - visibility = ["//visibility:public"], - deps = select({ - "//tools/build:android-armeabi-v7a": [ - "@llvm//:ARMDisassembler", - ], - "//tools/build:android-arm64-v8a": [ - "@llvm//:AArch64Disassembler", - ], - "//tools/build:android-x86": [ - "@llvm//:X86Desc", - "@llvm//:X86Disassembler", - ], - "//conditions:default": [], - }), -) - -android_dynamic_library( - name = "libinterceptor", - visibility = ["//visibility:public"], - exports = "lib/libinterceptor.exports", - deps = [":cc"], -) diff --git a/gapii/interceptor-lib/cc/include/interceptor.h b/gapii/interceptor-lib/cc/include/interceptor.h deleted file mode 100644 index a618ba4d85..0000000000 --- a/gapii/interceptor-lib/cc/include/interceptor.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_INTERCEPTOR_H_ -#define INTERCEPTOR_INTERCEPTOR_H_ - -// ----------------------------------------------------------------------------- -// extern "C" interface designed for users who dlopen the interceptor-lib -// instead of linking against it. The API for these functions using C structures -// only to support users compiled with different STL library and to support -// usesrs who want to use dlopen/dlsym for loading the library. -// ----------------------------------------------------------------------------- - -extern "C" { - -// Initializes the internal state of the interceptor library and returns a baton -// what have to be passed in to every other function. If called multiple times -// then multiple independent copies of the interceptor will be created. -void* InitializeInterceptor(); - -// Terminate an instance of the interceptor, deletes the trampolines set up by -// the instance and frees up all resources allocated by it. After this call the -// baton is a dangling pointer and passing it to any of the API function is -// undefined behaviour. -void TerminateInterceptor(void* interceptor); - -// Intercepts a function specified by "old_function" with the one specified by -// "new_function". If "callback_function" is not nullptr then a callback stub -// is generated and returned in the pointer specified by "callback_function" -// what can be used to call the original (not intercepted) function after -// casting it to the correct function signature. If an "error_callback" is -// specifed then it will be called for every error encountered during -// interception with the baton specified in "error_callback_baton" and the error -// message itself. The return value of the function will specify if the -// interception was successfull (return true) or not (return false). In case -// of an interception failure the error_callback (if specified) called at least -// once and the original function isn't modified. -bool InterceptFunction(void* interceptor, void* old_function, - void* new_function, void** callback_function = nullptr, - void (*error_callback)(void*, const char*) = nullptr, - void* error_callback_baton = nullptr); - -} // extern "C" - -#endif // INTERCEPTOR_INTERCEPTOR_H_ diff --git a/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.cpp b/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.cpp deleted file mode 100644 index 22ffeda35e..0000000000 --- a/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "target_aarch64.h" - -#include -#include - -#include "MCTargetDesc/AArch64MCTargetDesc.h" -#include "llvm/ADT/Triple.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstBuilder.h" - -#include "code_generator.h" -#include "disassembler.h" - -#define NELEM(x) (sizeof(x) / sizeof(x[0])) - -using namespace interceptor; - -static llvm::Triple GetTriple() { - llvm::Triple triple(llvm::sys::getProcessTriple()); - assert(triple.getArch() == llvm::Triple::aarch64 && - "Invalid default host triple for target"); - return triple; -} - -CodeGenerator* TargetAARCH64::GetCodeGenerator(void* address, - size_t start_alignment) { - return CodeGenerator::Create(GetTriple(), start_alignment); -} - -Disassembler* TargetAARCH64::CreateDisassembler(void* address) { - return Disassembler::Create(GetTriple()); -} - -std::vector TargetAARCH64::GetTrampolineConfigs( - uintptr_t start_address) const { - std::vector configs; - configs.push_back({FIRST_4G_TRAMPOLINE, false, 0x10000, 0xffffffff}); - configs.push_back({FULL_TRAMPOLINE, false, 0, 0xffffffffffffffff}); - return configs; -} - -static Error getFreeRegister(CodeGenerator& codegen, unsigned int& reg) { - static const unsigned int regs[] = {// First try the scratch registers. - llvm::AArch64::X17, llvm::AArch64::X16, - // Then try the caller saved registers. - llvm::AArch64::X9, llvm::AArch64::X10, - llvm::AArch64::X11, llvm::AArch64::X12, - llvm::AArch64::X13, llvm::AArch64::X14, - llvm::AArch64::X15}; - - for (int i = 0; i < NELEM(regs); i++) { - if (!codegen.IsRegisterReserved(regs[i])) { - reg = regs[i]; - return Error(); - } - } - return Error("No free scratch register available"); -} - -Error TargetAARCH64::EmitTrampoline(const TrampolineConfig& config, - CodeGenerator& codegen, void* target) { - unsigned int reg; - Error error = getFreeRegister(codegen, reg); - if (error.Fail()) { - return error; - } - - switch (config.type) { - case FIRST_4G_TRAMPOLINE: { - uint64_t target_addr = reinterpret_cast(target); - if (target_addr > 0xffffffff) - return Error("Target address is out of range for the trampoline"); - uint32_t target_addr32 = target_addr; - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::LDRWl) - .addReg(reg) - .addExpr(codegen.CreateDataExpr(target_addr32))); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::BR).addReg(reg)); - return Error(); - } - case FULL_TRAMPOLINE: { - uint64_t target_addr = reinterpret_cast(target); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::AArch64::LDRXl) - .addReg(reg) - .addExpr(codegen.CreateDataExpr(target_addr))); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::BR).addReg(reg)); - return Error(); - } - } - return Error("Unsupported trampoline type"); -} - -static void* calculatePcRelativeAddress(void* data, size_t pc_offset, - size_t offset, bool page_align) { - uintptr_t data_addr = reinterpret_cast(data); - assert((data_addr & 3) == 0 && "Unaligned data address"); - assert((pc_offset & 3) == 0 && "Unaligned PC offset"); - - data_addr += pc_offset; // Add the PC - if (page_align) { - data_addr &= ~0x0fff; // Align to 4KB - offset <<= 12; - } - data_addr += offset; // Add the offset - return reinterpret_cast(data_addr); -} - -static void reserveRegs(CodeGenerator& codegen, const llvm::MCInst& inst) { - for (size_t i = 0; i < inst.getNumOperands(); i++) { - const llvm::MCOperand& op = inst.getOperand(i); - if (op.isReg()) { - codegen.ReserveRegister(op.getReg()); - } - } -} - -Error TargetAARCH64::RewriteInstruction(const llvm::MCInst& inst, - CodeGenerator& codegen, void* data, - size_t offset, - bool& possible_end_of_function) { - switch (inst.getOpcode()) { - case llvm::AArch64::ADDXri: - case llvm::AArch64::ANDXri: - case llvm::AArch64::LDRXui: - case llvm::AArch64::MOVNWi: - case llvm::AArch64::MOVNXi: - case llvm::AArch64::MOVZWi: - case llvm::AArch64::MOVZXi: - case llvm::AArch64::MRS: - case llvm::AArch64::ORRWrs: - case llvm::AArch64::ORRXrs: - case llvm::AArch64::STPDi: - case llvm::AArch64::STPXi: - case llvm::AArch64::STPXpre: - case llvm::AArch64::STRBBui: - case llvm::AArch64::STRSui: - case llvm::AArch64::STRWui: - case llvm::AArch64::STRXpre: - case llvm::AArch64::STRXui: - case llvm::AArch64::SUBSWri: - case llvm::AArch64::SUBSXri: - case llvm::AArch64::SUBXri: { - reserveRegs(codegen, inst); - possible_end_of_function = false; - codegen.AddInstruction(inst); - break; - } - case llvm::AArch64::ADRP: { - uint32_t Rd = inst.getOperand(0).getReg(); - uint64_t imm = inst.getOperand(1).getImm(); - possible_end_of_function = false; - reserveRegs(codegen, inst); - - uint64_t addr = reinterpret_cast( - calculatePcRelativeAddress(data, offset, imm, true)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::AArch64::LDRXl) - .addReg(Rd) - .addExpr(codegen.CreateDataExpr(addr))); - break; - } - case llvm::AArch64::B: { - uint64_t imm = inst.getOperand(0).getImm() << 2; - possible_end_of_function = true; - - uint64_t addr = reinterpret_cast( - calculatePcRelativeAddress(data, offset, imm, false)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::AArch64::LDRXl) - .addReg(llvm::AArch64::X17) - .addExpr(codegen.CreateDataExpr(addr))); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::BR).addReg(llvm::AArch64::X17)); - break; - } - case llvm::AArch64::BL: { - uint64_t imm = inst.getOperand(0).getImm() << 2; - possible_end_of_function = true; - - uint64_t addr = reinterpret_cast( - calculatePcRelativeAddress(data, offset, imm, false)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::AArch64::LDRXl) - .addReg(llvm::AArch64::X17) - .addExpr(codegen.CreateDataExpr(addr))); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::BLR).addReg(llvm::AArch64::X17)); - break; - } - case llvm::AArch64::CBZX: { - reserveRegs(codegen, inst); - uint32_t Rt = inst.getOperand(0).getReg(); - uint64_t imm = inst.getOperand(1).getImm() << 2; - possible_end_of_function = false; - - uint64_t addr = reinterpret_cast( - calculatePcRelativeAddress(data, offset, imm, false)); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::CBNZX).addReg(Rt).addImm(12 >> 2)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::AArch64::LDRXl) - .addReg(llvm::AArch64::X17) - .addExpr(codegen.CreateDataExpr(addr))); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::AArch64::BR).addReg(llvm::AArch64::X17)); - break; - } - default: { - possible_end_of_function = true; - return Error("Unhandled instruction: %s (OpcodeId: %d)", - codegen.PrintInstruction(inst).c_str(), inst.getOpcode()); - } - } - return Error(); -} - -void* TargetAARCH64::CheckIsPLT(void* old_function, void* new_function) { - // Currently only handles the case where the first instruction in the - // function is an uncoditional branch. - std::unique_ptr disassembler(CreateDisassembler(old_function)); - if (!disassembler) { - return old_function; - } - - void* func_addr = GetLoadAddress(old_function); - llvm::MCInst inst; - uint64_t inst_size = 0; - if (!disassembler->GetInstruction(func_addr, 0, inst, inst_size)) { - return old_function; - } - - switch (inst.getOpcode()) { - case llvm::AArch64::B: { - uint64_t imm = inst.getOperand(0).getImm() << 2; - return calculatePcRelativeAddress(func_addr, 0, imm, false); - } - } - - return old_function; -} diff --git a/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.h b/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.h deleted file mode 100644 index 1698dc9bcf..0000000000 --- a/gapii/interceptor-lib/cc/lib/AArch64/target_aarch64.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_AARCH64_TARGET_AARCH64_H_ -#define INTERCEPTOR_AARCH64_TARGET_AARCH64_H_ - -#include "target.h" - -namespace interceptor { - -class TargetAARCH64 : public Target { - public: - CodeGenerator* GetCodeGenerator(void* address, - size_t start_alignment) override; - - Disassembler* CreateDisassembler(void* address) override; - - size_t GetCodeAlignment() const override { return 4; } - - std::vector GetTrampolineConfigs( - uintptr_t start_address) const override; - - Error EmitTrampoline(const TrampolineConfig& config, CodeGenerator& codegen, - void* target) override; - - Error RewriteInstruction(const llvm::MCInst& inst, CodeGenerator& codegen, - void* data, size_t offset, - bool& possible_end_of_function) override; - - void* CheckIsPLT(void* old_function, void* new_function) override; - - private: - enum TrampolineType { - FULL_TRAMPOLINE = 0, // Full trampoline with an absolute jump - FIRST_4G_TRAMPOLINE = 1, // Can target the first 4GB of the memory - }; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_AARCH64_TARGET_AARCH64_H_ diff --git a/gapii/interceptor-lib/cc/lib/ARM/target_arm.cpp b/gapii/interceptor-lib/cc/lib/ARM/target_arm.cpp deleted file mode 100644 index ee773f55fc..0000000000 --- a/gapii/interceptor-lib/cc/lib/ARM/target_arm.cpp +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "target_arm.h" - -#include - -#include "MCTargetDesc/ARMBaseInfo.h" -#include "MCTargetDesc/ARMMCTargetDesc.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstBuilder.h" - -#include "code_generator.h" -#include "disassembler.h" - -using namespace interceptor; - -static bool IsThumb(void* ptr) { return reinterpret_cast(ptr) & 1; } - -static bool IsThumb(const CodeGenerator& codegen) { - llvm::Triple::ArchType arch = - codegen.GetSubtargetInfo().getTargetTriple().getArch(); - return arch == llvm::Triple::thumb || arch == llvm::Triple::thumbeb; -} - -static llvm::Triple GetTriple(void* addr) { - llvm::Triple triple(llvm::sys::getProcessTriple()); - assert((triple.getArch() == llvm::Triple::arm || - triple.getArch() == llvm::Triple::thumb) && - "Invalid default host triple for target"); - if (IsThumb(addr)) { - llvm::StringRef arm_name = triple.getArchName(); - std::string thumb_name("thumb"); - thumb_name += arm_name.substr(3); - triple.setArchName(thumb_name); - } - return triple; -} - -CodeGenerator* TargetARM::GetCodeGenerator(void* address, - size_t start_alignment) { - return CodeGenerator::Create(GetTriple(address), start_alignment); -} - -Disassembler* TargetARM::CreateDisassembler(void* address) { - return Disassembler::Create(GetTriple(address)); -} - -void* TargetARM::GetLoadAddress(void* addr) { - uintptr_t addr_val = reinterpret_cast(addr); - addr_val &= ~1; - return reinterpret_cast(addr_val); -} - -void* TargetARM::FixupCallbackFunction(void* old_function, void* new_function) { - if (IsThumb(old_function)) { - uintptr_t new_func_addr = reinterpret_cast(new_function); - new_func_addr |= 1; - return reinterpret_cast(new_func_addr); - } - return new_function; -} - -std::vector TargetARM::GetTrampolineConfigs( - uintptr_t start_address) const { - std::vector configs; - configs.push_back({FULL_TRAMPOLINE, false, 0, 0xffffffff}); - return configs; -} - -Error TargetARM::EmitTrampoline(const TrampolineConfig& config, - CodeGenerator& codegen, void* target) { - switch (config.type) { - case FULL_TRAMPOLINE: { - uint32_t target_addr = (uintptr_t)target; - if (IsThumb(codegen)) { - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::ARM::t2LDRpci) - .addReg(llvm::ARM::PC) - .addExpr(codegen.CreateDataExpr(target_addr))); - } else { - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::LDRi12) - .addReg(llvm::ARM::PC) - .addExpr(codegen.CreateDataExpr(target_addr)) - .addImm(0) - .addImm(llvm::ARMCC::AL) - .addImm(0)); - } - return Error(); - } - } - return Error("Unsupported trampoline type"); -} - -static void* calculatePcRelativeAddressArm(void* data, size_t pc_offset, - size_t offset) { - uintptr_t data_addr = reinterpret_cast(data); - assert((data_addr & 3) == 0 && "Unaligned data address"); - assert((pc_offset & 3) == 0 && "Unaligned PC offset"); - - data_addr += pc_offset; // Add the PC - data_addr += 8; // Add the 8 byte implicit offset - data_addr += offset; // Add the offset - return reinterpret_cast(data_addr); -} - -static void* calculatePcRelativeAddressThumb(void* data, size_t pc_offset, - size_t offset, bool align) { - uintptr_t data_addr = reinterpret_cast(data); - assert((data_addr & 1) == 0 && "Unaligned data address"); - assert((pc_offset & 1) == 0 && "Unaligned PC offset"); - - data_addr += pc_offset; // Add the PC - data_addr += 1; // Add 1 for the thumb bit - data_addr += 4; // Add the 4 byte implicit offset - if (align) data_addr &= ~3; // Align to 4 byte - data_addr += offset; // Add the offset - return reinterpret_cast(data_addr); -} - -static uint32_t getThumbPc(void* data, size_t offset) { - uintptr_t data_addr = reinterpret_cast(data); - data_addr += offset; - data_addr += 4; - data_addr &= ~1; - return data_addr; -} - -static bool hasPcOperand(const llvm::MCInst& inst) { - for (size_t i = 0; i < inst.getNumOperands(); ++i) { - const llvm::MCOperand& op = inst.getOperand(i); - if (op.isReg() && op.getReg() == llvm::ARM::PC) return true; - } - return false; -} - -Error TargetARM::RewriteInstruction(const llvm::MCInst& inst, - CodeGenerator& codegen, void* data, - size_t offset, - bool& possible_end_of_function) { - switch (inst.getOpcode()) { - case llvm::ARM::tADDspi: - case llvm::ARM::tSUBspi: { - possible_end_of_function = false; - codegen.AddInstruction(inst); - break; - } - case llvm::ARM::MRC: - case llvm::ARM::MOVi16: - case llvm::ARM::tMOVi8: { - uint32_t RdRt = inst.getOperand(0).getReg(); - possible_end_of_function = (RdRt == llvm::ARM::PC); - codegen.AddInstruction(inst); - break; - } - case llvm::ARM::t2LDMIA_UPD: { - possible_end_of_function = hasPcOperand(inst); - codegen.AddInstruction(inst); - break; - } - case llvm::ARM::CMPrr: - case llvm::ARM::LDR_PRE_IMM: - case llvm::ARM::LDR_PRE_REG: - case llvm::ARM::LDR_POST_IMM: - case llvm::ARM::LDR_POST_REG: - case llvm::ARM::LDRH_PRE: - case llvm::ARM::LDRH_POST: - case llvm::ARM::LDRH: - case llvm::ARM::LDRB_PRE_IMM: - case llvm::ARM::LDRB_PRE_REG: - case llvm::ARM::LDRB_POST_IMM: - case llvm::ARM::LDRB_POST_REG: - case llvm::ARM::LDRBi12: - case llvm::ARM::LDRSH_PRE: - case llvm::ARM::LDRSH_POST: - case llvm::ARM::LDRSH: - case llvm::ARM::LDRSB_PRE: - case llvm::ARM::LDRSB_POST: - case llvm::ARM::LDRSB: - case llvm::ARM::STR_PRE_IMM: - case llvm::ARM::STR_PRE_REG: - case llvm::ARM::STR_POST_IMM: - case llvm::ARM::STR_POST_REG: - case llvm::ARM::STRi12: - case llvm::ARM::STRH_PRE: - case llvm::ARM::STRH_POST: - case llvm::ARM::STRH: - case llvm::ARM::STRB_PRE_IMM: - case llvm::ARM::STRB_PRE_REG: - case llvm::ARM::STRB_POST_IMM: - case llvm::ARM::STRB_POST_REG: - case llvm::ARM::STRBi12: - case llvm::ARM::MOVr: - case llvm::ARM::STMDA_UPD: - case llvm::ARM::STMDB_UPD: - case llvm::ARM::STRD: - case llvm::ARM::STRD_PRE: - case llvm::ARM::SUBri: - case llvm::ARM::tADDi3: - case llvm::ARM::tADDi8: - case llvm::ARM::tADDrSP: - case llvm::ARM::tADDrSPi: - case llvm::ARM::tBIC: - case llvm::ARM::tCMPi8: - case llvm::ARM::tLDRi: - case llvm::ARM::tLDRspi: - case llvm::ARM::tLSRri: - case llvm::ARM::tMOVr: - case llvm::ARM::tPUSH: - case llvm::ARM::tSTRspi: - case llvm::ARM::tSUBrr: - case llvm::ARM::t2ADDri: - case llvm::ARM::t2ADDri12: - case llvm::ARM::t2BICri: - case llvm::ARM::t2BICrr: - case llvm::ARM::t2CMPri: - case llvm::ARM::t2LDRi12: - case llvm::ARM::t2LDRDi8: - case llvm::ARM::t2LDRD_PRE: - case llvm::ARM::t2LDRD_POST: - case llvm::ARM::t2MOVi: - case llvm::ARM::t2MOVr: - case llvm::ARM::t2MOVTi16: - case llvm::ARM::t2STMDB_UPD: - case llvm::ARM::t2STR_PRE: - case llvm::ARM::t2STRDi8: - case llvm::ARM::t2STRD_PRE: - case llvm::ARM::t2STRD_POST: - case llvm::ARM::t2SUBri: - case llvm::ARM::VSTMDDB_UPD: { - if (hasPcOperand(inst)) - return Error( - "Instruction not handled yet when one of the operand is PC"); - possible_end_of_function = false; - codegen.AddInstruction(inst); - break; - } - case llvm::ARM::tADDhirr: { - uint32_t Rdn = inst.getOperand(0).getReg(); - uint32_t Rm = inst.getOperand(2).getReg(); - possible_end_of_function = (Rdn == llvm::ARM::PC); - - if (Rm == llvm::ARM::PC) { - if (Rdn == llvm::ARM::PC) return Error("'add pc, pc' is UNPREDICTABLE"); - - uint32_t pc_value = getThumbPc(data, offset); - uint32_t scratch_reg = - Rdn != llvm::ARM::R0 ? llvm::ARM::R0 : llvm::ARM::R1; - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::tPUSH) - .addImm(0) - .addImm(0) - .addReg(scratch_reg)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::tLDRpci) - .addReg(scratch_reg) - .addExpr(codegen.CreateDataExpr(pc_value))); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::tADDhirr) - .addReg(Rdn) - .addImm(0) - .addReg(scratch_reg)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::tPOP) - .addImm(0) - .addImm(0) - .addReg(scratch_reg)); - } else { - codegen.AddInstruction(inst); - } - break; - } - case llvm::ARM::LDRi12: { - uint32_t Rt = inst.getOperand(0).getReg(); - uint32_t Rn = inst.getOperand(1).getReg(); - int64_t imm = inst.getOperand(2).getImm(); - int64_t p = inst.getOperand(3).getImm(); - possible_end_of_function = (Rt == llvm::ARM::PC); - - if (Rn == llvm::ARM::PC) { - void* load_source = calculatePcRelativeAddressArm(data, offset, imm); - uint32_t load_data = 0; - memcpy(&load_data, load_source, sizeof(uint32_t)); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::LDRi12) - .addReg(Rt) - .addExpr(codegen.CreateDataExpr(load_data)) - .addImm(0) - .addImm(p) - .addImm(0)); - } else { - codegen.AddInstruction(inst); - } - break; - } - case llvm::ARM::tLDRpci: - case llvm::ARM::t2LDRpci: { - uint32_t Rt = inst.getOperand(0).getReg(); - int64_t imm = inst.getOperand(1).getImm(); - possible_end_of_function = (Rt == llvm::ARM::PC); - - void* load_source = - calculatePcRelativeAddressThumb(data, offset, imm, true); - uint32_t load_data = 0; - memcpy(&load_data, load_source, sizeof(uint32_t)); - llvm::MCInst new_inst = inst; // TODO: Use MCInstBuilder - new_inst.getOperand(1) = - llvm::MCOperand::createExpr(codegen.CreateDataExpr(load_data)); - codegen.AddInstruction(new_inst); - break; - } - case llvm::ARM::Bcc: { - uint32_t imm = inst.getOperand(0).getImm(); - uint32_t pred = inst.getOperand(1).getImm(); - possible_end_of_function = true; - - void* target = calculatePcRelativeAddressArm(data, offset, imm); - uint32_t target_addr = reinterpret_cast(target); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::LDRi12) - .addReg(llvm::ARM::PC) - .addExpr(codegen.CreateDataExpr(target_addr)) - .addImm(0) - .addImm(pred) - .addImm(0)); - break; - } - case llvm::ARM::t2B: { - uint32_t imm = inst.getOperand(0).getImm(); - possible_end_of_function = true; - - void* target = calculatePcRelativeAddressThumb(data, offset, imm, false); - uint32_t target_addr = reinterpret_cast(target); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::t2LDRpci) - .addReg(llvm::ARM::PC) - .addExpr(codegen.CreateDataExpr(target_addr))); - break; - } - case llvm::ARM::tBL: { - uint32_t imm = inst.getOperand(2).getImm(); - possible_end_of_function = false; - - uint32_t lr_offset = 5 + codegen.GetAlignmentOffset(4); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::t2ADDri12) - .addReg(llvm::ARM::LR) // Rd - .addReg(llvm::ARM::PC) // Rn - .addImm(lr_offset) // imm - .addImm(0) // - - .addImm(0) // - - .addReg(llvm::ARM::R0)); // S - - void* target = calculatePcRelativeAddressThumb(data, offset, imm, false); - uint32_t target_addr = reinterpret_cast(target); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::ARM::t2LDRpci) - .addReg(llvm::ARM::PC) - .addExpr(codegen.CreateDataExpr(target_addr))); - break; - } - default: { - possible_end_of_function = true; - return Error("Unhandled instruction: %s (OpcodeId: %d)", - codegen.PrintInstruction(inst).c_str(), inst.getOpcode()); - } - } - return Error(); -} - -void* TargetARM::CheckIsPLT(void* old_function, void* new_function) { - // Currently only handles the case where the first instruction in the - // function is an uncoditional branch. - std::unique_ptr disassembler(CreateDisassembler(old_function)); - if (!disassembler) { - return old_function; - } - - void* func_addr = GetLoadAddress(old_function); - llvm::MCInst inst; - uint64_t inst_size = 0; - if (!disassembler->GetInstruction(func_addr, 0, inst, inst_size)) { - return old_function; - } - - switch (inst.getOpcode()) { - case llvm::ARM::Bcc: { - uint32_t imm = inst.getOperand(0).getImm(); - uint32_t pred = inst.getOperand(1).getImm(); - if (pred == 0xE) { // Unconditional. - return calculatePcRelativeAddressArm(func_addr, 0, imm); - } - break; - } - } - - return old_function; -} diff --git a/gapii/interceptor-lib/cc/lib/ARM/target_arm.h b/gapii/interceptor-lib/cc/lib/ARM/target_arm.h deleted file mode 100644 index c93fdb971c..0000000000 --- a/gapii/interceptor-lib/cc/lib/ARM/target_arm.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_ARM_TARGET_ARM_H_ -#define INTERCEPTOR_ARM_TARGET_ARM_H_ - -#include "target.h" - -namespace interceptor { - -class TargetARM : public Target { - public: - CodeGenerator* GetCodeGenerator(void* address, - size_t start_alignment) override; - - Disassembler* CreateDisassembler(void* address) override; - - size_t GetCodeAlignment() const override { return 4; } - - void* GetLoadAddress(void* addr) override; - - std::vector GetTrampolineConfigs( - uintptr_t start_address) const override; - - Error EmitTrampoline(const TrampolineConfig& config, CodeGenerator& codegen, - void* target) override; - - Error RewriteInstruction(const llvm::MCInst& inst, CodeGenerator& codegen, - void* data, size_t offset, - bool& possible_end_of_function) override; - - void* FixupCallbackFunction(void* old_function, void* new_function) override; - - void* CheckIsPLT(void* old_function, void* new_function) override; - - private: - enum TrampolineType { - FULL_TRAMPOLINE = 0, // Full trampoline with an absolute jump - }; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_ARM_TARGET_ARM_H_ diff --git a/gapii/interceptor-lib/cc/lib/X86/target_x86.cpp b/gapii/interceptor-lib/cc/lib/X86/target_x86.cpp deleted file mode 100644 index b033e78b86..0000000000 --- a/gapii/interceptor-lib/cc/lib/X86/target_x86.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "target_x86.h" - -#include - -#include "MCTargetDesc/X86MCTargetDesc.h" -#include "llvm/ADT/Triple.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstBuilder.h" - -#include "code_generator.h" -#include "disassembler.h" - -using namespace interceptor; - -static llvm::Triple GetTriple() { - llvm::Triple triple(llvm::sys::getProcessTriple()); - assert(triple.getArch() == llvm::Triple::x86 && - "Invalid default host triple for target"); - return triple; -} - -CodeGenerator* TargetX86::GetCodeGenerator(void* address, - size_t start_alignment) { - return CodeGenerator::Create(GetTriple(), start_alignment); -} - -Disassembler* TargetX86::CreateDisassembler(void* address) { - return Disassembler::Create(GetTriple()); -} - -std::vector TargetX86::GetTrampolineConfigs( - uintptr_t start_address) const { - std::vector configs; - configs.push_back({FULL_TRAMPOLINE, false, 0, 0xffffffff}); - return configs; -} - -Error TargetX86::EmitTrampoline(const TrampolineConfig& config, - CodeGenerator& codegen, void* target) { - switch (config.type) { - case FULL_TRAMPOLINE: { - uintptr_t target_addr = reinterpret_cast(target); - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::X86::JMP_4).addImm(target_addr)); - return Error(); - } - } - return Error("Unsupported trampoline type"); -} - -static uintptr_t calculatePcRelativeAddress(void* data, int64_t pc_offset, - size_t offset, size_t instr_size) { - uintptr_t data_addr = reinterpret_cast(data); - data_addr += pc_offset; - data_addr += offset; - data_addr += instr_size; - return data_addr; -} - -// Checks if the given address is the address of the __x86.get_pc_thunk.bx -// function with comparing the instruction sequence to the following opcodes: -// MOVL (%esp), %ebx; RETL -// Additionally we detect functions with NOP instructions between the above -// sepcified instructions. -static Error IsGetPcThunk(TargetX86* target, void* address, bool& res) { - std::unique_ptr disassembler( - target->CreateDisassembler(address)); - if (!disassembler) return Error("Failed to create disassembler"); - - // The decode state represent the next instruction we are expecting - enum class DetectState : uint8_t { MOV, RET }; - DetectState state = DetectState::MOV; - - size_t offset = 0; - while (true) { - llvm::MCInst inst; - uint64_t inst_size = 0; - if (!disassembler->GetInstruction(address, offset, inst, inst_size)) - return Error("Failed to disassemble instruction at %p + %zd", address, - offset); - - switch (inst.getOpcode()) { - case llvm::X86::NOOP: - case llvm::X86::NOOPL: - case llvm::X86::NOOPW: - break; - case llvm::X86::RET: - case llvm::X86::RETL: - case llvm::X86::RETW: - res = (state == DetectState::RET); - return Error(); - case llvm::X86::MOV32rm: - if (state != DetectState::MOV) { - res = false; - return Error(); - } else if (inst.getNumOperands() < 2) { - res = false; - return Error(); - } - const llvm::MCOperand &op0 = inst.getOperand(0), - op1 = inst.getOperand(1); - if (!op0.isReg() || op0.getReg() != llvm::X86::EBX || !op1.isReg() || - op1.getReg() != llvm::X86::ESP) { - res = false; - return Error(); - } - state = DetectState::RET; - break; - } - offset += inst_size; - } -} - -Error TargetX86::RewriteInstruction(const llvm::MCInst& inst, - CodeGenerator& codegen, void* data, - size_t offset, - bool& possible_end_of_function) { - switch (inst.getOpcode()) { - case llvm::X86::AND32rr: - case llvm::X86::AND32mr: - case llvm::X86::AND32ri8: - case llvm::X86::AND32mi8: - case llvm::X86::AND32i32: - case llvm::X86::AND32ri: - case llvm::X86::AND32mi: - case llvm::X86::AND32rm: - case llvm::X86::LEA32r: - case llvm::X86::MOV32ao32: - case llvm::X86::MOV32rm: - case llvm::X86::MOV32rr: - case llvm::X86::PUSH32r: - case llvm::X86::SUB32ri: - case llvm::X86::SUB32ri8: { - possible_end_of_function = false; - codegen.AddInstruction(inst); - break; - } - case llvm::X86::CALLpcrel32: { - if (inst.getNumOperands() != 1) - return Error("CALL not supported when has more then 1 operand"); - possible_end_of_function = false; - uintptr_t target_addr = calculatePcRelativeAddress( - data, inst.getOperand(0).getImm(), offset, 5); - - bool is_get_pc_thunk = false; - Error error = IsGetPcThunk(this, reinterpret_cast(target_addr), - is_get_pc_thunk); - if (error.Fail()) return error; - - if (is_get_pc_thunk) { - uintptr_t return_value = calculatePcRelativeAddress(data, 0, offset, 5); - codegen.AddInstruction(llvm::MCInstBuilder(llvm::X86::MOV32ri) - .addReg(llvm::X86::EBX) - .addImm(return_value)); - } else { - codegen.AddInstruction( - llvm::MCInstBuilder(llvm::X86::CALLpcrel32).addImm(target_addr)); - } - break; - } - default: { - possible_end_of_function = true; - return Error("Unhandled instruction: %s (OpcodeId: %d)", - codegen.PrintInstruction(inst).c_str(), inst.getOpcode()); - } - } - return Error(); -} diff --git a/gapii/interceptor-lib/cc/lib/X86/target_x86.h b/gapii/interceptor-lib/cc/lib/X86/target_x86.h deleted file mode 100644 index d9456d9c45..0000000000 --- a/gapii/interceptor-lib/cc/lib/X86/target_x86.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_X86_TARGET_X86_H_ -#define INTERCEPTOR_X86_TARGET_X86_H_ - -#include "target.h" - -namespace interceptor { - -class TargetX86 : public Target { - public: - CodeGenerator* GetCodeGenerator(void* address, - size_t start_alignment) override; - - Disassembler* CreateDisassembler(void* address) override; - - size_t GetCodeAlignment() const override { return 4; } - - std::vector GetTrampolineConfigs( - uintptr_t start_address) const override; - - Error EmitTrampoline(const TrampolineConfig& config, CodeGenerator& codegen, - void* target) override; - - Error RewriteInstruction(const llvm::MCInst& inst, CodeGenerator& codegen, - void* data, size_t offset, - bool& possible_end_of_function) override; - - private: - enum TrampolineType { - FULL_TRAMPOLINE = 0, // Full trampoline with an absolute jump - }; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_X86_TARGET_X86_H_ diff --git a/gapii/interceptor-lib/cc/lib/code_generator.cpp b/gapii/interceptor-lib/cc/lib/code_generator.cpp deleted file mode 100644 index 8dde310980..0000000000 --- a/gapii/interceptor-lib/cc/lib/code_generator.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "code_generator.h" - -using namespace interceptor; - -CodeGenerator::CodeGenerator(const llvm::Triple& triple, size_t start_alignment) - : start_alignment_(start_alignment), triple_(triple), code_stream_(code_) { - // Set the start alignment of the stream to match with the specified value - for (size_t i = 0; i < start_alignment_; ++i) code_stream_.write((char)0); -} - -CodeGenerator* CodeGenerator::Create(const llvm::Triple& triple, - size_t start_alignment) { - std::unique_ptr codegen( - new CodeGenerator(triple, start_alignment)); - if (codegen->Initialize()) return codegen.release(); - return nullptr; -} - -void CodeGenerator::AddInstruction(const llvm::MCInst& inst) { - size_t offset = code_.size(); - llvm::SmallVector new_fixups; - asm_->getEmitter().encodeInstruction(inst, code_stream_, new_fixups, *sti_); - - // We have to offset the fixups with the offset of the generated instruction - // in the data stream because encodeInstruction emits them as if it is - // writing the new instructions from the beginning of the stream. - for (llvm::MCFixup& fixup : new_fixups) - fixup.setOffset(fixup.getOffset() + offset); - - fixups_.insert(fixups_.end(), new_fixups.begin(), new_fixups.end()); -} - -bool CodeGenerator::Initialize() { - std::string error; - - const llvm::Target* target = - llvm::TargetRegistry::lookupTarget(triple_.str().c_str(), error); - if (!target) return false; - - mri_.reset(target->createMCRegInfo(triple_.str().c_str())); - if (!mri_) return false; - - sti_.reset(target->createMCSubtargetInfo(triple_.str().c_str(), "", "")); - if (!sti_) return false; - - mii_.reset(target->createMCInstrInfo()); - if (!mii_) return false; - - llvm::MCTargetOptions options; - - auto asmb = std::unique_ptr( - target->createMCAsmBackend(*sti_, *mri_, options)); - if (!asmb) return false; - - ctx_.reset(new llvm::MCContext(nullptr, mri_.get(), nullptr)); - if (!ctx_) return false; - - auto codegen = std::unique_ptr( - target->createMCCodeEmitter(*mii_, *mri_, *ctx_)); - if (!codegen) return false; - - // These are used only for logging and error reporting. Don't fail if we - // haven't managed to create them. - asmi_.reset(target->createMCAsmInfo(*mri_, triple_.str().c_str())); - if (asmi_) { - ipr_.reset(target->createMCInstPrinter(llvm::Triple(triple_), 0, *asmi_, - *mii_, *mri_)); - } - - auto writer = asmb->createObjectWriter(code_stream_); - if (!writer) return false; - - asm_.reset(new llvm::MCAssembler(*ctx_, std::move(asmb), std::move(codegen), - std::move(writer))); - if (!asm_) return false; - - return true; -} - -size_t CodeGenerator::LayoutCode() { - for (const ConstantPoolDataExpr* pool : const_pool_exprs_) - const_cast(pool)->allocate(code_stream_); - return code_.size() - start_alignment_; -} - -Error CodeGenerator::LinkCode(uintptr_t location) { - for (const ConstantPoolDataExpr* pool : const_pool_exprs_) - const_cast(pool)->setBaseLocation(location); - - for (const llvm::MCFixup& fixup : fixups_) { - const llvm::MCExpr* expr = fixup.getValue(); - - llvm::MCValue mc_value; - uint64_t value = 0; - if (!expr->evaluateAsRelocatable(mc_value, nullptr, &fixup)) - return Error("Failed to evalue the value of an MCFixup"); - value = mc_value.getConstant(); - - auto& asmb = asm_->getBackend(); - int flags = asmb.getFixupKindInfo(fixup.getKind()).Flags; - bool pc_rel = flags & llvm::MCFixupKindInfo::FKF_IsPCRel; - bool align_pc = flags & llvm::MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; - if (pc_rel) { - uint64_t offset = fixup.getOffset(); - if (align_pc) offset &= ~0x3; - value -= offset; - value -= location; - } - - asmb.applyFixup(*asm_, fixup, mc_value, - llvm::makeMutableArrayRef(code_.data(), code_.size()), - value, pc_rel, sti_.get()); - } - - if (start_alignment_ != 0) - code_.erase(code_.begin(), code_.begin() + start_alignment_); - - return Error(); -} - -const llvm::SmallVectorImpl& CodeGenerator::GetCode() const { - return code_; -} - -const llvm::MCSubtargetInfo& CodeGenerator::GetSubtargetInfo() const { - return *sti_; -} - -uint32_t CodeGenerator::GetAlignmentOffset(uint32_t alignment_base) const { - return code_.size() % alignment_base; -} - -std::string CodeGenerator::PrintInstruction(const llvm::MCInst& inst) { - std::string s; - llvm::raw_string_ostream os(s); - if (ipr_) - ipr_->printInst(&inst, os, "", *sti_); - else - inst.dump_pretty(os, nullptr, " "); - return os.str(); -} diff --git a/gapii/interceptor-lib/cc/lib/code_generator.h b/gapii/interceptor-lib/cc/lib/code_generator.h deleted file mode 100644 index 18da24c262..0000000000 --- a/gapii/interceptor-lib/cc/lib/code_generator.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_CONSTNT_POOL_DATA_EXPR_H_ -#define INTERCEPTOR_CONSTNT_POOL_DATA_EXPR_H_ - -#include -#include -#include -#include - -#include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCAssembler.h" -#include "llvm/MC/MCCodeEmitter.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCFixupKindInfo.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCObjectWriter.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" - -#include "constant_pool_data_expr.h" -#include "error.h" - -namespace interceptor { - -class CodeGenerator { - public: - static CodeGenerator* Create(const llvm::Triple& triple, - size_t start_alignment = 0); - - void AddInstruction(const llvm::MCInst& inst); - - size_t LayoutCode(); - - Error LinkCode(uintptr_t location); - - const llvm::SmallVectorImpl& GetCode() const; - - uint32_t GetAlignmentOffset(uint32_t alignment_base) const; - - template - const llvm::MCExpr* CreateDataExpr(T value, size_t alignment = A); - - const llvm::MCSubtargetInfo& GetSubtargetInfo() const; - - std::string PrintInstruction(const llvm::MCInst& inst); - - void ReserveRegister(unsigned int reg) { reserved_regs_.insert(reg); } - - bool IsRegisterReserved(unsigned int reg) { - return reserved_regs_.find(reg) != reserved_regs_.end(); - } - - private: - CodeGenerator(const llvm::Triple& triple, size_t start_alignment); - - bool Initialize(); - - size_t start_alignment_; - - llvm::Triple triple_; - std::unique_ptr mri_; - std::unique_ptr sti_; - std::unique_ptr mii_; - std::unique_ptr ipr_; - std::unique_ptr asmi_; - std::unique_ptr ctx_; - std::unique_ptr asm_; - - std::vector instructions_; - std::vector const_pool_exprs_; - - llvm::SmallVector code_; - llvm::raw_svector_ostream code_stream_; - llvm::SmallVector fixups_; - - std::unordered_set reserved_regs_; -}; - -template -const llvm::MCExpr* CodeGenerator::CreateDataExpr(T value, size_t alignment) { - const llvm::MCExpr* value_exp = llvm::MCConstantExpr::create(value, *ctx_); - const_pool_exprs_.emplace_back( - ConstantPoolDataExpr::Create(value_exp, sizeof(T), alignment, *ctx_)); - return const_pool_exprs_.back(); -} - -} // end of namespace interceptor - -#endif // INTERCEPTOR_CONSTNT_POOL_DATA_EXPR_H_ diff --git a/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.cpp b/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.cpp deleted file mode 100644 index 8c2c429326..0000000000 --- a/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "constant_pool_data_expr.h" - -using namespace interceptor; - -ConstantPoolDataExpr::ConstantPoolDataExpr(const llvm::MCExpr* expr, - size_t size, size_t alignment) - : expr_(expr), - size_(size), - alignment_(alignment), - allocated_(false), - base_location_(0) {} - -const ConstantPoolDataExpr* ConstantPoolDataExpr::Create( - const llvm::MCExpr* expr, size_t size, size_t alignment, - llvm::MCContext& ctx) { - return new (ctx) ConstantPoolDataExpr(expr, size, alignment); -} - -void ConstantPoolDataExpr::printImpl(llvm::raw_ostream&, - const llvm::MCAsmInfo*) const {} - -void ConstantPoolDataExpr::fixELFSymbolsInTLSFixups(llvm::MCAssembler&) const {} - -void ConstantPoolDataExpr::visitUsedExpr(llvm::MCStreamer& Streamer) const { - Streamer.visitUsedExpr(*expr_); -} - -llvm::MCFragment* ConstantPoolDataExpr::findAssociatedFragment() const { - llvm_unreachable("FIXME: what goes here?"); -} - -bool ConstantPoolDataExpr::evaluateAsRelocatableImpl( - llvm::MCValue& res, const llvm::MCAsmLayout*, const llvm::MCFixup*) const { - if (!allocated_) return false; - res = llvm::MCValue::get(base_location_); - return true; -} - -bool ConstantPoolDataExpr::allocate(llvm::raw_ostream& data) { - llvm::MCValue val; - if (!expr_->evaluateAsRelocatable(val, nullptr, nullptr)) return false; - - base_location_ += data.tell(); - while (base_location_ % alignment_ != 0) { - data.write((char)0); - base_location_++; - } - - switch (size_) { - case 1: { - uint8_t value = val.getConstant(); - data.write((char*)&value, sizeof(value)); - break; - } - case 2: { - uint16_t value = val.getConstant(); - data.write((char*)&value, sizeof(value)); - break; - } - case 4: { - uint32_t value = val.getConstant(); - data.write((char*)&value, sizeof(value)); - break; - } - case 8: { - uint64_t value = val.getConstant(); - data.write((char*)&value, sizeof(value)); - break; - } - default: { - assert(false && "Unsupported alignment"); - return false; - } - } - - allocated_ = true; - return true; -} - -void ConstantPoolDataExpr::setBaseLocation(uintptr_t location) { - base_location_ += location; -} diff --git a/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.h b/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.h deleted file mode 100644 index c1d5885535..0000000000 --- a/gapii/interceptor-lib/cc/lib/constant_pool_data_expr.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_CONSTANT_POOL_DATA_EXPR_H_ -#define INTERCEPTOR_CONSTANT_POOL_DATA_EXPR_H_ - -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/raw_ostream.h" - -namespace interceptor { - -class ConstantPoolDataExpr : public llvm::MCTargetExpr { - public: - void printImpl(llvm::raw_ostream&, const llvm::MCAsmInfo*) const override; - - void visitUsedExpr(llvm::MCStreamer& Streamer) const override; - - llvm::MCFragment* findAssociatedFragment() const override; - - bool evaluateAsRelocatableImpl(llvm::MCValue& res, const llvm::MCAsmLayout*, - const llvm::MCFixup*) const override; - - void fixELFSymbolsInTLSFixups(llvm::MCAssembler&) const override; - - bool allocate(llvm::raw_ostream& data); - - void setBaseLocation(uintptr_t location); - - static const ConstantPoolDataExpr* Create(const llvm::MCExpr* expr, - size_t size, size_t alignment, - llvm::MCContext& ctx); - - static bool classof(const MCExpr* E) { - return E->getKind() == MCExpr::Target; - } - - private: - ConstantPoolDataExpr(const llvm::MCExpr* expr, size_t size, size_t alignment); - - const llvm::MCExpr* expr_; - const size_t size_; - const size_t alignment_; - - bool allocated_; - uintptr_t base_location_; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_CONSTANT_POOL_DATA_EXPR_H_ diff --git a/gapii/interceptor-lib/cc/lib/disassembler.cpp b/gapii/interceptor-lib/cc/lib/disassembler.cpp deleted file mode 100644 index ceda03928c..0000000000 --- a/gapii/interceptor-lib/cc/lib/disassembler.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "disassembler.h" - -using namespace interceptor; - -Disassembler::Disassembler(const llvm::Triple& triple) : triple_(triple) {} - -Disassembler* Disassembler::Create(const llvm::Triple& triple) { - std::unique_ptr disassembler(new Disassembler(triple)); - if (disassembler->Initialize()) return disassembler.release(); - return nullptr; -} - -bool Disassembler::Initialize() { - std::string error; - const llvm::Target* target = - llvm::TargetRegistry::lookupTarget(triple_.str().c_str(), error); - if (!target) return false; - - sti_.reset(target->createMCSubtargetInfo(triple_.str().c_str(), "", "")); - if (!sti_) return false; - - mri_.reset(target->createMCRegInfo(triple_.str().c_str())); - if (!mri_) return false; - - ctx_.reset(new llvm::MCContext(nullptr, mri_.get(), nullptr)); - dis_.reset(target->createMCDisassembler(*sti_, *ctx_)); - if (!dis_) return false; - - return true; -} - -bool Disassembler::GetInstruction(const void* data, size_t offset, - llvm::MCInst& inst, uint64_t& inst_size) { - const uint8_t* data_p = static_cast(data); - llvm::ArrayRef data_arr(data_p + offset, 32); - auto status = dis_->getInstruction(inst, inst_size, data_arr, offset, - llvm::nulls(), llvm::nulls()); - switch (status) { - case llvm::MCDisassembler::Success: - return true; - case llvm::MCDisassembler::Fail: - case llvm::MCDisassembler::SoftFail: - return false; - } - llvm_unreachable("Unexpected decode status"); -} diff --git a/gapii/interceptor-lib/cc/lib/disassembler.h b/gapii/interceptor-lib/cc/lib/disassembler.h deleted file mode 100644 index 73b015b2f0..0000000000 --- a/gapii/interceptor-lib/cc/lib/disassembler.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_DISASSEMBLER_H_ -#define INTERCEPTOR_DISASSEMBLER_H_ - -#include - -#include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCCodeEmitter.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCFixupKindInfo.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" - -namespace interceptor { - -class Disassembler { - public: - static Disassembler* Create(const llvm::Triple& triple); - - bool GetInstruction(const void* data, size_t offset, llvm::MCInst& inst, - uint64_t& inst_size); - - private: - Disassembler(const llvm::Triple& triple); - - bool Initialize(); - - llvm::Triple triple_; - std::unique_ptr mri_; - std::unique_ptr sti_; - std::unique_ptr ctx_; - std::unique_ptr dis_; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_DISASSEMBLER_H_ diff --git a/gapii/interceptor-lib/cc/lib/error.cpp b/gapii/interceptor-lib/cc/lib/error.cpp deleted file mode 100644 index d7c39a70d5..0000000000 --- a/gapii/interceptor-lib/cc/lib/error.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "error.h" - -#include -#include - -using namespace interceptor; - -Error::Error(const char* format, ...) { - va_list args, copy_args; - va_start(args, format); - va_copy(copy_args, args); - - char buf[1024]; - size_t len = vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - if (len >= sizeof(buf)) { - std::vector buf2(len + 1); - vsnprintf(buf2.data(), buf2.size(), format, args); - va_end(copy_args); - message_.assign(buf2.data()); - } else { - message_.assign(buf); - } -} diff --git a/gapii/interceptor-lib/cc/lib/error.h b/gapii/interceptor-lib/cc/lib/error.h deleted file mode 100644 index 8efe28828c..0000000000 --- a/gapii/interceptor-lib/cc/lib/error.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_ERROR_H_ -#define INTERCEPTOR_ERROR_H_ - -#include - -namespace interceptor { - -class Error { - public: - Error() = default; - Error(const char* format, ...) __attribute__((format(printf, 2, 3))); - - bool Fail() const { return !Success(); } - bool Success() const { return message_.empty(); } - bool operator()() const { return Success(); } - - const std::string& GetMessage() const { return message_; } - - private: - std::string message_; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_ERROR_H_ diff --git a/gapii/interceptor-lib/cc/lib/exports.in b/gapii/interceptor-lib/cc/lib/exports.in deleted file mode 100644 index c839c63c22..0000000000 --- a/gapii/interceptor-lib/cc/lib/exports.in +++ /dev/null @@ -1,5 +0,0 @@ -{ - global: - @EXPORTS@ - local: *; -}; \ No newline at end of file diff --git a/gapii/interceptor-lib/cc/lib/interceptor.cpp b/gapii/interceptor-lib/cc/lib/interceptor.cpp deleted file mode 100644 index 2efe13bc29..0000000000 --- a/gapii/interceptor-lib/cc/lib/interceptor.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "interceptor.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "llvm/MC/MCAsmBackend.h" -#include "llvm/MC/MCCodeEmitter.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCFixupKindInfo.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstBuilder.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" - -#include "code_generator.h" -#include "memory_manager.h" -#include "target.h" - -#if defined(__arm__) -#include "ARM/target_arm.h" -#elif defined(__arm64__) || defined(__aarch64__) -#include "AArch64/target_aarch64.h" -#elif defined(__i386__) -#include "X86/target_x86.h" -#endif - -using namespace interceptor; - -namespace interceptor { - -class InterceptorImpl { - public: - InterceptorImpl(); - ~InterceptorImpl(); - - Error InterceptFunction(void* old_function, void* new_function, - void** callback_function); - - private: - Error WriteMemory(void* target, const void* source, size_t num, - bool is_executable); - - Error GetTrampolineSize(const TrampolineConfig& config, void* old_function, - void* new_function, size_t& trampoline_size); - - Error InstallTrampoline(const TrampolineConfig& config, void* old_function, - void* new_function); - - Error RewriteInstructions(void* old_function, size_t rewrite_size, - std::unique_ptr& codegen); - - Error CreateCompensationFunction(void* old_function, size_t rewrite_size, - void** callback_function); - - std::unique_ptr target_; - std::unique_ptr executable_memory_; - std::unordered_map> original_codes_; -}; - -} // end of namespace interceptor - -extern "C" { - -void* InitializeInterceptor() { return new InterceptorImpl(); } - -void TerminateInterceptor(void* interceptor) { - delete static_cast(interceptor); -} - -bool InterceptFunction(void* interceptor, void* old_function, - void* new_function, void** callback_function, - void (*error_callback)(void*, const char*), - void* error_callback_baton) { - Error error = - static_cast(interceptor) - ->InterceptFunction(old_function, new_function, callback_function); - if (error_callback && error.Fail()) { - std::ostringstream oss; - oss << "Intercepting function at " << old_function - << " failed: " << error.GetMessage(); - error_callback(error_callback_baton, oss.str().c_str()); - } - return error.Success(); -} - -} // extern "C" - -static void InitializeLLVM() { - static std::once_flag flag; - - std::call_once(flag, []() { - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllDisassemblers(); - }); -} - -static Error ChangePageProtection(void* ptr, size_t size, int prot) { - uintptr_t page_size = getpagesize(); - uintptr_t page_mask = ~(page_size - 1); - uintptr_t ptr_val = reinterpret_cast(ptr); - uintptr_t base = ptr_val & page_mask; - uintptr_t end = (ptr_val + size + page_size - 1) & page_mask; - if (mprotect(reinterpret_cast(base), end - base, prot) != 0) - return Error("Failed to change protection for %p to %x", ptr, prot); - return Error(); -} - -InterceptorImpl::InterceptorImpl() - : executable_memory_(new MemoryManager(PROT_EXEC | PROT_READ, - MAP_PRIVATE | MAP_ANONYMOUS)) { - InitializeLLVM(); - -#if defined(__arm__) - target_.reset(new TargetARM()); -#elif defined(__arm64__) || defined(__aarch64__) - target_.reset(new TargetAARCH64()); -#elif defined(__i386__) - target_.reset(new TargetX86()); -#else - assert(false && "Not supported architecture!"); -#endif -} - -InterceptorImpl::~InterceptorImpl() { - for (const auto& code : original_codes_) - WriteMemory(code.first, code.second.data(), code.second.size(), true); -} - -Error InterceptorImpl::WriteMemory(void* target, const void* source, size_t num, - bool is_executable) { - int prot = PROT_READ; - if (is_executable) prot |= PROT_EXEC; - - Error error = ChangePageProtection(target, num, prot | PROT_WRITE); - if (error.Fail()) return error; - - memcpy(target, source, num); - - error = ChangePageProtection(target, num, prot); - if (error.Fail()) return error; - - return error; -} - -static size_t GetCodeAligment(Target* target, void* function) { - uintptr_t load_address = - reinterpret_cast(target->GetLoadAddress(function)); - return load_address % target->GetCodeAlignment(); -} - -Error InterceptorImpl::GetTrampolineSize(const TrampolineConfig& config, - void* old_function, void* new_function, - size_t& trampoline_size) { - size_t initial_alignment = GetCodeAligment(target_.get(), old_function); - std::unique_ptr codegen( - target_->GetCodeGenerator(old_function, initial_alignment)); - if (!codegen) return Error("Failed to create a code generator!"); - - Error error = target_->EmitTrampoline(config, *codegen, new_function); - if (error.Fail()) return error; - trampoline_size = codegen->LayoutCode(); - return Error(); -} - -Error InterceptorImpl::InstallTrampoline(const TrampolineConfig& config, - void* old_function, - void* new_function) { - size_t initial_alignment = GetCodeAligment(target_.get(), old_function); - std::unique_ptr codegen( - target_->GetCodeGenerator(old_function, initial_alignment)); - if (!codegen) return Error("Failed to create a code generator!"); - - Error error = target_->EmitTrampoline(config, *codegen, new_function); - if (error.Fail()) return error; - - codegen->LayoutCode(); - - void* load_address = target_->GetLoadAddress(old_function); - codegen->LinkCode(reinterpret_cast(load_address)); - - const llvm::SmallVectorImpl& trampoline = codegen->GetCode(); - - std::vector original_code(trampoline.size()); - memcpy(original_code.data(), load_address, trampoline.size()); - - error = WriteMemory(load_address, trampoline.data(), trampoline.size(), true); - if (error.Fail()) return error; - - original_codes_.emplace(load_address, std::move(original_code)); - return Error(); -} - -Error InterceptorImpl::RewriteInstructions( - void* old_function, size_t rewrite_size, - std::unique_ptr& codegen) { - codegen.reset(target_->GetCodeGenerator(old_function, 0)); - if (!codegen) return Error("Failed to create codegen"); - - std::unique_ptr disassembler( - target_->CreateDisassembler(old_function)); - if (!disassembler) return Error("Failed to create disassembler"); - - size_t offset = 0; - void* func_addr = target_->GetLoadAddress(old_function); - bool reached_end_of_function = false; - while (offset < rewrite_size && !reached_end_of_function) { - llvm::MCInst inst; - uint64_t inst_size = 0; - if (!disassembler->GetInstruction(func_addr, offset, inst, inst_size)) - return Error("Failed to disassemble instruction at %p + %zd", func_addr, - offset); - - Error error = target_->RewriteInstruction(inst, *codegen, func_addr, offset, - reached_end_of_function); - if (error.Fail()) return error; - - offset += inst_size; - } - - if (offset < rewrite_size) - return Error( - "End of function reached after %zd byte when rewriting %zd bytes", - offset, rewrite_size); - - uint8_t* target_addr = static_cast(old_function) + offset; - TrampolineConfig full_config = target_->GetFullTrampolineConfig(); - Error error = target_->EmitTrampoline(full_config, *codegen, target_addr); - if (error.Fail()) return error; - - return Error(); -} - -Error InterceptorImpl::CreateCompensationFunction(void* old_function, - size_t rewrite_size, - void** callback_function) { - std::unique_ptr codegen; - Error error = RewriteInstructions(old_function, rewrite_size, codegen); - if (error.Fail()) return error; - - size_t code_size = codegen->LayoutCode(); - void* target = - executable_memory_->Allocate(code_size, target_->GetCodeAlignment()); - if (!target) return Error("Failed to allocate executable memory"); - - error = codegen->LinkCode(reinterpret_cast(target)); - if (error.Fail()) return error; - - const llvm::SmallVectorImpl& instructions = codegen->GetCode(); - error = WriteMemory(target, instructions.data(), instructions.size(), true); - if (error.Fail()) return error; - - *callback_function = target_->FixupCallbackFunction(old_function, target); - return Error(); -} - -Error InterceptorImpl::InterceptFunction(void* old_function, void* new_function, - void** callback_function) { - old_function = target_->CheckIsPLT(old_function, new_function); - - if (!callback_function) { - // TODO: Verify that the function is long enough for placing a trampoline - // inside it. If it isn't then currently we are overwriting the - // beginning of the next function as well causing potential SIGILL. - - // We don't have to set up a callback function so installing a trampoline - // without generating compensation instructions is sufficient. - TrampolineConfig full_config = target_->GetFullTrampolineConfig(); - return InstallTrampoline(full_config, old_function, new_function); - } - - uintptr_t old_address = reinterpret_cast(old_function); - - size_t aligned_full_trampoline_size = 0; - TrampolineConfig full_config = target_->GetFullTrampolineConfig(); - Error error = GetTrampolineSize(full_config, nullptr, new_function, - aligned_full_trampoline_size); - if (error.Fail()) return error; - - std::vector configs = - target_->GetTrampolineConfigs(old_address); - for (const auto& config : configs) { - if (config.IsFullTrampoline()) { - size_t trampoline_size = 0; - error = GetTrampolineSize(config, old_function, new_function, - trampoline_size); - if (error.Fail()) return error; - - error = CreateCompensationFunction(old_function, trampoline_size, - callback_function); - if (error.Fail()) return error; - - return InstallTrampoline(config, old_function, new_function); - } else { - void* intermediate_trampoline = executable_memory_->Allocate( - aligned_full_trampoline_size, target_->GetCodeAlignment(), - config.start_address, config.end_address); - if (!intermediate_trampoline) continue; - - size_t trampoline_size = 0; - error = GetTrampolineSize(config, old_function, intermediate_trampoline, - trampoline_size); - if (error.Fail()) return error; - - error = CreateCompensationFunction(old_function, trampoline_size, - callback_function); - if (error.Fail()) return error; - - error = - InstallTrampoline(full_config, intermediate_trampoline, new_function); - if (error.Fail()) return error; - - return InstallTrampoline(config, old_function, intermediate_trampoline); - } - } - return Error("Failed to find a suitable trampoline"); -} diff --git a/gapii/interceptor-lib/cc/lib/libinterceptor.exports b/gapii/interceptor-lib/cc/lib/libinterceptor.exports deleted file mode 100644 index 5ad10aeee9..0000000000 --- a/gapii/interceptor-lib/cc/lib/libinterceptor.exports +++ /dev/null @@ -1,3 +0,0 @@ -InitializeInterceptor -TerminateInterceptor -InterceptFunction diff --git a/gapii/interceptor-lib/cc/lib/memory_manager.cpp b/gapii/interceptor-lib/cc/lib/memory_manager.cpp deleted file mode 100644 index 5b92711086..0000000000 --- a/gapii/interceptor-lib/cc/lib/memory_manager.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "memory_manager.h" - -#include -#include -#include - -#ifndef PAGE_SIZE -#define PAGE_SIZE 0x1000 -#endif - -using namespace interceptor; - -MemoryManager::MemoryManager(int prot, int flags) - : prot_(prot), flags_(flags) {} - -MemoryManager::~MemoryManager() { - for (const auto& alloc : allocations_) - munmap(reinterpret_cast(alloc.start()), alloc.size()); -} - -void* MemoryManager::Allocate(size_t size, size_t alignment, - uintptr_t range_start, uintptr_t range_end) { - assert(size > 0 && "Can't allocate 0 or negative amount of memory."); - assert(size <= PAGE_SIZE && "Can't allocate more then PAGE_SIZE memory"); - assert(PAGE_SIZE % alignment == 0 && - "Can met alignment requiremenet not " - "satisfied by a page boundary"); - - for (Allocation& alloc : allocations_) { - if (void* addr = alloc.Alloc(size, alignment, range_start, range_end)) - return addr; - if (range_start >= alloc.start() && range_start <= alloc.end()) - range_start = alloc.end(); - } - void* target = mmap(reinterpret_cast(range_start), PAGE_SIZE, prot_, - flags_, 0, 0); - if (!target) return nullptr; - - allocations_.emplace_back(target, PAGE_SIZE); - return allocations_.back().Alloc(size, alignment, range_start, range_end); -} - -void* MemoryManager::Allocation::Alloc(size_t size, size_t alignment, - uintptr_t range_start, - uintptr_t range_end) { - size_t new_offset = CalculateNewOffset(size, alignment); - if (new_offset + size > size_) return nullptr; // Doesn't fit - - uintptr_t address = reinterpret_cast(start_ + new_offset); - if (address < range_start || address > range_end) - return nullptr; // Out of range - - offset_ = new_offset + size; - return start_ + new_offset; -} - -size_t MemoryManager::Allocation::CalculateNewOffset(size_t size, - size_t alignment) const { - size_t new_offset = offset_; - if (new_offset % alignment != 0) - new_offset += alignment - (new_offset % alignment); - return new_offset; -} diff --git a/gapii/interceptor-lib/cc/lib/memory_manager.h b/gapii/interceptor-lib/cc/lib/memory_manager.h deleted file mode 100644 index 5089ac7681..0000000000 --- a/gapii/interceptor-lib/cc/lib/memory_manager.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_MEMORY_MANAGER_H_ -#define INTERCEPTOR_MEMORY_MANAGER_H_ - -#include -#include -#include -#include - -namespace interceptor { - -class MemoryManager { - public: - MemoryManager(int prot, int flags); - ~MemoryManager(); - - void* Allocate(size_t size, size_t alignment, - uintptr_t range_start = std::numeric_limits::min(), - uintptr_t range_end = std::numeric_limits::max()); - - private: - class Allocation { - public: - Allocation(void* start, size_t size) - : start_(static_cast(start)), size_(size), offset_(0) {} - - uintptr_t start() const { return reinterpret_cast(start_); } - uintptr_t end() const { return start() + size_; } - size_t size() const { return size_; } - - void* Alloc(size_t size, size_t alignment, uintptr_t range_start, - uintptr_t range_end); - - private: - uint8_t* const start_; - const size_t size_; - size_t offset_; - - size_t CalculateNewOffset(size_t size, size_t alignment) const; - }; - - const int prot_; - const int flags_; - - std::vector allocations_; -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_MEMORY_MANAGER_H_ diff --git a/gapii/interceptor-lib/cc/lib/target.cpp b/gapii/interceptor-lib/cc/lib/target.cpp deleted file mode 100644 index 47bde00728..0000000000 --- a/gapii/interceptor-lib/cc/lib/target.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "target.h" - -using namespace interceptor; - -TrampolineConfig Target::GetFullTrampolineConfig() const { - TrampolineConfig config = GetTrampolineConfigs(0).back(); - assert(config.IsFullTrampoline()); - return config; -} diff --git a/gapii/interceptor-lib/cc/lib/target.h b/gapii/interceptor-lib/cc/lib/target.h deleted file mode 100644 index a63b0b5c9f..0000000000 --- a/gapii/interceptor-lib/cc/lib/target.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERCEPTOR_TARGET_H_ -#define INTERCEPTOR_TARGET_H_ - -#include -#include -#include - -#include "llvm/MC/MCInst.h" - -#include "code_generator.h" -#include "disassembler.h" -#include "error.h" - -namespace interceptor { - -struct TrampolineConfig { - uint32_t type; // Architecture specific value - bool require_source; // Using relative or absolute jump - uintptr_t start_address; // First address it can jump to - uintptr_t end_address; // Last address it can jump to - - // Returns true if the trampoline can jump from any address in the address - // space to any other address and false otherwise. - bool IsFullTrampoline() const { - return !require_source && - start_address == std::numeric_limits::min() && - end_address == std::numeric_limits::max(); - } -}; - -class Target { - public: - virtual ~Target() = default; - - // Create a new code generator with the specified start alignment what can - // generate code with the same ISA pointed by the address (e.g. thumb vs arm). - virtual CodeGenerator* GetCodeGenerator(void* address, - size_t start_alignment) = 0; - - // Create a disassebler what can disassamble code coming from the specified - // address. - virtual Disassembler* CreateDisassembler(void* address) = 0; - - // Get the maximum alignment required by the target by any instruction in any - // of the supported ISA. - virtual size_t GetCodeAlignment() const = 0; - - // Return a load address from a function pointer. Have to be implemented for - // architectures where some bits of the function pointers contain meta-data - // (e.g. thumb bit) - virtual void* GetLoadAddress(void* addr) { return addr; } - - // Returns the full list of avaiulable trampolines on the given architecture - // sorted to increasing order by the total size of instructions (including - // data) inside the trampoline. - virtual std::vector GetTrampolineConfigs( - uintptr_t start_address) const = 0; - - // Return the configuartion of the full trampoline what have to be able to - // jump to any address inside the process's address space. - TrampolineConfig GetFullTrampolineConfig() const; - - // Emit a trampoline with the given config into the code generator what will - // jump to the specified target address if it is placed into the location - // specified by the source address. - virtual Error EmitTrampoline(const TrampolineConfig& config, - CodeGenerator& codegen, void* target) = 0; - - // Rewrite the specified instruction read from "data + offset "into the code - // generator with a set of instructions with the exact same effect but without - // any limitation about the location they have to be placed at. Additionally - // it sets the "possible_end_of_function" flag to true if the instruction can - // be the last one inside a function and to false otherwise. - virtual Error RewriteInstruction(const llvm::MCInst& inst, - CodeGenerator& codegen, void* data, - size_t offset, - bool& possible_end_of_function) = 0; - - // Convert the pointer specified by "new_function" from a memory load address - // to a function pointer with the same ISA as the function pointed by - // "old_function". Have to be implemented for architectures where some bits of - // the function pointers contain meta-data (e.g. thumb bit). - virtual void* FixupCallbackFunction(void* old_function, void* new_function) { - return new_function; - } - - // Checks if the old function is a simple PLT type function where it is - // (likely) not possible to install a trampoline. Returns the address of the - // PLT target or old_function. - virtual void* CheckIsPLT(void* old_function, void* new_function) { - return old_function; - } -}; - -} // end of namespace interceptor - -#endif // INTERCEPTOR_TARGET_H_ diff --git a/gapil/bapi/BUILD.bazel b/gapil/bapi/BUILD.bazel index ea6459f320..a4bf70ad16 100644 --- a/gapil/bapi/BUILD.bazel +++ b/gapil/bapi/BUILD.bazel @@ -51,8 +51,6 @@ go_test( name = "go_default_test", srcs = ["bapi_test.go"], data = [ - "//gapis/api/gles:api_files", - "//gapis/api/gvr:api_files", "//gapis/api/vulkan:api_files", "//gapis/messages:messages_api", ], diff --git a/gapil/bapi/bapi_test.go b/gapil/bapi/bapi_test.go index bfec4114ff..9fa64b4195 100644 --- a/gapil/bapi/bapi_test.go +++ b/gapil/bapi/bapi_test.go @@ -36,8 +36,6 @@ import ( const toRoot = "../../" var testAPIs = []string{ - toRoot + "gapis/api/gles/gles.api", - toRoot + "gapis/api/gvr/gvr.api", toRoot + "gapis/api/vulkan/vulkan.api", } diff --git a/gapir/cc/BUILD.bazel b/gapir/cc/BUILD.bazel index 4ff7e7d3a0..83fb3b6b3a 100644 --- a/gapir/cc/BUILD.bazel +++ b/gapir/cc/BUILD.bazel @@ -14,22 +14,6 @@ load("//tools/build:rules.bzl", "apic_template", "cc_copts", "mm_library") -apic_template( - name = "gles_cc", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:specific_gfx_api.cpp", - ], -) - -apic_template( - name = "gles_h", - api = "//gapis/api/gles:api", - templates = [ - "//gapis/api/templates:specific_gfx_api.h", - ], -) - apic_template( name = "vulkan_cc", api = "//gapis/api/vulkan:api", @@ -54,7 +38,6 @@ mm_library( "*.h", "*.inc", ]) + [ - ":gles_h", ":vulkan_h", ], copts = cc_copts() + [ @@ -87,8 +70,6 @@ cc_library( "android/*.h", ]), }) + [ - ":gles_cc", - ":gles_h", ":vulkan_cc", ":vulkan_h", ], @@ -108,8 +89,6 @@ cc_library( "//conditions:default": [ "-lm", "-llog", - "-lEGL", - "-lGLESv2", "-landroid", ], }), diff --git a/gapir/cc/android/gles_renderer.cpp b/gapir/cc/android/gles_renderer.cpp deleted file mode 100644 index 5139b19eb1..0000000000 --- a/gapir/cc/android/gles_renderer.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapir/cc/gles_renderer.h" -#include "gapir/cc/gles_gfx_api.h" - -#include "core/cc/gl/formats.h" -#include "core/cc/log.h" - -#include -#include - -namespace gapir { -namespace { - -class GlesRendererImpl : public GlesRenderer { - public: - GlesRendererImpl(GlesRendererImpl* shared); - virtual ~GlesRendererImpl() override; - - virtual Api* api() override; - virtual void setBackbuffer(Backbuffer backbuffer) override; - virtual void bind(bool resetViewportScissor) override; - virtual void unbind() override; - virtual void* createExternalImage(uint32_t texture) override; - virtual bool frameDelimiter() override; - virtual const char* name() override; - virtual const char* extensions() override; - virtual const char* vendor() override; - virtual const char* version() override; - - private: - void reset(); - - Backbuffer mBackbuffer; - bool mNeedsResolve; - Gles mApi; - - EGLConfig mConfig; - EGLContext mContext; - EGLContext mSharedContext; - EGLSurface mSurface; - EGLDisplay mDisplay; -}; - -#define EGL_CHECK_ERROR(FORMAT, ...) \ - do { \ - EGLint err = eglGetError(); \ - if (err != EGL_SUCCESS) { \ - GAPID_FATAL(FORMAT ": 0x%x", ##__VA_ARGS__, err); \ - } \ - } while (false) - -GlesRendererImpl::GlesRendererImpl(GlesRendererImpl* shared) - : mNeedsResolve(false), - mContext(EGL_NO_CONTEXT), - mSharedContext(shared == nullptr ? EGL_NO_CONTEXT : shared->mContext), - mSurface(EGL_NO_SURFACE) { - mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - EGL_CHECK_ERROR("Failed to get EGL display"); - - eglInitialize(mDisplay, nullptr, nullptr); - EGL_CHECK_ERROR("Failed to initialize EGL"); - - eglBindAPI(EGL_OPENGL_ES_API); - EGL_CHECK_ERROR("Failed to bind EGL API"); -} - -GlesRendererImpl::~GlesRendererImpl() { - unbind(); - - if (mContext != nullptr) { - eglDestroyContext(mDisplay, mContext); - EGL_CHECK_ERROR("Failed to destroy context %p", mContext); - } - - if (mSurface != nullptr) { - eglDestroySurface(mDisplay, mSurface); - EGL_CHECK_ERROR("Failed to destroy surface %p", mSurface); - } - - eglTerminate(mDisplay); - EGL_CHECK_ERROR("Failed to terminate EGL"); - - eglReleaseThread(); - EGL_CHECK_ERROR("Failed to release EGL thread"); -} - -Api* GlesRendererImpl::api() { return &mApi; } - -void GlesRendererImpl::setBackbuffer(Backbuffer backbuffer) { - if (mBackbuffer == backbuffer) { - return; // No change - } - - if (mBackbuffer.format == backbuffer.format) { - // Only a resize is necessary - GAPID_INFO("Resizing renderer: %dx%d -> %dx%d", mBackbuffer.width, - mBackbuffer.height, backbuffer.width, backbuffer.height); - } else { - if (mContext != nullptr) { - GAPID_WARNING( - "Attempting to change format of renderer: [0x%x, 0x%x, 0x%x] -> " - "[0x%x, 0x%x, 0x%x]", - mBackbuffer.format.color, mBackbuffer.format.depth, - mBackbuffer.format.stencil, backbuffer.format.color, - backbuffer.format.depth, backbuffer.format.stencil); - } - - // Find a supported EGL context config. - int r = 8, g = 8, b = 8, a = 8, d = 24, s = 8; - core::gl::getColorBits(backbuffer.format.color, r, g, b, a); - core::gl::getDepthBits(backbuffer.format.depth, d); - core::gl::getStencilBits(backbuffer.format.stencil, s); - - const int configAttribList[] = { - // clang-format off - EGL_RED_SIZE, r, - EGL_GREEN_SIZE, g, - EGL_BLUE_SIZE, b, - EGL_ALPHA_SIZE, a, - EGL_BUFFER_SIZE, r+g+b+a, - EGL_DEPTH_SIZE, d, - EGL_STENCIL_SIZE, s, - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE - // clang-format on - }; - int one = 1; - eglChooseConfig(mDisplay, configAttribList, &mConfig, 1, &one); - EGL_CHECK_ERROR("Failed to choose EGL config"); - } - - // Delete existing surface. - if (mSurface != EGL_NO_SURFACE) { - eglDestroySurface(mDisplay, mSurface); - EGL_CHECK_ERROR("Failed to destroy EGL surface %p", mSurface); - mSurface = EGL_NO_SURFACE; - } - - // Create an EGL surface for the read/draw framebuffer. - const int surfaceAttribList[] = { - // clang-format off - EGL_WIDTH, backbuffer.width, - EGL_HEIGHT, backbuffer.height, - EGL_NONE - // clang-format on - }; - mSurface = eglCreatePbufferSurface(mDisplay, mConfig, surfaceAttribList); - EGL_CHECK_ERROR("Failed to create EGL pbuffer surface"); - - if (mContext == nullptr) { - // Create an EGL context. - const int contextAttribList[] = { - // clang-format off - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE - // clang-format on - }; - mContext = - eglCreateContext(mDisplay, mConfig, mSharedContext, contextAttribList); - EGL_CHECK_ERROR("Failed to create EGL context"); - mNeedsResolve = true; - } - - mBackbuffer = backbuffer; -} - -void GlesRendererImpl::bind(bool resetViewportScissor) { - eglMakeCurrent(mDisplay, mSurface, mSurface, mContext); - EGL_CHECK_ERROR("Failed to make context %p current", mContext); - - if (mNeedsResolve) { - mNeedsResolve = false; - mApi.resolve(); - } - - if (resetViewportScissor) { - mApi.mFunctionStubs.glViewport(0, 0, mBackbuffer.width, mBackbuffer.height); - mApi.mFunctionStubs.glScissor(0, 0, mBackbuffer.width, mBackbuffer.height); - } -} - -void GlesRendererImpl::unbind() { - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - EGL_CHECK_ERROR("Failed to release EGL context"); -} - -void* GlesRendererImpl::createExternalImage(uint32_t texture) { - return mApi.mFunctionStubs.eglCreateImageKHR( - mDisplay, mContext, EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer)(uint64_t)texture, nullptr); -} - -bool GlesRendererImpl::frameDelimiter() { - if (mSurface != nullptr) { - eglSwapBuffers(mDisplay, mSurface); - EGL_CHECK_ERROR("Failed to swap buffers"); - return true; - } - return false; -} - -const char* GlesRendererImpl::name() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_RENDERER)); -} - -const char* GlesRendererImpl::extensions() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_EXTENSIONS)); -} - -const char* GlesRendererImpl::vendor() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VENDOR)); -} - -const char* GlesRendererImpl::version() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VERSION)); -} - -} // anonymous namespace - -GlesRenderer* GlesRenderer::create(GlesRenderer* sharedContext) { - return new GlesRendererImpl( - reinterpret_cast(sharedContext)); -} - -} // namespace gapir diff --git a/gapir/cc/context.cpp b/gapir/cc/context.cpp index 6241001d4e..1044df4ecc 100644 --- a/gapir/cc/context.cpp +++ b/gapir/cc/context.cpp @@ -15,9 +15,7 @@ */ #include "context.h" -#include "gapir/cc/gles_gfx_api.h" #include "gapir/cc/vulkan_gfx_api.h" -#include "gles_renderer.h" #include "interpreter.h" #include "memory_manager.h" #include "post_buffer.h" @@ -70,19 +68,10 @@ Context::Context(ReplayService* srv, core::CrashHandler& crash_handler, })), mNumSentDebugMessages(0) {} -Context::~Context() { - for (auto it = mGlesRenderers.begin(); it != mGlesRenderers.end(); it++) { - delete it->second; - } - delete mVulkanRenderer; -} +Context::~Context() { delete mVulkanRenderer; } bool Context::cleanup() { - for (auto it = mGlesRenderers.begin(); it != mGlesRenderers.end(); it++) { - delete it->second; - } delete mVulkanRenderer; - mGlesRenderers.clear(); mVulkanRenderer = nullptr; return true; } @@ -213,194 +202,6 @@ void Context::registerCallbacks(Interpreter* interpreter) { }); // Registering custom synthetic functions - interpreter->registerBuiltin(Gles::INDEX, Builtins::StartTimer, - [this](uint32_t label, Stack* stack, bool) { - return this->startTimer(stack); - }); - interpreter->registerBuiltin( - Gles::INDEX, Builtins::StopTimer, - [this](uint32_t label, Stack* stack, bool pushReturn) { - return this->stopTimer(stack, pushReturn); - }); - interpreter->registerBuiltin(Gles::INDEX, Builtins::FlushPostBuffer, - [this](uint32_t label, Stack* stack, bool) { - return this->flushPostBuffer(stack); - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayFrameDelimiter, - [this](uint32_t label, Stack* stack, bool) { - uint32_t id = stack->pop(); - if (stack->isValid()) { - GAPID_INFO("[%u]replayFrameDelimiter(%u)", label, id); - auto found = mGlesRenderers.find(id); - if (found == mGlesRenderers.end()) { - GAPID_ERROR("replayFrameDelimiter has no renderer at ID: %u", id); - return false; - } - found->second->frameDelimiter(); - return true; - } else { - GAPID_WARNING( - "[%u]Error during calling function replayFrameDelimiter", label); - return false; - } - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayCreateRenderer, - [this](uint32_t label, Stack* stack, bool) { - uint32_t id = stack->pop(); - if (stack->isValid()) { - GAPID_INFO("[%u]replayCreateRenderer(%u)", label, id); - auto existing = mGlesRenderers.find(id); - if (existing != mGlesRenderers.end()) { - delete existing->second; - } - // Share objects with the root GLES context. - // This will essentially make all objects shared between all contexts. - // It is ok since correct replay will only reference what it is - // supposed to. - if (!mRootGlesRenderer) { - mRootGlesRenderer.reset(GlesRenderer::create(nullptr)); - if (!mRootGlesRenderer) { - GAPID_ERROR("Could not create GLES renderer on this device"); - return false; - } - mRootGlesRenderer->setBackbuffer(GlesRenderer::Backbuffer( - 8, 8, core::gl::GL_RGBA8, core::gl::GL_DEPTH24_STENCIL8, - core::gl::GL_DEPTH24_STENCIL8)); - } - auto renderer = GlesRenderer::create(mRootGlesRenderer.get()); - if (!renderer) { - GAPID_ERROR("Could not create GLES renderer on this device"); - return false; - } - renderer->setListener(this); - mGlesRenderers[id] = renderer; - return true; - } else { - GAPID_WARNING( - "[%u]Error during calling function replayCreateRenderer", label); - return false; - } - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayBindRenderer, - [this, interpreter](uint32_t label, Stack* stack, bool) { - bool resetViewportScissor = stack->pop(); - uint32_t id = stack->pop(); - if (stack->isValid()) { - GAPID_INFO("[%u]replayBindRenderer(%u, %s)", label, id, - resetViewportScissor ? "true" : "false"); - auto renderer = mGlesRenderers[id]; - renderer->bind(resetViewportScissor); - Api* api = renderer->api(); - interpreter->setRendererFunctions(api->index(), &api->mFunctions); - GAPID_DEBUG("[%u]Bound renderer %u: %s - %s", label, id, - renderer->name(), renderer->version()); - return true; - } else { - GAPID_WARNING("[%u]Error during calling function replayBindRenderer", - label); - return false; - } - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayUnbindRenderer, - [this](uint32_t label, Stack* stack, bool) { - uint32_t id = stack->pop(); - if (stack->isValid()) { - GAPID_DEBUG("[%u]replayUnbindRenderer(%" PRIu32 ")", label, id); - auto renderer = mGlesRenderers[id]; - renderer->unbind(); - // TODO: Unbind renderer functions with the interpreter? - // Api* api = renderer->api(); - // interpreter->setRendererFunctions(api->index(), nullptr); - GAPID_DEBUG("[%u]Unbound renderer %" PRIu32, label, id); - return true; - } else { - GAPID_WARNING( - "[%u]Error during calling function replayUnbindRenderer", label); - return false; - } - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayChangeBackbuffer, - [this](uint32_t label, Stack* stack, bool) { - GlesRenderer::Backbuffer backbuffer; - - backbuffer.format.stencil = stack->pop(); - backbuffer.format.depth = stack->pop(); - backbuffer.format.color = stack->pop(); - backbuffer.height = stack->pop(); - backbuffer.width = stack->pop(); - uint32_t id = stack->pop(); - - if (!stack->isValid()) { - GAPID_WARNING( - "[%u]Error during calling function replayChangeBackbuffer", - label); - return false; - } - - if (stack->isValid()) { - GAPID_INFO("[%u]replayChangeBackbuffer(%d, %d, 0x%x, 0x%x, 0x%x)", - label, backbuffer.width, backbuffer.height, - backbuffer.format.color, backbuffer.format.depth, - backbuffer.format.stencil); - auto renderer = mGlesRenderers[id]; - if (renderer == nullptr) { - GAPID_WARNING( - "[%u]replayChangeBackbuffer called with unknown renderer " - "%" PRIu32, - label, id); - return false; - } - renderer->setBackbuffer(backbuffer); - return true; - } else { - GAPID_WARNING( - "[%u]Error during calling function replayChangeBackbuffer", - label); - return false; - } - }); - - interpreter->registerBuiltin( - Gles::INDEX, Builtins::ReplayCreateExternalImage, - [this](uint32_t label, Stack* stack, bool pushReturn) { - uint32_t texId = stack->pop(); - uint32_t ctxId = stack->pop(); - - if (!stack->isValid()) { - GAPID_WARNING( - "[%u]Error during calling function replayCreateExternalImage", - label); - return false; - } - - auto renderer = mGlesRenderers[ctxId]; - if (renderer == nullptr) { - GAPID_WARNING( - "[%u]replayCreateExternalImage called with unknown renderer " - "%" PRIu32, - label, ctxId); - return false; - } - - GAPID_INFO("[%u]replayCreateExternalImage(%d, %d)", label, ctxId, - texId); - auto result = renderer->createExternalImage(texId); - if (pushReturn) { - stack->push(result); - } - return true; - }); - interpreter->registerBuiltin( Vulkan::INDEX, Builtins::ReplayCreateVkInstance, [this, interpreter](uint32_t label, Stack* stack, bool pushReturn) { diff --git a/gapir/cc/context.h b/gapir/cc/context.h index 4083d8a2af..476b79d5d4 100644 --- a/gapir/cc/context.h +++ b/gapir/cc/context.h @@ -30,7 +30,6 @@ namespace gapir { -class GlesRenderer; class Interpreter; class MemoryManager; class PostBuffer; @@ -135,12 +134,6 @@ class Context : private Renderer::Listener { // An array of timers. core::Timer mTimers[MAX_TIMERS]; - // GLES renderer used as reference for all context sharing. - std::unique_ptr mRootGlesRenderer; - - // The constructed GLES renderers. - std::unordered_map mGlesRenderers; - // The lazily-built Vulkan renderer. VulkanRenderer* mVulkanRenderer; diff --git a/gapir/cc/gles_renderer.h b/gapir/cc/gles_renderer.h deleted file mode 100644 index df1f480678..0000000000 --- a/gapir/cc/gles_renderer.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPIR_GLES_RENDERER_H -#define GAPIR_GLES_RENDERER_H - -#include "renderer.h" - -namespace gapir { - -// The GLES renderer implementation, which creates a OpenGL / GLES rendering -// context. -class GlesRenderer : public Renderer { - public: - // Backbuffer describes a backbuffer dimensions and format. - struct Backbuffer { - struct Format { - inline Format(); - inline Format(uint32_t c, uint32_t d, uint32_t s); - uint32_t color; - uint32_t depth; - uint32_t stencil; - }; - - inline Backbuffer(); - inline Backbuffer(int w, int h, uint32_t c, uint32_t d, uint32_t s); - - int width; - int height; - Format format; - }; - - // Construct and return an offscreen renderer. - static GlesRenderer* create(GlesRenderer* sharedContext); - - // Returns the renderer's API. - virtual Api* api() = 0; - - // Changes the back-buffer dimensions and format. - virtual void setBackbuffer(Backbuffer backbuffer) = 0; - - // Makes the current renderer active. - virtual void bind(bool resetViewportScissor) = 0; - - // Makes the current renderer inactive. - virtual void unbind() = 0; - - // Returns the name of the renderer's created graphics context. - virtual const char* name() = 0; - - // Returns the list of extensions that the renderer's graphics context - // supports. - virtual const char* extensions() = 0; - - // Returns the name of the vendor that has implemented the renderer's graphics - // context. - virtual const char* vendor() = 0; - - // Returns the version of the renderer's graphics context. - virtual const char* version() = 0; - - virtual bool isValid() { return true; } - - // Creates an external image backed by the given texture. - virtual void* createExternalImage(uint32_t texture) { return nullptr; } - - // Perform a call that acts as a frame delimiter, typically swapBuffers - virtual bool frameDelimiter() { return true; } -}; - -inline GlesRenderer::Backbuffer::Format::Format() - : color(0), depth(0), stencil(0) {} - -inline GlesRenderer::Backbuffer::Format::Format(uint32_t c, uint32_t d, - uint32_t s) - : color(c), depth(d), stencil(s) {} - -inline bool operator==(const GlesRenderer::Backbuffer::Format& lhs, - const GlesRenderer::Backbuffer::Format& rhs) { - return lhs.color == rhs.color && lhs.depth == rhs.depth && - lhs.stencil == rhs.stencil; -} - -inline GlesRenderer::Backbuffer::Backbuffer() : width(0), height(0) {} - -inline GlesRenderer::Backbuffer::Backbuffer(int w, int h, uint32_t c, - uint32_t d, uint32_t s) - : width(w), height(h), format(c, d, s) {} - -inline bool operator==(const GlesRenderer::Backbuffer& lhs, - const GlesRenderer::Backbuffer& rhs) { - return lhs.width == rhs.width && lhs.height == rhs.height && - lhs.format == rhs.format; -} - -} // namespace gapir - -#endif // GAPIR_GLES_RENDERER_H diff --git a/gapir/cc/linux/gles_renderer.cpp b/gapir/cc/linux/gles_renderer.cpp deleted file mode 100644 index a5c5f76b97..0000000000 --- a/gapir/cc/linux/gles_renderer.cpp +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapir/cc/gles_renderer.h" -#include "gapir/cc/gles_gfx_api.h" - -#include "core/cc/dl_loader.h" -#include "core/cc/get_gles_proc_address.h" -#include "core/cc/gl/formats.h" -#include "core/cc/gl/versions.h" -#include "core/cc/log.h" - -#include -#include - -namespace gapir { -namespace { - -typedef XID GLXPbuffer; -typedef XID GLXDrawable; -typedef /*struct __GLXcontextRec*/ void* GLXContext; -typedef /*struct __GLXFBConfigRec*/ void* GLXFBConfig; - -enum { - // Used by glXChooseFBConfig. - GLX_RED_SIZE = 8, - GLX_GREEN_SIZE = 9, - GLX_BLUE_SIZE = 10, - GLX_ALPHA_SIZE = 11, - GLX_DEPTH_SIZE = 12, - GLX_STENCIL_SIZE = 13, - GLX_DRAWABLE_TYPE = 0x8010, - GLX_RENDER_TYPE = 0x8011, - GLX_RGBA_BIT = 0x00000001, - GLX_PBUFFER_BIT = 0x00000004, - - // Used by glXCreateNewContext. - GLX_RGBA_TYPE = 0x8014, - - // Used by glXCreatePbuffer. - GLX_PBUFFER_HEIGHT = 0x8040, - GLX_PBUFFER_WIDTH = 0x8041, - - // Attribute name for glXCreateContextAttribsARB. - GLX_CONTEXT_MAJOR_VERSION_ARB = 0x2091, - GLX_CONTEXT_MINOR_VERSION_ARB = 0x2092, - GLX_CONTEXT_FLAGS_ARB = 0x2094, - GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126, - - // Attribute value for glXCreateContextAttribsARB. - GLX_CONTEXT_DEBUG_BIT_ARB = 0x0001, - GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002, - GLX_CONTEXT_CORE_PROFILE_BIT_ARB = 0x0001, - GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x0002, -}; - -extern "C" { - -typedef GLXFBConfig* (*pfn_glXChooseFBConfig)(Display* dpy, int screen, - const int* attrib_list, - int* nelements); -typedef GLXContext (*pfn_glXCreateNewContext)(Display* dpy, GLXFBConfig config, - int render_type, - GLXContext share_list, - Bool direct); -typedef GLXPbuffer (*pfn_glXCreatePbuffer)(Display* dpy, GLXFBConfig config, - const int* attrib_list); -typedef void (*pfn_glXDestroyPbuffer)(Display* dpy, GLXPbuffer pbuf); -typedef Bool (*pfn_glXMakeContextCurrent)(Display* dpy, GLXDrawable draw, - GLXDrawable read, GLXContext ctx); -typedef Bool (*pfn_glXQueryVersion)(Display* dpy, int* maj, int* min); -typedef void (*pfn_glXDestroyContext)(Display* dpy, GLXContext ctx); -typedef void* (*pfn_glXGetProcAddress)(const char* procName); -typedef GLXContext (*glXCreateContextAttribsARBProc)(Display* dpy, - GLXFBConfig config, - GLXContext share_context, - Bool direct, - const int* attrib_list); - -typedef int (*pfn_XFree)(void*); -typedef int (*pfn_XCloseDisplay)(Display*); -typedef Display* (*pfn_XOpenDisplay)(_Xconst char*); -typedef XErrorHandler (*pfn_XSetErrorHandler)(XErrorHandler); -typedef int (*pfn_XSync)(Display*, Bool); - -} // extern "C" - -class GlesRendererImpl : public GlesRenderer { - public: - GlesRendererImpl(GlesRendererImpl* shared_context); - virtual ~GlesRendererImpl() override; - - virtual Api* api() override; - virtual void setBackbuffer(Backbuffer backbuffer) override; - virtual void bind(bool resetViewportScissor) override; - virtual void unbind() override; - virtual const char* name() override; - virtual const char* extensions() override; - virtual const char* vendor() override; - virtual const char* version() override; - - private: - void createPbuffer(int width, int height); - - Backbuffer mBackbuffer; - bool mNeedsResolve; - Gles mApi; - std::string mExtensions; - bool mQueriedExtensions; - - Display* mDisplay; - bool mOwnsDisplay; // True if we created mDisplay - GLXContext mContext; - GLXContext mSharedContext; - GLXPbuffer mPbuffer; - GLXFBConfig mFBConfig; - - pfn_XFree fn_XFree; - pfn_XCloseDisplay fn_XCloseDisplay; - pfn_XOpenDisplay fn_XOpenDisplay; - pfn_XSetErrorHandler fn_XSetErrorHandler; - pfn_XSync fn_XSync; - core::DlLoader libX; - - pfn_glXChooseFBConfig fn_glXChooseFBConfig; - pfn_glXCreateNewContext fn_glXCreateNewContext; - pfn_glXCreatePbuffer fn_glXCreatePbuffer; - pfn_glXDestroyPbuffer fn_glXDestroyPbuffer; - pfn_glXMakeContextCurrent fn_glXMakeContextCurrent; - pfn_glXQueryVersion fn_glXQueryVersion; - pfn_glXDestroyContext fn_glXDestroyContext; - pfn_glXGetProcAddress fn_glXGetProcAddress; -}; - -// NB: We keep a reference the shared GL context, so "parent" context -// must stay alive at least for the duration of this context. -// We create "root" context for this purpose so it is satisfied. -// TODO: Add assert/refcounting to enforce this. -GlesRendererImpl::GlesRendererImpl(GlesRendererImpl* shared_context) - : mNeedsResolve(false), - mDisplay(nullptr), - mContext(nullptr), - mSharedContext(shared_context != nullptr ? shared_context->mContext : 0), - mPbuffer(0), - libX("libX11.so") { - fn_XFree = (pfn_XFree)libX.lookup("XFree"); - fn_XCloseDisplay = (pfn_XCloseDisplay)libX.lookup("XCloseDisplay"); - fn_XOpenDisplay = (pfn_XOpenDisplay)libX.lookup("XOpenDisplay"); - fn_XSetErrorHandler = (pfn_XSetErrorHandler)libX.lookup("XSetErrorHandler"); - fn_XSync = (pfn_XSync)libX.lookup("XSync"); - - fn_glXChooseFBConfig = - (pfn_glXChooseFBConfig)core::GetGlesProcAddress("glXChooseFBConfig"); - fn_glXCreateNewContext = - (pfn_glXCreateNewContext)core::GetGlesProcAddress("glXCreateNewContext"); - fn_glXCreatePbuffer = - (pfn_glXCreatePbuffer)core::GetGlesProcAddress("glXCreatePbuffer"); - fn_glXDestroyPbuffer = - (pfn_glXDestroyPbuffer)core::GetGlesProcAddress("glXDestroyPbuffer"); - fn_glXMakeContextCurrent = - (pfn_glXMakeContextCurrent)core::GetGlesProcAddress( - "glXMakeContextCurrent"); - fn_glXQueryVersion = - (pfn_glXQueryVersion)core::GetGlesProcAddress("glXQueryVersion"); - fn_glXDestroyContext = - (pfn_glXDestroyContext)core::GetGlesProcAddress("glXDestroyContext"); - fn_glXGetProcAddress = - (pfn_glXGetProcAddress)core::GetGlesProcAddress("glXGetProcAddress"); - - if (shared_context != nullptr) { - // Ensure that shared contexts also share X-display. - // Drivers are know to misbehave/crash without this. - // NB: This relies on the shared_context to stay alive. - mDisplay = shared_context->mDisplay; - mOwnsDisplay = false; - } else { - mDisplay = fn_XOpenDisplay(nullptr); - if (mDisplay == nullptr) { - // Default display was not found. This may be because we're executing in - // the bazel sandbox. Attempt to connect to the 0'th display instead. - mDisplay = fn_XOpenDisplay(":0"); - } - if (mDisplay == nullptr) { - GAPID_FATAL("Unable to to open X display"); - } - mOwnsDisplay = true; - } - - int major; - int minor; - if (!fn_glXQueryVersion(mDisplay, &major, &minor) || - (major == 1 && minor < 3)) { - GAPID_FATAL("GLX 1.3+ unsupported by X server (was %d.%d)", major, minor); - } -} - -GlesRendererImpl::~GlesRendererImpl() { - unbind(); - - if (mContext != nullptr) { - fn_glXDestroyContext(mDisplay, mContext); - GAPID_DEBUG("Destroyed context %p", mContext); - } - - if (mPbuffer != 0) { - fn_glXDestroyPbuffer(mDisplay, mPbuffer); - } - - if (mOwnsDisplay && mDisplay != nullptr) { - fn_XCloseDisplay(mDisplay); - } -} - -Api* GlesRendererImpl::api() { return &mApi; } - -void GlesRendererImpl::createPbuffer(int width, int height) { - if (mContext != nullptr) { - unbind(); // Flush before yanking the surface. - } - - if (mPbuffer != 0) { - fn_glXDestroyPbuffer(mDisplay, mPbuffer); - mPbuffer = 0; - } - const int pbufferAttribs[] = { - // clang-format off - GLX_PBUFFER_WIDTH, width, - GLX_PBUFFER_HEIGHT, height, - None - // clang-format on - }; - mPbuffer = fn_glXCreatePbuffer(mDisplay, mFBConfig, pbufferAttribs); -} - -static void DebugCallback(uint32_t source, uint32_t type, Gles::GLuint id, - uint32_t severity, Gles::GLsizei length, - const Gles::GLchar* message, const void* user_param) { - auto renderer = reinterpret_cast(user_param); - auto listener = renderer->getListener(); - if (listener != nullptr) { - if (type == Gles::GLenum::GL_DEBUG_TYPE_ERROR || - severity == Gles::GLenum::GL_DEBUG_SEVERITY_HIGH) { - listener->onDebugMessage(LOG_LEVEL_ERROR, Gles::INDEX, message); - } else { - listener->onDebugMessage(LOG_LEVEL_DEBUG, Gles::INDEX, message); - } - } -} - -void GlesRendererImpl::setBackbuffer(Backbuffer backbuffer) { - if (mBackbuffer == backbuffer) { - return; // No change - } - - if (mBackbuffer.format == backbuffer.format) { - // Only a resize is necessary - GAPID_INFO("Resizing renderer: %dx%d -> %dx%d", mBackbuffer.width, - mBackbuffer.height, backbuffer.width, backbuffer.height); - } else { - if (mContext != nullptr) { - GAPID_WARNING( - "Attempting to change format of renderer: [0x%x, 0x%x, 0x%x] -> " - "[0x%x, 0x%x, 0x%x]", - mBackbuffer.format.color, mBackbuffer.format.depth, - mBackbuffer.format.stencil, backbuffer.format.color, - backbuffer.format.depth, backbuffer.format.stencil); - } - - // Find the FB config matching the requested format. - int r = 8, g = 8, b = 8, a = 8, d = 24, s = 8; - core::gl::getColorBits(backbuffer.format.color, r, g, b, a); - core::gl::getDepthBits(backbuffer.format.depth, d); - core::gl::getStencilBits(backbuffer.format.stencil, s); - - const int visualAttribs[] = { - // clang-format off - GLX_RED_SIZE, r, - GLX_GREEN_SIZE, g, - GLX_BLUE_SIZE, b, - GLX_ALPHA_SIZE, a, - GLX_DEPTH_SIZE, d, - GLX_STENCIL_SIZE, s, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, - None - // clang-format on - }; - int fbConfigsCount; - GLXFBConfig* fbConfigs = fn_glXChooseFBConfig( - mDisplay, DefaultScreen(mDisplay), visualAttribs, &fbConfigsCount); - if (fbConfigs == nullptr) { - GAPID_FATAL("Unable to find a suitable X framebuffer config"); - } - mFBConfig = fbConfigs[0]; - fn_XFree(fbConfigs); - } - - // Some exotic extensions let you create contexts without a backbuffer. - // In these cases the backbuffer is zero size - just create a small one. - int safe_width = (backbuffer.width > 0) ? backbuffer.width : 8; - int safe_height = (backbuffer.height > 0) ? backbuffer.height : 8; - createPbuffer(safe_width, safe_height); - - if (mContext == nullptr) { - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = - (glXCreateContextAttribsARBProc)fn_glXGetProcAddress( - "glXCreateContextAttribsARB"); - if (glXCreateContextAttribsARB == nullptr) { - GAPID_FATAL("Unable to get address of glXCreateContextAttribsARB"); - } - // Prevent X from taking down the process if the GL version is not - // supported. - auto oldHandler = - fn_XSetErrorHandler([](Display*, XErrorEvent*) -> int { return 0; }); - for (auto gl_version : core::gl::sVersionSearchOrder) { - // List of name-value pairs. - const int contextAttribs[] = { - // clang-format off - GLX_RENDER_TYPE, GLX_RGBA_TYPE, - GLX_CONTEXT_MAJOR_VERSION_ARB, gl_version.major, - GLX_CONTEXT_MINOR_VERSION_ARB, gl_version.minor, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None, - // clang-format on - }; - mContext = glXCreateContextAttribsARB(mDisplay, mFBConfig, mSharedContext, - /* direct */ True, contextAttribs); - if (mContext != nullptr) { - GAPID_DEBUG("Created GL %i.%i context %p (shaded with context %p)", - gl_version.major, gl_version.minor, mContext, - mSharedContext); - break; - } - } - fn_XSetErrorHandler(oldHandler); - if (mContext == nullptr) { - GAPID_FATAL("Failed to create glX context"); - } - fn_XSync(mDisplay, False); - mNeedsResolve = true; - } - - mBackbuffer = backbuffer; -} - -void GlesRendererImpl::bind(bool resetViewportScissor) { - if (!fn_glXMakeContextCurrent(mDisplay, mPbuffer, mPbuffer, mContext)) { - GAPID_FATAL("Unable to make GLX context current"); - } - - if (mNeedsResolve) { - mNeedsResolve = false; - mApi.resolve(); - } - - if (mApi.mFunctionStubs.glDebugMessageCallback != nullptr) { - mApi.mFunctionStubs.glDebugMessageCallback( - reinterpret_cast(&DebugCallback), this); - mApi.mFunctionStubs.glEnable(Gles::GLenum::GL_DEBUG_OUTPUT); - mApi.mFunctionStubs.glEnable(Gles::GLenum::GL_DEBUG_OUTPUT_SYNCHRONOUS); - GAPID_DEBUG("Enabled KHR_debug extension"); - } - - if (resetViewportScissor) { - mApi.mFunctionStubs.glViewport(0, 0, mBackbuffer.width, mBackbuffer.height); - mApi.mFunctionStubs.glScissor(0, 0, mBackbuffer.width, mBackbuffer.height); - } -} - -void GlesRendererImpl::unbind() { - fn_glXMakeContextCurrent(mDisplay, None, None, nullptr); -} - -const char* GlesRendererImpl::name() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_RENDERER)); -} - -const char* GlesRendererImpl::extensions() { - if (!mQueriedExtensions) { - mQueriedExtensions = true; - int32_t n, i; - mApi.mFunctionStubs.glGetIntegerv(Gles::GLenum::GL_NUM_EXTENSIONS, &n); - for (i = 0; i < n; i++) { - if (i > 0) { - mExtensions += " "; - } - mExtensions += reinterpret_cast( - mApi.mFunctionStubs.glGetStringi(Gles::GLenum::GL_EXTENSIONS, i)); - } - } - return &mExtensions[0]; -} - -const char* GlesRendererImpl::vendor() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VENDOR)); -} - -const char* GlesRendererImpl::version() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VERSION)); -} - -} // anonymous namespace - -GlesRenderer* GlesRenderer::create(GlesRenderer* shared_context) { - if (core::hasGLorGLES() && core::DlLoader::can_load("libX11.so")) { - return new GlesRendererImpl( - reinterpret_cast(shared_context)); - } else { - return nullptr; - } -} - -} // namespace gapir diff --git a/gapir/cc/osx/gles_renderer.mm b/gapir/cc/osx/gles_renderer.mm deleted file mode 100644 index 2205f41094..0000000000 --- a/gapir/cc/osx/gles_renderer.mm +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapir/cc/gles_renderer.h" -#include "gapir/cc/gles_gfx_api.h" - -#include "core/cc/gl/formats.h" -#include "core/cc/log.h" - -#include - -#import -#import - -// Some versions of AppKit include these GL defines. -#undef GL_EXTENSIONS -#undef GL_RENDERER -#undef GL_VENDOR -#undef GL_VERSION - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -#define NSWindowStyleMaskBorderless NSBorderlessWindowMask -#endif - -namespace gapir { -namespace { - -class GlesRendererImpl : public GlesRenderer { - public: - GlesRendererImpl(GlesRendererImpl* shared_context); - virtual ~GlesRendererImpl() override; - - virtual Api* api() override; - virtual void setBackbuffer(Backbuffer backbuffer) override; - virtual void bind(bool resetViewportScissor) override; - virtual void unbind() override; - virtual const char* name() override; - virtual const char* extensions() override; - virtual const char* vendor() override; - virtual const char* version() override; - - private: - void reset(); - - Backbuffer mBackbuffer; - std::string mExtensions; - bool mQueriedExtensions; - NSWindow* mWindow; - NSOpenGLContext* mContext; - NSOpenGLContext* mSharedContext; - bool mNeedsResolve; - Gles mApi; -}; - -GlesRendererImpl::GlesRendererImpl(GlesRendererImpl* shared_context) - : mQueriedExtensions(false), - mWindow(nullptr), - mContext(nullptr), - mSharedContext(shared_context != nullptr ? shared_context->mContext : 0), - mNeedsResolve(false) {} - -GlesRendererImpl::~GlesRendererImpl() { - unbind(); - - if (mWindow != nullptr) { - [mWindow close]; - [mWindow release]; - } - - if (mContext != nullptr) { - [mContext release]; - } -} - -Api* GlesRendererImpl::api() { return &mApi; } - -void GlesRendererImpl::setBackbuffer(Backbuffer backbuffer) { - if (mBackbuffer == backbuffer) { - return; // No change - } - - // Some exotic extensions let you create contexts without a backbuffer. - // In these cases the backbuffer is zero size - just create a small one. - int safe_width = (backbuffer.width > 0) ? backbuffer.width : 8; - int safe_height = (backbuffer.height > 0) ? backbuffer.height : 8; - - if (mBackbuffer.format == backbuffer.format) { - // Only a resize is necessary - GAPID_INFO("Resizing renderer: %dx%d -> %dx%d", mBackbuffer.width, mBackbuffer.height, - backbuffer.width, backbuffer.height); - [mWindow setContentSize:NSMakeSize(safe_width, safe_height)]; - [mContext update]; - mBackbuffer = backbuffer; - return; - } else if (mContext != nullptr) { - GAPID_WARNING( - "Attempting to change format of renderer: [0x%x, 0x%x, 0x%x] -> [0x%x, 0x%x, 0x%x]", - mBackbuffer.format.color, mBackbuffer.format.depth, mBackbuffer.format.stencil, - backbuffer.format.color, backbuffer.format.depth, backbuffer.format.stencil); - if (mWindow != nullptr) { - [mWindow close]; - [mWindow release]; - mWindow = nullptr; - } - } - - [NSApplication sharedApplication]; - - NSRect rect = NSMakeRect(0, 0, safe_width, safe_height); - mWindow = [[NSWindow alloc] initWithContentRect:rect - styleMask:NSWindowStyleMaskBorderless - backing:NSBackingStoreBuffered - defer:NO]; - if (mWindow == nullptr) { - GAPID_FATAL("Unable to create NSWindow"); - } - - if (mContext == nullptr) { - int r = 8, g = 8, b = 8, a = 8, d = 24, s = 8; - core::gl::getColorBits(backbuffer.format.color, r, g, b, a); - core::gl::getDepthBits(backbuffer.format.depth, d); - core::gl::getStencilBits(backbuffer.format.stencil, s); - - NSOpenGLPixelFormatAttribute attributes[] = { - // clang-format on - NSOpenGLPFANoRecovery, - NSOpenGLPFAColorSize, - (NSOpenGLPixelFormatAttribute)(r + g + b), - NSOpenGLPFAAlphaSize, - (NSOpenGLPixelFormatAttribute)(a), - NSOpenGLPFADepthSize, - (NSOpenGLPixelFormatAttribute)d, - NSOpenGLPFAStencilSize, - (NSOpenGLPixelFormatAttribute)s, - NSOpenGLPFAAccelerated, - NSOpenGLPFABackingStore, - NSOpenGLPFAOpenGLProfile, - NSOpenGLProfileVersion3_2Core, - (NSOpenGLPixelFormatAttribute)0 - // clang-format off - }; - - NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - if (format == nullptr) { - GAPID_FATAL("Unable to create NSOpenGLPixelFormat"); - } - - mContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:mSharedContext]; - if (mContext == nullptr) { - GAPID_FATAL("Unable to create NSOpenGLContext"); - } - mNeedsResolve = true; - } - - [mContext setView:[mWindow contentView]]; - [mWindow display]; - - mBackbuffer = backbuffer; -} - -void GlesRendererImpl::bind(bool resetViewportScissor) { - [mContext makeCurrentContext]; - - if (mNeedsResolve) { - mNeedsResolve = false; - mApi.resolve(); - } - - if (resetViewportScissor) { - mApi.mFunctionStubs.glViewport(0, 0, mBackbuffer.width, mBackbuffer.height); - mApi.mFunctionStubs.glScissor(0, 0, mBackbuffer.width, mBackbuffer.height); - } -} - -void GlesRendererImpl::unbind() { - [NSOpenGLContext clearCurrentContext]; -} - -const char* GlesRendererImpl::name() { - return reinterpret_cast(mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_RENDERER)); -} - -const char* GlesRendererImpl::extensions() { - if (!mQueriedExtensions) { - mQueriedExtensions = true; - int32_t n, i; - mApi.mFunctionStubs.glGetIntegerv(Gles::GLenum::GL_NUM_EXTENSIONS, &n); - for (i = 0; i < n; i++) { - if (i > 0) { - mExtensions += " "; - } - mExtensions += reinterpret_cast( - mApi.mFunctionStubs.glGetStringi(Gles::GLenum::GL_EXTENSIONS, i)); - } - } - return &mExtensions[0]; -} - -const char* GlesRendererImpl::vendor() { - return reinterpret_cast(mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VENDOR)); -} - -const char* GlesRendererImpl::version() { - return reinterpret_cast(mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VERSION)); -} - -} // anonymous namespace - -GlesRenderer* GlesRenderer::create(GlesRenderer* shared_context) { - return new GlesRendererImpl(reinterpret_cast(shared_context)); -} - -} // namespace gapir diff --git a/gapir/cc/windows/gles_renderer.cpp b/gapir/cc/windows/gles_renderer.cpp deleted file mode 100644 index e11173e0e3..0000000000 --- a/gapir/cc/windows/gles_renderer.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gapir/cc/gles_renderer.h" -#include "gapir/cc/gles_gfx_api.h" - -#include "core/cc/gl/formats.h" -#include "core/cc/gl/versions.h" -#include "core/cc/log.h" -#include "core/cc/thread.h" - -#include -#include -#include -#include - -namespace gapir { -namespace { - -DECLARE_HANDLE(HPBUFFERARB); - -typedef BOOL (*PFNWGLCHOOSEPIXELFORMATARB)(HDC hdc, const int* piAttribIList, - const FLOAT* pfAttribFList, - UINT nMaxFormats, int* piFormats, - UINT* nNumFormats); -typedef HGLRC (*PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC, HGLRC hShareContext, - const int* attribList); -typedef HPBUFFERARB (*PFNWGLCREATEPBUFFERARB)(HDC hDC, int iPixelFormat, - int iWidth, int iHeight, - const int* piAttribList); -typedef HDC (*PFNWGLGETPBUFFERDCARB)(HPBUFFERARB hPbuffer); -typedef int (*PFNWGLRELEASEPBUFFERDCARB)(HPBUFFERARB hPbuffer, HDC hDC); -typedef BOOL (*PFNWGLDESTROYPBUFFERARB)(HPBUFFERARB hPbuffer); -typedef BOOL (*PFNWGLQUERYPBUFFERARB)(HPBUFFERARB hPbuffer, int iAttribute, - int* piValue); - -const int WGL_CONTEXT_RELEASE_BEHAVIOR_ARB = 0x2097; -const int WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; -const int WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; -const int WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB = 0x0000; -const int WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB = 0x2098; - -const int WGL_DRAW_TO_PBUFFER_ARB = 0x202D; -const int WGL_SUPPORT_OPENGL_ARB = 0x2010; -const int WGL_RED_BITS_ARB = 0x2015; -const int WGL_GREEN_BITS_ARB = 0x2017; -const int WGL_BLUE_BITS_ARB = 0x2019; -const int WGL_ALPHA_BITS_ARB = 0x201B; -const int WGL_DEPTH_BITS_ARB = 0x2022; -const int WGL_STENCIL_BITS_ARB = 0x2023; - -const TCHAR* wndClassName = TEXT("gapir"); - -class WGL { - public: - class PBuffer { - public: - ~PBuffer(); - - static std::shared_ptr create( - const GlesRenderer::Backbuffer& backbuffer, PBuffer* shared_ctx); - - void bind(); - void unbind(); - void set_backbuffer(const GlesRenderer::Backbuffer& backbuffer); - - private: - PBuffer(const GlesRenderer::Backbuffer& backbuffer, PBuffer* shared_ctx); - - void create_buffer(const GlesRenderer::Backbuffer& backbuffer); - void release_buffer(); - - HPBUFFERARB mPBuf; - HGLRC mCtx; - HDC mHDC; - }; - - WGL(); - - static const WGL& get(); - - private: - HWND mWindow; - HDC mHDC; - - PFNWGLCHOOSEPIXELFORMATARB ChoosePixelFormatARB; - PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; - PFNWGLCREATEPBUFFERARB CreatePbufferARB; - PFNWGLGETPBUFFERDCARB GetPbufferDCARB; - PFNWGLRELEASEPBUFFERDCARB ReleasePbufferDCARB; - PFNWGLDESTROYPBUFFERARB DestroyPbufferARB; - PFNWGLQUERYPBUFFERARB QueryPbufferARB; -}; - -WGL::PBuffer::PBuffer(const GlesRenderer::Backbuffer& backbuffer, - PBuffer* shared_ctx) - : mPBuf(nullptr), mCtx(nullptr), mHDC(nullptr) { - create_buffer(backbuffer); - - auto wgl = WGL::get(); - for (auto gl_version : core::gl::sVersionSearchOrder) { - std::vector attribs; - attribs.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB); - attribs.push_back(gl_version.major); - attribs.push_back(WGL_CONTEXT_MINOR_VERSION_ARB); - attribs.push_back(gl_version.minor); - // https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_context_flush_control.txt - // These are disabled as they don't seem to improve performance. - // attribs.push_back(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB); - // attribs.push_back(WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB); - attribs.push_back(0); - auto ctx = wgl.CreateContextAttribsARB( - mHDC, (shared_ctx != nullptr) ? shared_ctx->mCtx : nullptr, - attribs.data()); - if (ctx != nullptr) { - mCtx = ctx; - return; - } - } - GAPID_FATAL( - "Failed to create GL context using wglCreateContextAttribsARB. Error: " - "0x%x", - GetLastError()); -} - -WGL::PBuffer::~PBuffer() { - release_buffer(); - if (!wglDeleteContext(mCtx)) { - GAPID_ERROR("Failed to delete GL context. Error: 0x%x", GetLastError()); - } -} - -void WGL::PBuffer::create_buffer(const GlesRenderer::Backbuffer& backbuffer) { - release_buffer(); - - int r = 8, g = 8, b = 8, a = 8, d = 24, s = 8; - core::gl::getColorBits(backbuffer.format.color, r, g, b, a); - core::gl::getDepthBits(backbuffer.format.depth, d); - core::gl::getStencilBits(backbuffer.format.stencil, s); - - // Some exotic extensions let you create contexts without a backbuffer. - // In these cases the backbuffer is zero size - just create a small one. - int safe_width = (backbuffer.width > 0) ? backbuffer.width : 8; - int safe_height = (backbuffer.height > 0) ? backbuffer.height : 8; - - const unsigned int MAX_FORMATS = 32; - - int formats[MAX_FORMATS]; - unsigned int num_formats; - const int fmt_attribs[] = { - // clang-format off - WGL_DRAW_TO_PBUFFER_ARB, 1, - WGL_SUPPORT_OPENGL_ARB, 1, - WGL_DEPTH_BITS_ARB, d, - WGL_STENCIL_BITS_ARB, s, - WGL_RED_BITS_ARB, r, - WGL_GREEN_BITS_ARB, g, - WGL_BLUE_BITS_ARB, b, - WGL_ALPHA_BITS_ARB, a, - 0, // terminator - // clang-format on - }; - - auto wgl = WGL::get(); - - if (!wgl.ChoosePixelFormatARB(wgl.mHDC, fmt_attribs, nullptr, MAX_FORMATS, - formats, &num_formats)) { - GAPID_FATAL("wglChoosePixelFormatARB failed. Error: 0x%x", GetLastError()); - } - if (num_formats == 0) { - GAPID_FATAL("wglChoosePixelFormatARB returned no compatibile formats"); - } - auto format = formats[0]; // TODO: Examine returned formats? - const int create_attribs[] = {0}; - mPBuf = wgl.CreatePbufferARB(wgl.mHDC, format, safe_width, safe_height, - create_attribs); - if (mPBuf == nullptr) { - GAPID_FATAL("wglCreatePbufferARB(%p, %d, %d, %d, %p) failed. Error: 0x%x", - wgl.mHDC, format, safe_width, safe_height, create_attribs, - GetLastError()); - } - - mHDC = wgl.GetPbufferDCARB(mPBuf); - if (mHDC == nullptr) { - GAPID_FATAL("wglGetPbufferDCARB(%p) failed. Error: 0x%x", mPBuf, - GetLastError()); - } -} - -void WGL::PBuffer::release_buffer() { - auto wgl = WGL::get(); - if (mHDC != nullptr) { - unbind(); - if (!wgl.ReleasePbufferDCARB(mPBuf, mHDC)) { - GAPID_ERROR("Failed to release HDC. Error: 0x%x", GetLastError()); - } - mHDC = nullptr; - } - if (mPBuf != nullptr) { - if (!wgl.DestroyPbufferARB(mPBuf)) { - GAPID_ERROR("Failed to destroy pbuffer. Error: 0x%x", GetLastError()); - } - mPBuf = nullptr; - } -} - -void WGL::PBuffer::bind() { - if (!wglMakeCurrent(mHDC, mCtx)) { - GAPID_FATAL("Failed to bind GL context. Error: 0x%x", GetLastError()); - } -} - -void WGL::PBuffer::unbind() { - if (!wglMakeCurrent(mHDC, nullptr)) { - GAPID_FATAL("Failed to unbind GL context. Error: 0x%x", GetLastError()); - } -} - -void WGL::PBuffer::set_backbuffer(const GlesRenderer::Backbuffer& backbuffer) { - // Kill the pbuffer, and create a new one with the new backbuffer settings. - // - // Note - according to the MSDN documentation of wglMakeCurrent: - // "It need not be the same hdc that was passed to wglCreateContext when - // hglrc was created, but it must be on the same device and have the same - // pixel format." - // - // This means pixel format changes should error. If this happens, we're - // going to have to come up with a different approach. - create_buffer(backbuffer); -} - -std::shared_ptr WGL::PBuffer::create( - const GlesRenderer::Backbuffer& backbuffer, PBuffer* shared_ctx) { - return std::shared_ptr(new PBuffer(backbuffer, shared_ctx)); -} - -WGL::WGL() { - class registerWindowClass { - public: - registerWindowClass() { - WNDCLASS wc; - memset(&wc, 0, sizeof(wc)); - - auto hInstance = GetModuleHandle(nullptr); - if (hInstance == nullptr) { - GAPID_FATAL("Failed to get module handle. Error: 0x%x", GetLastError()); - } - - wc.style = 0; - wc.lpfnWndProc = DefWindowProc; - wc.hInstance = hInstance; - wc.hCursor = LoadCursor(0, IDC_ARROW); // TODO: Needed? - wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1); - wc.lpszMenuName = TEXT(""); - wc.lpszClassName = wndClassName; - - if (RegisterClass(&wc) == 0) { - GAPID_FATAL("Failed to register window class. Error: 0x%x", - GetLastError()); - } - } - }; - - static registerWindowClass rwc; - - mWindow = CreateWindow(wndClassName, TEXT(""), WS_POPUP, 0, 0, 8, 8, 0, 0, - GetModuleHandle(0), 0); - if (mWindow == 0) { - GAPID_FATAL("Failed to create window. Error: 0x%x", GetLastError()); - } - - mHDC = GetDC(mWindow); - if (mHDC == nullptr) { - GAPID_FATAL("GetDC failed. Error: 0x%x", GetLastError()); - } - - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cRedBits = 8; - pfd.cGreenBits = 8; - pfd.cBlueBits = 8; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - pfd.cColorBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - int pixel_fmt = ChoosePixelFormat(mHDC, &pfd); - SetPixelFormat(mHDC, pixel_fmt, &pfd); - - // Resolve extension functions. - CreateContextAttribsARB = nullptr; - auto temp_context = wglCreateContext(mHDC); - if (temp_context == nullptr) { - GAPID_FATAL("Couldn't create temporary WGL context. Error: 0x%x", - GetLastError()); - } - - wglMakeCurrent(mHDC, temp_context); - -#define RESOLVE(name) \ - name = reinterpret_cast(wglGetProcAddress("wgl" #name)); \ - if (name == nullptr) { \ - GAPID_FATAL("Couldn't resolve function 'wgl" #name "'"); \ - } - - RESOLVE(CreateContextAttribsARB); - RESOLVE(ChoosePixelFormatARB); - RESOLVE(CreateContextAttribsARB); - RESOLVE(CreatePbufferARB); - RESOLVE(GetPbufferDCARB); - RESOLVE(ReleasePbufferDCARB); - RESOLVE(DestroyPbufferARB); - RESOLVE(QueryPbufferARB); - -#undef RESOLVE - - wglMakeCurrent(mHDC, nullptr); - wglDeleteContext(temp_context); -} - -const WGL& WGL::get() { - // This is thread-local as anything touching a HDC is pretty much - // non-thread safe. - static thread_local WGL instance; - return instance; -} - -class GlesRendererImpl : public GlesRenderer { - public: - GlesRendererImpl(GlesRendererImpl* shared_context); - virtual ~GlesRendererImpl() override; - - virtual Api* api() override; - virtual void setBackbuffer(Backbuffer backbuffer) override; - virtual void bind(bool resetViewportScissor) override; - virtual void unbind() override; - virtual const char* name() override; - virtual const char* extensions() override; - virtual const char* vendor() override; - virtual const char* version() override; - - private: - Gles mApi; - Backbuffer mBackbuffer; - - bool mNeedsResolve; - bool mQueriedExtensions; - std::string mExtensions; - std::shared_ptr mContext; - std::shared_ptr mSharedContext; -}; - -GlesRendererImpl::GlesRendererImpl(GlesRendererImpl* shared_context) - : mNeedsResolve(true), - mQueriedExtensions(false), - mSharedContext(shared_context != nullptr ? shared_context->mContext - : nullptr) {} - -GlesRendererImpl::~GlesRendererImpl() { unbind(); } - -Api* GlesRendererImpl::api() { return &mApi; } - -static void DebugCallback(uint32_t source, uint32_t type, Gles::GLuint id, - uint32_t severity, Gles::GLsizei length, - const Gles::GLchar* message, const void* user_param) { - auto renderer = reinterpret_cast(user_param); - auto listener = renderer->getListener(); - if (listener != nullptr) { - if (type == Gles::GLenum::GL_DEBUG_TYPE_ERROR || - severity == Gles::GLenum::GL_DEBUG_SEVERITY_HIGH) { - listener->onDebugMessage(LOG_LEVEL_ERROR, Gles::INDEX, message); - } else { - listener->onDebugMessage(LOG_LEVEL_DEBUG, Gles::INDEX, message); - } - } -} - -void GlesRendererImpl::setBackbuffer(Backbuffer backbuffer) { - if (mBackbuffer == backbuffer) { - return; // No change - } - - if (mContext == nullptr) { - mContext = WGL::PBuffer::create(backbuffer, mSharedContext.get()); - mNeedsResolve = true; - } else { - mContext->set_backbuffer(backbuffer); - } - - mBackbuffer = backbuffer; -} - -void GlesRendererImpl::bind(bool resetViewportScissor) { - if (mContext == nullptr) { - GAPID_FATAL("Attempted to bind a null context"); - } - mContext->bind(); - - if (mNeedsResolve) { - mNeedsResolve = false; - mApi.resolve(); - } - - if (mApi.mFunctionStubs.glDebugMessageCallback != nullptr) { - mApi.mFunctionStubs.glDebugMessageCallback( - reinterpret_cast(&DebugCallback), this); - mApi.mFunctionStubs.glEnable(Gles::GLenum::GL_DEBUG_OUTPUT); - mApi.mFunctionStubs.glEnable(Gles::GLenum::GL_DEBUG_OUTPUT_SYNCHRONOUS); - GAPID_DEBUG("Enabled KHR_debug extension"); - } - - if (resetViewportScissor) { - mApi.mFunctionStubs.glViewport(0, 0, mBackbuffer.width, mBackbuffer.height); - mApi.mFunctionStubs.glScissor(0, 0, mBackbuffer.width, mBackbuffer.height); - } -} - -void GlesRendererImpl::unbind() { - if (mContext != nullptr) { - mContext->unbind(); - } -} - -const char* GlesRendererImpl::name() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_RENDERER)); -} - -const char* GlesRendererImpl::extensions() { - if (!mQueriedExtensions) { - mQueriedExtensions = true; - int32_t n, i; - mApi.mFunctionStubs.glGetIntegerv(Gles::GLenum::GL_NUM_EXTENSIONS, &n); - bool first = true; - for (i = 0; i < n; i++) { - const char* extension = reinterpret_cast( - mApi.mFunctionStubs.glGetStringi(Gles::GLenum::GL_EXTENSIONS, i)); - if (extension == nullptr) { - GAPID_WARNING("glGetStringi(GL_EXTENSIONS, %d) return nullptr", i); - continue; - } - if (!first) { - mExtensions += " "; - } - mExtensions += extension; - first = false; - } - } - return (mExtensions.size() > 0) ? &mExtensions[0] : nullptr; -} - -const char* GlesRendererImpl::vendor() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VENDOR)); -} - -const char* GlesRendererImpl::version() { - return reinterpret_cast( - mApi.mFunctionStubs.glGetString(Gles::GLenum::GL_VERSION)); -} - -} // anonymous namespace - -GlesRenderer* GlesRenderer::create(GlesRenderer* shared_context) { - return new GlesRendererImpl( - reinterpret_cast(shared_context)); -} - -} // namespace gapir diff --git a/gapis/api/all/BUILD.bazel b/gapis/api/all/BUILD.bazel index 5fe911d74a..c55335af0e 100644 --- a/gapis/api/all/BUILD.bazel +++ b/gapis/api/all/BUILD.bazel @@ -20,8 +20,6 @@ go_library( importpath = "github.com/google/gapid/gapis/api/all", visibility = ["//visibility:public"], deps = [ - "//gapis/api/gles:go_default_library", - "//gapis/api/gvr:go_default_library", "//gapis/api/vulkan:go_default_library", ], ) diff --git a/gapis/api/all/all.go b/gapis/api/all/all.go index f5b581a77b..bf7ec86d3a 100644 --- a/gapis/api/all/all.go +++ b/gapis/api/all/all.go @@ -16,7 +16,5 @@ package all import ( - _ "github.com/google/gapid/gapis/api/gles" - _ "github.com/google/gapid/gapis/api/gvr" _ "github.com/google/gapid/gapis/api/vulkan" ) diff --git a/gapis/api/gles/BUILD.bazel b/gapis/api/gles/BUILD.bazel deleted file mode 100644 index 7ad3d48a1c..0000000000 --- a/gapis/api/gles/BUILD.bazel +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("//tools/build:rules.bzl", "api_library", "apic_template") - -filegroup( - name = "api_files", - srcs = glob([ - "*.api", - "api/*.api", - ]), - visibility = ["//visibility:public"], -) - -api_library( - name = "api", - api = "gles.api", - apiname = "gles", - includes = [":api_files"], - visibility = ["//visibility:public"], - deps = ["//gapis/messages:api"], -) - -apic_template( - name = "generated", - api = ":api", - templates = [ - "//gapis/api/templates:api", - "//gapis/api/templates:api_types", - "//gapis/api/templates:mutate", - "//gapis/api/templates:constant_sets", - "//gapis/api/templates:convert", - "//gapis/api/templates:proto", - "//gapis/api/templates:state_serialize", - ], - visibility = ["//visibility:public"], -) - -go_library( - name = "go_default_library", - srcs = [ - "compat.go", - "compat_buffers.go", - "compat_client.go", - "context.go", - "custom_replay.go", - "datatypes.go", - "dependency_graph_behaviour_provider.go", - "doc.go", - "draw_call.go", - "draw_call_mesh.go", - "externs.go", - "extras.go", - "find_issues.go", - "gles.go", - "glsl.go", - "graph_visualization.go", - "guess_semantics.go", - "helpers.go", - "image.go", - "importance.go", - "issue_whitelist.go", - "links.go", - "markers.go", - "math.go", - "read_depth.go", - "read_framebuffer.go", - "read_texture.go", - "replay.go", - "resources.go", - "state.go", - "state_builder.go", - "string.go", - "stub_program.go", - "texture_compat.go", - "tweaker.go", - "undefined_framebuffer.go", - "version.go", - "wireframe.go", - ], - embed = [ - ":generated", # keep - ":gles_go_proto", - ], - importpath = "github.com/google/gapid/gapis/api/gles", - visibility = ["//visibility:public"], - deps = [ - "//core/app/analytics:go_default_library", - "//core/app/status:go_default_library", - "//core/context/keys:go_default_library", - "//core/data/binary:go_default_library", - "//core/data/compare:go_default_library", - "//core/data/dictionary:go_default_library", - "//core/data/endian:go_default_library", - "//core/data/id:go_default_library", - "//core/data/protoconv:go_default_library", - "//core/event/task:go_default_library", # keep - "//core/image:go_default_library", - "//core/image/astc:go_default_library", - "//core/log:go_default_library", - "//core/math/interval:go_default_library", - "//core/math/sint:go_default_library", - "//core/math/u32:go_default_library", - "//core/math/u64:go_default_library", - "//core/memory/arena:go_default_library", # keep - "//core/os/device:go_default_library", - "//core/stream:go_default_library", - "//core/stream/fmts:go_default_library", - "//core/text:go_default_library", - "//gapil/constset:go_default_library", # keep - "//gapis/api:go_default_library", - "//gapis/api/gles/gles_pb:go_default_library", - "//gapis/api/transform:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/config:go_default_library", - "//gapis/database:go_default_library", - "//gapis/memory:go_default_library", - "//gapis/memory/memory_pb:go_default_library", # keep - "//gapis/messages:go_default_library", - "//gapis/replay:go_default_library", - "//gapis/replay/builder:go_default_library", - "//gapis/replay/protocol:go_default_library", - "//gapis/replay/value:go_default_library", - "//gapis/resolve:go_default_library", - "//gapis/resolve/dependencygraph:go_default_library", - "//gapis/service:go_default_library", - "//gapis/service/box:go_default_library", - "//gapis/service/memory_box:go_default_library", #keep - "//gapis/service/path:go_default_library", - "//gapis/service/types:go_default_library", #keep - "//gapis/shadertools:go_default_library", - "//gapis/stringtable:go_default_library", - "//gapis/vertex:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_pkg_errors//:go_default_library", - ], -) - -proto_library( - name = "gles_proto", - srcs = ["resolvables.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/image:image_proto", - "//gapis/service/path:path_proto", - ], -) - -go_proto_library( - name = "gles_go_proto", - importpath = "github.com/google/gapid/gapis/api/gles", - proto = ":gles_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/image:go_default_library", - "//gapis/service/path:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "compat_test.go", - "dead_code_elimination_test.go", - "dependencygraph2_test.go", - "markers_test.go", - "stub_program_test.go", - ], - embed = [":go_default_library"], - deps = [ - "//core/assert:go_default_library", - "//core/log:go_default_library", - "//core/memory/arena:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//gapis/api:go_default_library", - "//gapis/api/transform:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/database:go_default_library", - "//gapis/memory:go_default_library", - "//gapis/resolve/dependencygraph:go_default_library", - "//gapis/resolve/dependencygraph2:go_default_library", - ], -) diff --git a/gapis/api/gles/api/android_extension_pack.api b/gapis/api/gles/api/android_extension_pack.api deleted file mode 100644 index b3a1a670d8..0000000000 --- a/gapis/api/gles/api/android_extension_pack.api +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@if(Extension.GL_KHR_blend_equation_advanced) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_blend_equation_advanced.txt", Extension.GL_KHR_blend_equation_advanced) -cmd void glBlendBarrierKHR() { - BlendBarrier() -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glBlendEquationSeparateiEXT(DrawBufferIndex buf, GLenum modeRGB, GLenum modeAlpha) { - BlendEquationSeparatei(buf, modeRGB, modeAlpha) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glBlendEquationiEXT(DrawBufferIndex buf, GLenum mode) { - BlendEquationi(buf, mode) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glBlendFuncSeparateiEXT(DrawBufferIndex buf, - GLenum srcRGB, - GLenum dstRGB, - GLenum srcAlpha, - GLenum dstAlpha) { - BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glBlendFunciEXT(DrawBufferIndex buf, GLenum src, GLenum dst) { - BlendFunci(buf, src, dst) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glColorMaskiEXT(DrawBufferIndex index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - ColorMaski(index, r, g, b, a) -} - -@if(Extension.GL_EXT_copy_image) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_copy_image.txt", Extension.GL_EXT_copy_image) -cmd void glCopyImageSubDataEXT(SrcImageId srcName, - GLenum srcTarget, - GLint srcLevel, - GLint srcX, - GLint srcY, - GLint srcZ, - DstImageId dstName, - GLenum dstTarget, - GLint dstLevel, - GLint dstX, - GLint dstY, - GLint dstZ, - GLsizei srcWidth, - GLsizei srcHeight, - GLsizei srcDepth) { - CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glDebugMessageCallbackKHR(GLDEBUGPROC callback, const void* userParam) { - DebugMessageCallback(callback, userParam) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glDebugMessageControlKHR(GLenum source, - GLenum type, - GLenum severity, - GLsizei count, - const GLuint* ids, - GLboolean enabled) { - DebugMessageControl(source, type, severity, count, ids, enabled) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glDebugMessageInsertKHR(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message) { - DebugMessageInsert(source, type, id, severity, length, message) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glDisableiEXT(GLenum target, GLuint index) { - Disablei(target, index) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd void glEnableiEXT(GLenum target, GLuint index) { - Enablei(target, index) -} - -@if(Extension.GL_EXT_geometry_shader) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_geometry_shader.txt", Extension.GL_EXT_geometry_shader) -cmd void glFramebufferTextureEXT(GLenum target, GLenum attachment, TextureId texture, GLint level) { - FramebufferTexture(target, attachment, texture, level) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd GLuint glGetDebugMessageLogKHR(GLuint count, - GLsizei bufSize, - GLenum* sources, - GLenum* types, - GLuint* ids, - GLenum* severities, - GLsizei* lengths, - GLchar* messageLog) { - l := ? - GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog, l) - return l -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glGetObjectLabelKHR(GLenum identifier, - GLuint name, - GLsizei bufSize, - GLsizei* length, - GLchar* label) { - GetObjectLabel(identifier, name, bufSize, length, label) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glGetObjectPtrLabelKHR(const void* ptr, - GLsizei bufSize, - GLsizei* length, - GLchar* label) { - GetObjectPtrLabel(ptr, bufSize, length, label) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glGetPointervKHR(GLenum pname, void** params) { - GetPointerv(pname, params) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glGetSamplerParameterIivEXT(SamplerId sampler, GLenum pname, GLint* params) { - GetSamplerParameterIiv(sampler, pname, params) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glGetSamplerParameterIuivEXT(SamplerId sampler, GLenum pname, GLuint* params) { - GetSamplerParameterIuiv(sampler, pname, params) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glGetTexParameterIivEXT(GLenum target, GLenum pname, GLint* params) { - GetTexParameterIiv(target, pname, params) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glGetTexParameterIuivEXT(GLenum target, GLenum pname, GLuint* params) { - GetTexParameterIuiv(target, pname, params) -} - -@if(Extension.GL_EXT_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers_indexed.txt", Extension.GL_EXT_draw_buffers_indexed) -cmd GLboolean glIsEnablediEXT(GLenum target, GLuint index) { - return IsEnabledi(target, index) -} - -@if(Extension.GL_OES_sample_shading) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_sample_shading.txt", Extension.GL_OES_sample_shading) -cmd void glMinSampleShadingOES(GLfloat value) { - MinSampleShading(value) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glObjectLabelKHR(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) { - ObjectLabel(identifier, name, length, label) -} - -@if(Extension.GL_KHR_debug) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glObjectPtrLabelKHR(const void* ptr, GLsizei length, const GLchar* label) { - ObjectPtrLabel(ptr, length, label) -} - -@if(Extension.GL_EXT_tessellation_shader) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_tessellation_shader.txt", Extension.GL_EXT_tessellation_shader) -cmd void glPatchParameteriEXT(GLenum pname, GLint value) { - PatchParameteri(pname, value) -} - -@if(Extension.GL_KHR_debug) -@pop_user_marker -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glPopDebugGroupKHR() { - PopDebugGroup() -} - -@if(Extension.GL_EXT_primitive_bounding_box) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_primitive_bounding_box.txt", Extension.GL_EXT_primitive_bounding_box) -cmd void glPrimitiveBoundingBoxEXT(GLfloat minX, - GLfloat minY, - GLfloat minZ, - GLfloat minW, - GLfloat maxX, - GLfloat maxY, - GLfloat maxZ, - GLfloat maxW) { - PrimitiveBoundingBox(minX, minY, minZ, minW, maxX, maxY, maxZ, maxW) -} - -@if(Extension.GL_KHR_debug) -@push_user_marker -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_debug.txt", Extension.GL_KHR_debug) -cmd void glPushDebugGroupKHR(GLenum source, GLuint id, GLsizei length, const GLchar* message) { - PushDebugGroup(source, id, length, message) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glSamplerParameterIivEXT(SamplerId sampler, GLenum pname, const GLint* param) { - SamplerParameterIiv(sampler, pname, param) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glSamplerParameterIuivEXT(SamplerId sampler, GLenum pname, const GLuint* param) { - SamplerParameterIuiv(sampler, pname, param) -} - -@if(Extension.GL_EXT_texture_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_buffer.txt", Extension.GL_EXT_texture_buffer) -cmd void glTexBufferEXT(GLenum target, GLenum internalformat, BufferId buffer) { - TexBuffer(target, internalformat, buffer) -} - -@if(Extension.GL_EXT_texture_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_buffer.txt", Extension.GL_EXT_texture_buffer) -cmd void glTexBufferRangeEXT(GLenum target, - GLenum internalformat, - BufferId buffer, - GLintptr offset, - GLsizeiptr size) { - TexBufferRange(target, internalformat, buffer, offset, size) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glTexParameterIivEXT(GLenum target, GLenum pname, const GLint* params) { - TexParameterIiv(target, pname, params) -} - -@if(Extension.GL_EXT_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_border_clamp.txt", Extension.GL_EXT_texture_border_clamp) -cmd void glTexParameterIuivEXT(GLenum target, GLenum pname, const GLuint* params) { - TexParameterIuiv(target, pname, params) -} - -@if(Extension.GL_OES_texture_storage_multisample_2d_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_storage_multisample_2d_array.txt", Extension.GL_OES_texture_storage_multisample_2d_array) -cmd void glTexStorage3DMultisampleOES(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLboolean fixedsamplelocations) { - TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) -} diff --git a/gapis/api/gles/api/android_native.api b/gapis/api/gles/api/android_native.api deleted file mode 100644 index 0572813cb3..0000000000 --- a/gapis/api/gles/api/android_native.api +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class AndroidNativeBufferExtra { - u32 Width - u32 Height - @unused u32 Stride - AndroidGraphicsBufferFormat Format - @unused AndroidGraphicsBufferUsage Usage - u32 LayerCount -} - -type void* AHardwareBuffer - -@post_fence -extern ref!AndroidNativeBufferExtra GetAndroidNativeBufferExtra(void* buffer) - -enum AndroidGraphicsBufferFormat { - HAL_PIXEL_FORMAT_RGBA_8888 = 0x01, - HAL_PIXEL_FORMAT_RGBX_8888 = 0x02, - HAL_PIXEL_FORMAT_RGB_888 = 0x03, - HAL_PIXEL_FORMAT_RGB_565 = 0x04, - HAL_PIXEL_FORMAT_BGRA_8888 = 0x05, - HAL_PIXEL_FORMAT_RGBA_5551 = 0x06, - HAL_PIXEL_FORMAT_RGBA_4444 = 0x07, - HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21 -} - -@analyze_usage -enum AndroidGraphicsBufferUsage { - USAGE_SW_READ_NEVER = 0x00000000, - USAGE_SW_READ_RARELY = 0x00000002, - USAGE_SW_READ_OFTEN = 0x00000003, - USAGE_SW_READ_MASK = 0x0000000F, - USAGE_SW_WRITE_NEVER = 0x00000000, - USAGE_SW_WRITE_RARELY = 0x00000020, - USAGE_SW_WRITE_OFTEN = 0x00000030, - USAGE_SW_WRITE_MASK = 0x000000F0, - USAGE_HW_TEXTURE = 0x00000100, - USAGE_HW_RENDER = 0x00000200, - USAGE_HW_2D = 0x00000400, - USAGE_HW_FB = 0x00001000, - USAGE_HW_MASK = 0x00001F00, -} diff --git a/gapis/api/gles/api/asynchronous_queries.api b/gapis/api/gles/api/asynchronous_queries.api deleted file mode 100644 index 0bec7a9f1e..0000000000 --- a/gapis/api/gles/api/asynchronous_queries.api +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class Query { - QueryId ID - GLenum Type - bool Active - - // Table 21.31: Query Object State - // GLuint QueryResult = 0 // TODO: or GL_FALSE? - // GLboolean QueryResultAvailable = GL_FALSE - @unused string Label -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBeginQuery.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBeginQuery.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBeginQuery.xhtml", Version.GLES32) -cmd void glBeginQuery(GLenum target, QueryId query) { - switch (target) { - case GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: { - // version 3.0 - } - @if(Version.GLES32) - case GL_PRIMITIVES_GENERATED: { - } - default: { - glErrorInvalidEnum(target) - } - } - ctx := GetContext() - q := GetOrCreateQuery(query, target) - q.Active = true - ctx.Other.ActiveQueries[target] = q -} - -sub ref!Query GetOrCreateQuery(QueryId id, GLenum type) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.Queries[id] == null) { - ctx.Objects.Queries[id] = new!Query(ID: id, Type: type) - ctx.Objects.GeneratedNames.Queries[id] = true - } - return ctx.Objects.Queries[id] -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteQueries.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteQueries.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteQueries.xhtml", Version.GLES32) -cmd void glDeleteQueries(GLsizei count, const QueryId* queries) { - DeleteQueries(count, queries) -} - -sub void DeleteQueries(GLsizei count, const QueryId* queries) { - CheckCountGE!GLsizei(count, 0) - q := queries[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := q[i] - if id != 0 { - delete(ctx.Objects.Queries, id) - delete(ctx.Objects.GeneratedNames.Queries, id) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBeginQuery.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBeginQuery.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBeginQuery.xhtml", Version.GLES32) -cmd void glEndQuery(GLenum target) { - switch (target) { - case GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: { - // version 3.0 - } - @if(Version.GLES32) - case GL_PRIMITIVES_GENERATED: { - } - default: { - glErrorInvalidEnum(target) - } - } - ctx := GetContext() - if !(target in ctx.Other.ActiveQueries) { glErrorInvalidOperation() } - ctx.Other.ActiveQueries[target].Active = false - delete(ctx.Other.ActiveQueries, target) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenQueries.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenQueries.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenQueries.xhtml", Version.GLES32) -cmd void glGenQueries(GLsizei count, QueryId* queries) { - GenQueries(count, queries) -} - -sub void GenQueries(GLsizei count, QueryId* queries) { - CheckCountGE!GLsizei(count, 0) - q := queries[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!QueryId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Queries[id] = true - q[i] = id - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetQueryObjectuiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetQueryObjectuiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetQueryObjectuiv.xhtml", Version.GLES32) -cmd void glGetQueryObjectuiv(QueryId query, GLenum parameter, GLuint* value) { - switch (parameter) { - case GL_QUERY_RESULT, GL_QUERY_RESULT_AVAILABLE: { - // version 3.0 - } - default: { - glErrorInvalidEnum(parameter) - } - } - - value[0] = ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetQueryiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetQueryiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetQueryiv.xhtml", Version.GLES32) -cmd void glGetQueryiv(GLenum target, GLenum parameter, GLint* value) { - switch (target) { - case GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: { - // version 3.0 - } - @if(Version.GLES32) - case GL_PRIMITIVES_GENERATED: { - } - @if(Extension.GL_EXT_disjoint_timer_query) - case GL_TIMESTAMP_EXT: { - } - default: { - glErrorInvalidEnum(target) - } - } - switch (parameter) { - case GL_CURRENT_QUERY: { - // version 3.0 - ctx := GetContext() - if (target in ctx.Other.ActiveQueries) { - value[0] = as!GLint(ctx.Other.ActiveQueries[target].ID) - } else { - value[0] = 0 - } - } - @if(Extension.GL_EXT_disjoint_timer_query) - case GL_QUERY_COUNTER_BITS_EXT: { - value[0] = ? - } - default: { - glErrorInvalidEnum(parameter) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsQuery.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsQuery.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsQuery.xhtml", Version.GLES32) -cmd GLboolean glIsQuery(QueryId query) { - - ctx := GetContext() - return toGLboolean(query in ctx.Objects.Queries) -} diff --git a/gapis/api/gles/api/buffer_objects.api b/gapis/api/gles/api/buffer_objects.api deleted file mode 100644 index b62b80caec..0000000000 --- a/gapis/api/gles/api/buffer_objects.api +++ /dev/null @@ -1,531 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class Buffer { - BufferId ID - - @internal u8[] Data - - // Table 21.5: Buffer Object State - GLsizeiptr Size = 0 - GLenum Usage = GL_STATIC_DRAW - GLboolean Mapped = GL_FALSE - GLbitfield AccessFlags - u8* MapPointer = null - GLintptr MapOffset = 0 - GLsizeiptr MapLength = 0 - @unused string Label -} - -sub ref!Buffer GetBoundBufferOrError(GLenum target) { - b := GetBoundBuffer(target) - if b == null { glErrorInvalidOperation() } - return b -} - -sub ref!Buffer GetBoundBuffer(GLenum target) { - ctx := GetContext() - // TODO: The error conditions are not spelled out for all commands in the spec. - b := switch (target) { - @if(Version.GLES20) - case GL_ARRAY_BUFFER: { - ctx.Bound.ArrayBuffer - } - @if(Version.GLES20) - case GL_ELEMENT_ARRAY_BUFFER: { - ctx.Bound.VertexArray.ElementArrayBuffer - } - @if(Version.GLES30) - case GL_COPY_READ_BUFFER: { - ctx.Bound.CopyReadBuffer - } - @if(Version.GLES30) - case GL_COPY_WRITE_BUFFER: { - ctx.Bound.CopyWriteBuffer - } - @if(Version.GLES30) - case GL_PIXEL_PACK_BUFFER: { - ctx.Bound.PixelPackBuffer - } - @if(Version.GLES30) - case GL_PIXEL_UNPACK_BUFFER: { - ctx.Bound.PixelUnpackBuffer - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER: { - ctx.Bound.TransformFeedbackBuffer - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER: { - ctx.Bound.UniformBuffer - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER: { - ctx.Bound.AtomicCounterBuffer - } - @if(Version.GLES31) - case GL_DISPATCH_INDIRECT_BUFFER: { - ctx.Bound.DispatchIndirectBuffer - } - @if(Version.GLES31) - case GL_DRAW_INDIRECT_BUFFER: { - ctx.Bound.DrawIndirectBuffer - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER: { - ctx.Bound.ShaderStorageBuffer - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER: { - ctx.Bound.TextureBuffer - } - default: { - // TODO: glErrorInvalidEnum(target) - as!ref!Buffer(null) - } - } - return b -} - -sub ref!Buffer GetBoundBufferAtIndex(GLenum target, GLuint index) { - ctx := GetContext() - bb := switch (target) { - @if(Version.GLES30) case GL_TRANSFORM_FEEDBACK_BUFFER: ctx.Bound.TransformFeedback.Buffers[index] - @if(Version.GLES30) case GL_UNIFORM_BUFFER: ctx.Bound.UniformBuffers[index] - @if(Version.GLES31) case GL_ATOMIC_COUNTER_BUFFER: ctx.Bound.AtomicCounterBuffers[index] - @if(Version.GLES31) case GL_SHADER_STORAGE_BUFFER: ctx.Bound.ShaderStorageBuffers[index] - default: BufferBinding() - } - return bb.Binding -} - -sub ref!Buffer GetOrCreateBuffer(BufferId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.Buffers[id] == null) { - ctx.Objects.Buffers[id] = new!Buffer(ID: id) - ctx.Objects.GeneratedNames.Buffers[id] = true - } - return ctx.Objects.Buffers[id] -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindBuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindBuffer.xhtml", Version.GLES32) -cmd void glBindBuffer(GLenum target, BufferId buffer) { - ctx := GetContext() - switch (target) { - case GL_ARRAY_BUFFER: { - ctx.Bound.ArrayBuffer = GetOrCreateBuffer(buffer) - } - case GL_ELEMENT_ARRAY_BUFFER: { - ctx.Bound.VertexArray.ElementArrayBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_COPY_READ_BUFFER: { - ctx.Bound.CopyReadBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_COPY_WRITE_BUFFER: { - ctx.Bound.CopyWriteBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_PIXEL_PACK_BUFFER: { - ctx.Bound.PixelPackBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_PIXEL_UNPACK_BUFFER: { - ctx.Bound.PixelUnpackBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER: { - ctx.Bound.TransformFeedback.Buffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER: { - ctx.Bound.UniformBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER: { - ctx.Bound.AtomicCounterBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES31) - case GL_DISPATCH_INDIRECT_BUFFER: { - ctx.Bound.DispatchIndirectBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES31) - case GL_DRAW_INDIRECT_BUFFER: { - ctx.Bound.DrawIndirectBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER: { - ctx.Bound.ShaderStorageBuffer = GetOrCreateBuffer(buffer) - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER: { - ctx.Bound.TextureBuffer = GetOrCreateBuffer(buffer) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindBufferBase.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindBufferBase.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindBufferBase.xhtml", Version.GLES32) -cmd void glBindBufferBase(GLenum target, GLuint index, BufferId buffer) { - ctx := GetContext() - size := switch (buffer in ctx.Objects.Buffers) { - case true: ctx.Objects.Buffers[buffer].Size - case false: as!GLsizeiptr(0) - } - BindBufferRange(target, index, buffer, 0, size) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindBufferRange.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindBufferRange.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindBufferRange.xhtml", Version.GLES32) -cmd void glBindBufferRange(GLenum target, - GLuint index, - BufferId buffer, - GLintptr offset, - GLsizeiptr size) { - BindBufferRange(target, index, buffer, offset, size) -} - -sub void BindBufferRange(GLenum target, - GLuint index, - BufferId buffer, - GLintptr offset, - GLsizeiptr size) { - ctx := GetContext() - switch (target) { - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER: { - b := GetOrCreateBuffer(buffer) - ctx.Bound.TransformFeedback.Buffer = b - ctx.Bound.TransformFeedback.Buffers[index] = BufferBinding(b, offset, size) - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER: { - b := GetOrCreateBuffer(buffer) - ctx.Bound.UniformBuffer = b - ctx.Bound.UniformBuffers[index] = BufferBinding(b, offset, size) - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER: { - b := GetOrCreateBuffer(buffer) - ctx.Bound.AtomicCounterBuffer = b - ctx.Bound.AtomicCounterBuffers[index] = BufferBinding(b, offset, size) - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER: { - b := GetOrCreateBuffer(buffer) - ctx.Bound.ShaderStorageBuffer = b - ctx.Bound.ShaderStorageBuffers[index] = BufferBinding(b, offset, size) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBufferData.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBufferData.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBufferData.xhtml", Version.GLES32) -cmd void glBufferData(GLenum target, GLsizeiptr size, BufferDataPointer data, GLenum usage) { - b := GetBoundBufferOrError(target) - switch (usage) { - case GL_DYNAMIC_DRAW, GL_STATIC_DRAW, GL_STREAM_DRAW: { - // version 2.0 - } - @if(Version.GLES30) - case GL_DYNAMIC_COPY, GL_DYNAMIC_READ, GL_STATIC_COPY, GL_STATIC_READ, GL_STREAM_COPY, - GL_STREAM_READ: { - } - default: { - glErrorInvalidEnum(usage) - } - } - CheckSizeGE!GLsizeiptr(size, 0) - - b.Data = make!u8(size) - if (data != null) { - copy(b.Data, as!u8*(data)[0:size]) - } - b.Size = size - b.Usage = usage -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferSubData.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBufferSubData.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBufferSubData.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBufferSubData.xhtml", Version.GLES32) -cmd void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, BufferDataPointer data) { - b := GetBoundBufferOrError(target) - CheckGE!GLintptr(offset, 0) - CheckSizeGE!GLsizeiptr(size, 0) - CheckLE!GLsizeiptr((as!GLsizeiptr(offset) + size), b.Size) - copy(b.Data[offset:as!GLsizeiptr(offset) + size], as!u8*(data)[0:size]) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCopyBufferSubData.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCopyBufferSubData.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCopyBufferSubData.xhtml", Version.GLES32) -cmd void glCopyBufferSubData(GLenum readTarget, - GLenum writeTarget, - GLintptr readOffset, - GLintptr writeOffset, - GLsizeiptr size) { - CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) -} - -sub void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { - _ = GetBoundBufferOrError(readTarget) - _ = GetBoundBufferOrError(writeTarget) - _ = readOffset // TODO - _ = writeOffset // TODO - _ = size // TODO -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteBuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteBuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteBuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteBuffers.xhtml", Version.GLES32) -cmd void glDeleteBuffers(GLsizei count, const BufferId* buffers) { - CheckCountGE!GLsizei(count, 0) - b := buffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := b[i] - if id != 0 { - delete(ctx.Objects.Buffers, id) - delete(ctx.Objects.GeneratedNames.Buffers, id) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenBuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenBuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenBuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenBuffers.xhtml", Version.GLES32) -cmd void glGenBuffers(GLsizei count, BufferId* buffers) { - CheckCountGE!GLsizei(count, 0) - b := buffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!BufferId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Buffers[id] = true - b[i] = id - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetBufferParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetBufferParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetBufferParameter.xhtml", Version.GLES32) -cmd void glGetBufferParameteri64v(GLenum target, GLenum parameter, GLint64* value) { - GetBufferParameter!GLint64(target, parameter, value) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetBufferParameteriv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetBufferParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetBufferParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetBufferParameter.xhtml", Version.GLES32) -cmd void glGetBufferParameteriv(GLenum target, GLenum parameter, GLint* value) { - GetBufferParameter!GLint(target, parameter, value) -} - -sub void GetBufferParameter!T(GLenum target, GLenum parameter, T* value) { - b := GetBoundBufferOrError(target) - switch (parameter) { - @if(Version.GLES20) - case GL_BUFFER_SIZE: { - value[0] = as!T(b.Size) - } - @if(Version.GLES20) - case GL_BUFFER_USAGE: { - value[0] = as!T(b.Usage) - } - @if(Version.GLES30) - case GL_BUFFER_ACCESS_FLAGS: { - value[0] = as!T(b.AccessFlags) - } - @if(Version.GLES30) - case GL_BUFFER_MAPPED: { - value[0] = as!T(b.Mapped) - } - @if(Version.GLES30) - case GL_BUFFER_MAP_LENGTH: { - value[0] = as!T(b.MapLength) - } - @if(Version.GLES30) - case GL_BUFFER_MAP_OFFSET: { - value[0] = as!T(b.MapOffset) - } - default: { - glErrorInvalidEnum(parameter) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetBufferPointerv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetBufferPointerv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetBufferPointerv.xhtml", Version.GLES32) -cmd void glGetBufferPointerv(GLenum target, GLenum pname, void** params) { - GetBufferPointerv(target, pname, params) -} - -sub void GetBufferPointerv(GLenum target, GLenum pname, void** params) { - switch (target) { - case GL_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_ELEMENT_ARRAY_BUFFER, - GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, - GL_UNIFORM_BUFFER: { - // version 3.0 - } - @if(Version.GLES32) - case GL_ATOMIC_COUNTER_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_DRAW_INDIRECT_BUFFER, - GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER: { - } - default: { - glErrorInvalidEnum(target) - } - } - switch (pname) { - case GL_BUFFER_MAP_POINTER: { - // version 3.0 - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - - write(params[0:1]) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsBuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsBuffer.xhtml", Version.GLES32) -cmd GLboolean glIsBuffer(BufferId buffer) { - - ctx := GetContext() - return toGLboolean(buffer in ctx.Objects.Buffers) -} - -// This command only exits in desktop GL - but we need the signature in compat. -cmd void* glMapBuffer(GLenum target, GLenum access) { - ptr := ? - MapBuffer(target, access, as!u8*(ptr)) - return ptr -} - -sub void MapBuffer(GLenum target, GLenum access, u8* ptr) { - b := GetBoundBufferOrError(target) - accessBits := switch (access) { - case GL_READ_ONLY: GL_MAP_READ_BIT - case GL_WRITE_ONLY: GL_MAP_WRITE_BIT - case GL_READ_WRITE: GL_MAP_READ_BIT | GL_MAP_WRITE_BIT - } - MapBufferRange(target, 0 /* offset */, b.Size, accessBits, as!u8*(ptr)) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glMapBufferRange.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glMapBufferRange.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glMapBufferRange.xhtml", Version.GLES32) -cmd void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { - ptr := ? - MapBufferRange(target, offset, length, access, as!u8*(ptr)) - return ptr -} - -sub void MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr size, GLbitfield access, u8* ptr) { - b := GetBoundBufferOrError(target) - CheckGE!GLintptr(offset, 0) - CheckSizeGE!GLsizeiptr(size, 0) - CheckLE!GLsizeiptr((as!GLsizeiptr(offset) + size), b.Size) - supportsBits(access, GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_READ_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_WRITE_BIT) - if b.Mapped == GL_TRUE { glErrorInvalidOperation() } - - b.Mapped = GL_TRUE - b.AccessFlags = access - b.MapPointer = ptr - b.MapOffset = offset - b.MapLength = size - mapMemory(ptr[0:size]) - - if GL_MAP_READ_BIT in access { - write(ptr[0:size]) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glMapBufferRange.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glMapBufferRange.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glMapBufferRange.xhtml", Version.GLES32) -cmd GLboolean glUnmapBuffer(GLenum target) { - UnmapBuffer(target) - return ? -} - -sub void UnmapBuffer(GLenum target) { - b := GetBoundBufferOrError(target) - if b.Mapped == GL_FALSE { glErrorInvalidOperation() } - if (GL_MAP_WRITE_BIT in b.AccessFlags) && (!(GL_MAP_FLUSH_EXPLICIT_BIT in b.AccessFlags)) { - copyLength := as!GLintptr(b.MapLength) - copy(b.Data[b.MapOffset:b.MapOffset + copyLength], b.MapPointer[0:copyLength]) - } - unmapMemory(b.MapPointer[0:b.MapLength]) - b.Mapped = GL_FALSE - b.AccessFlags = as!GLbitfield(0) - b.MapPointer = null - b.MapOffset = 0 - b.MapLength = 0 -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFlushMappedBufferRange.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFlushMappedBufferRange.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFlushMappedBufferRange.xhtml", Version.GLES32) -cmd void glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) { - FlushMappedBufferRange(target, offset, length) -} - -sub void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr size) { - b := GetBoundBufferOrError(target) - if b.Mapped == GL_FALSE { glErrorInvalidOperation() } - if !(GL_MAP_FLUSH_EXPLICIT_BIT in b.AccessFlags) { glErrorInvalidOperation() } - CheckGE!GLintptr(offset, 0) - CheckSizeGE!GLsizeiptr(size, 0) - CheckLE!GLsizeiptr((as!GLsizeiptr(offset) + size), b.MapLength) - dstOffset := b.MapOffset + offset - copy(b.Data[dstOffset:dstOffset + as!GLintptr(size)], b.MapPointer[offset:offset + as!GLintptr(size)]) -} diff --git a/gapis/api/gles/api/constants.api b/gapis/api/gles/api/constants.api deleted file mode 100644 index f88b7f678d..0000000000 --- a/gapis/api/gles/api/constants.api +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Implementation dependent constants. -@internal -class Constants { - @unused string Vendor - @unused string Version - @unused string Renderer - map!(u32, string) Extensions - - // Constants defined in version 2.0.25 (November 2, 2010) - // SampleBuffers and Samples are omitted since they are not constants in later versions. - GLfloat[2] AliasedLineWidthRange - GLfloat[2] AliasedPointSizeRange - map!(u32, GLenum) CompressedTextureFormats - GLint MaxCombinedTextureImageUnits - GLint MaxCubeMapTextureSize - GLint MaxFragmentUniformVectors - GLint MaxRenderbufferSize - GLint MaxTextureImageUnits - GLint MaxTextureSize - GLint MaxVaryingVectors - GLint MaxVertexAttribs - GLint MaxVertexTextureImageUnits - GLint MaxVertexUniformVectors - GLint[2] MaxViewportDims - map!(u32, GLenum) ShaderBinaryFormats - GLboolean ShaderCompiler - @unused string ShadingLanguageVersion - GLint SubpixelBits - ShaderPrecisionFormat VertexShaderPrecisionFormat - ShaderPrecisionFormat FragmentShaderPrecisionFormat - - // Constants defined in version 3.0.4 (August 27, 2014) - GLint MajorVersion - GLint Max3dTextureSize - GLint MaxArrayTextureLayers - GLint MaxColorAttachments - GLint64 MaxCombinedFragmentUniformComponents - GLint MaxCombinedUniformBlocks - GLint64 MaxCombinedVertexUniformComponents - GLint MaxDrawBuffers - GLint MaxElementsIndices - GLint MaxElementsVertices - GLint64 MaxElementIndex - GLint MaxFragmentInputComponents - GLint MaxFragmentUniformBlocks - GLint MaxFragmentUniformComponents - GLint MaxProgramTexelOffset - GLint64 MaxServerWaitTimeout - GLfloat MaxTextureLodBias - GLint MaxTransformFeedbackInterleavedComponents - GLint MaxTransformFeedbackSeparateAttribs - GLint MaxTransformFeedbackSeparateComponents - GLint64 MaxUniformBlockSize - GLint MaxUniformBufferBindings - GLint MaxVaryingComponents - GLint MaxVertexOutputComponents - GLint MaxVertexUniformBlocks - GLint MaxVertexUniformComponents - GLint MinorVersion - GLint MinProgramTexelOffset - map!(u32, GLenum) ProgramBinaryFormats - GLint UniformBufferOffsetAlignment - - // Constants defined in version 3.1 (April 29, 2015) - GLint MaxAtomicCounterBufferBindings - GLint MaxAtomicCounterBufferSize - GLint MaxColorTextureSamples - GLint MaxCombinedAtomicCounters - GLint MaxCombinedAtomicCounterBuffers - GLint MaxCombinedComputeUniformComponents - GLint MaxCombinedImageUniforms - GLint MaxCombinedShaderOutputResources - GLint MaxCombinedShaderStorageBlocks - GLint MaxComputeAtomicCounters - GLint MaxComputeAtomicCounterBuffers - GLint MaxComputeImageUniforms - GLint MaxComputeShaderStorageBlocks - GLint MaxComputeSharedMemorySize - GLint MaxComputeTextureImageUnits - GLint MaxComputeUniformBlocks - GLint MaxComputeUniformComponents - GLint[3] MaxComputeWorkGroupCount - GLint MaxComputeWorkGroupInvocations - GLint[3] MaxComputeWorkGroupSize - GLint MaxDepthTextureSamples - GLint MaxFragmentAtomicCounters - GLint MaxFragmentAtomicCounterBuffers - GLint MaxFragmentImageUniforms - GLint MaxFragmentShaderStorageBlocks - GLint MaxFramebufferHeight - GLint MaxFramebufferSamples - GLint MaxFramebufferWidth - GLint MaxImageUnits - GLint MaxIntegerSamples - GLint MaxProgramTextureGatherOffset - GLint MaxSampleMaskWords - GLint64 MaxShaderStorageBlockSize - GLint MaxShaderStorageBufferBindings - GLint MaxUniformLocations - GLint MaxVertexAtomicCounters - GLint MaxVertexAtomicCounterBuffers - GLint MaxVertexAttribBindings - GLint MaxVertexAttribRelativeOffset - GLint MaxVertexAttribStride - GLint MaxVertexImageUniforms - GLint MaxVertexShaderStorageBlocks - GLint MinProgramTextureGatherOffset - GLint ShaderStorageBufferOffsetAlignment - - // Constants defined in version 3.2 (June 15, 2016) - GLint ContextFlags - GLint FragmentInterpolationOffsetBits - GLenum LayerProvokingVertex - GLint MaxCombinedGeometryUniformComponents - GLint MaxCombinedTessControlUniformComponents - GLint MaxCombinedTessEvaluationUniformComponents - GLint MaxDebugGroupStackDepth - GLint MaxDebugLoggedMessages - GLint MaxDebugMessageLength - GLfloat MaxFragmentInterpolationOffset - GLint MaxFramebufferLayers - GLint MaxGeometryAtomicCounters - GLint MaxGeometryAtomicCounterBuffers - GLint MaxGeometryImageUniforms - GLint MaxGeometryInputComponents - GLint MaxGeometryOutputComponents - GLint MaxGeometryOutputVertices - GLint MaxGeometryShaderInvocations - GLint MaxGeometryShaderStorageBlocks - GLint MaxGeometryTextureImageUnits - GLint MaxGeometryTotalOutputComponents - GLint MaxGeometryUniformBlocks - GLint MaxGeometryUniformComponents - GLint MaxLabelLength - GLint MaxPatchVertices - GLint MaxTessControlAtomicCounters - GLint MaxTessControlAtomicCounterBuffers - GLint MaxTessControlImageUniforms - GLint MaxTessControlInputComponents - GLint MaxTessControlOutputComponents - GLint MaxTessControlShaderStorageBlocks - GLint MaxTessControlTextureImageUnits - GLint MaxTessControlTotalOutputComponents - GLint MaxTessControlUniformBlocks - GLint MaxTessControlUniformComponents - GLint MaxTessEvaluationAtomicCounters - GLint MaxTessEvaluationAtomicCounterBuffers - GLint MaxTessEvaluationImageUniforms - GLint MaxTessEvaluationInputComponents - GLint MaxTessEvaluationOutputComponents - GLint MaxTessEvaluationShaderStorageBlocks - GLint MaxTessEvaluationTextureImageUnits - GLint MaxTessEvaluationUniformBlocks - GLint MaxTessEvaluationUniformComponents - GLint MaxTessGenLevel - GLint MaxTessPatchComponents - GLint MaxTextureBufferSize - GLfloat MinFragmentInterpolationOffset - GLfloat MultisampleLineWidthGranularity - GLfloat[2] MultisampleLineWidthRange - GLboolean PrimitiveRestartForPatchesSupported - GLint TextureBufferOffsetAlignment - GLint ResetNotificationStrategy - - // Constants defined in extensions - GLfloat MaxTextureMaxAnisotropyExt - GLint MaxViewsExt -} - -@internal -class ShaderPrecisionFormat { - @unused PrecisionFormat LowFloat - @unused PrecisionFormat MediumFloat - @unused PrecisionFormat HighFloat - @unused PrecisionFormat LowInt - @unused PrecisionFormat MediumInt - @unused PrecisionFormat HighInt -} - -@internal -class PrecisionFormat { - @unused GLint MinRange - @unused GLint MaxRange - @unused GLint Precision -} diff --git a/gapis/api/gles/api/debug.api b/gapis/api/gles/api/debug.api deleted file mode 100644 index 095cd9f531..0000000000 --- a/gapis/api/gles/api/debug.api +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class DebugState { - // Table 21.53: Debug Output State - @unused GLDEBUGPROC CallbackFunction - @unused const void* CallbackUserParam - // GLuint LoggedMessages = 0 - // GLuint NextLoggedMessageLength = 0 - GLboolean OutputSynchronous = GL_FALSE - // GLuint GroupStackDepth = 1 - GLboolean Output // TODO: init -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDebugMessageCallback.xhtml", Version.GLES32) -cmd void glDebugMessageCallback(GLDEBUGPROC callback, const void* userParam) { - DebugMessageCallback(callback, userParam) -} - -sub void DebugMessageCallback(GLDEBUGPROC callback, const void* userParam) { - ctx := GetContext() - ctx.Other.Debug.CallbackFunction = callback - ctx.Other.Debug.CallbackUserParam = userParam -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDebugMessageControl.xhtml", Version.GLES32) -cmd void glDebugMessageControl(GLenum source, - GLenum type, - GLenum severity, - GLsizei count, - const GLuint* ids, - GLboolean enabled) { - DebugMessageControl(source, type, severity, count, ids, enabled) -} - -sub void DebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled) { - switch (source) { - case GL_DEBUG_SOURCE_API, GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_SOURCE_OTHER, - GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_SOURCE_THIRD_PARTY, - GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DONT_CARE: { - // version 3.2 - } - default: { - glErrorInvalidEnum(source) - } - } - switch (type) { - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DEBUG_TYPE_ERROR, GL_DEBUG_TYPE_MARKER, - GL_DEBUG_TYPE_OTHER, GL_DEBUG_TYPE_PERFORMANCE, GL_DEBUG_TYPE_POP_GROUP, - GL_DEBUG_TYPE_PORTABILITY, GL_DEBUG_TYPE_PUSH_GROUP, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR, - GL_DONT_CARE: { - // version 3.2 - } - default: { - glErrorInvalidEnum(type) - } - } - switch (severity) { - case GL_DEBUG_SEVERITY_HIGH, GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_MEDIUM, - GL_DEBUG_SEVERITY_NOTIFICATION, GL_DONT_CARE: { - // version 3.2 - } - default: { - glErrorInvalidEnum(severity) - } - } - _ = enabled // TODO - read(ids[0:count]) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDebugMessageInsert.xhtml", Version.GLES32) -cmd void glDebugMessageInsert(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message) { - DebugMessageInsert(source, type, id, severity, length, message) -} - -sub void DebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message) { - switch (source) { - case GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_SOURCE_THIRD_PARTY: { - // version 3.2 - } - default: { - glErrorInvalidEnum(source) - } - } - switch (type) { - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DEBUG_TYPE_ERROR, GL_DEBUG_TYPE_MARKER, - GL_DEBUG_TYPE_OTHER, GL_DEBUG_TYPE_PERFORMANCE, GL_DEBUG_TYPE_POP_GROUP, - GL_DEBUG_TYPE_PORTABILITY, GL_DEBUG_TYPE_PUSH_GROUP, GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: { - // version 3.2 - } - default: { - glErrorInvalidEnum(type) - } - } - switch (severity) { - case GL_DEBUG_SEVERITY_HIGH, GL_DEBUG_SEVERITY_LOW, GL_DEBUG_SEVERITY_MEDIUM, - GL_DEBUG_SEVERITY_NOTIFICATION: { - // version 3.2 - } - default: { - glErrorInvalidEnum(severity) - } - } - _ = id // TODO - _ = readString(length, message, false) -} - -sub void GetDebugMessageLog(GLuint count, - GLsizei bufSize, - GLenum* sources, - GLenum* types, - GLuint* ids, - GLenum* severities, - GLsizei* lengths, - GLchar* messageLog, - GLuint gotCount) { - _ = count // TODO - if sources != null { - write(sources[0:gotCount]) - } - if types != null { - write(types[0:gotCount]) - } - if ids != null { - write(ids[0:gotCount]) - } - if severities != null { - write(severities[0:gotCount]) - } - if lengths != null { - write(lengths[0:gotCount]) - } - if gotCount > 0 { - write(messageLog[0:bufSize]) // TODO: "sum of lengths" bytes. - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetDebugMessageLog.xhtml", Version.GLES32) -cmd GLuint glGetDebugMessageLog(GLuint count, - GLsizei bufSize, - GLenum* sources, - GLenum* types, - GLuint* ids, - GLenum* severities, - GLsizei* lengths, - GLchar* messageLog) { - l := ? - GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog, l) - return l -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetObjectLabel.xhtml", Version.GLES32) -cmd void glGetObjectLabel(GLenum identifier, - GLuint name, - GLsizei bufSize, - GLsizei* length, - GLchar* label) { - GetObjectLabel(identifier, name, bufSize, length, label) -} - -sub void GetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label) { - switch (identifier) { - case GL_BUFFER, GL_FRAMEBUFFER, GL_PROGRAM, GL_PROGRAM_PIPELINE, GL_QUERY, GL_RENDERBUFFER, - GL_SAMPLER, GL_SHADER, GL_TEXTURE, GL_TRANSFORM_FEEDBACK, GL_VERTEX_ARRAY: { - // version 3.2 - } - default: { - glErrorInvalidEnum(identifier) - } - } - _ = name // TODO - writeString(bufSize, length, label) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetObjectPtrLabel.xhtml", Version.GLES32) -cmd void glGetObjectPtrLabel(const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) { - GetObjectPtrLabel(ptr, bufSize, length, label) -} - -sub void GetObjectPtrLabel(const void* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) { - _ = ptr // TODO - writeString(bufSize, length, label) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetPointerv.xhtml", Version.GLES32) -cmd void glGetPointerv(GLenum pname, void** params) { - GetPointerv(pname, params) -} - -sub void GetPointerv(GLenum pname, void** params) { - switch (pname) { - case GL_DEBUG_CALLBACK_FUNCTION, GL_DEBUG_CALLBACK_USER_PARAM: { - // version 3.2 - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - write(params[0:1]) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glObjectLabel.xhtml", Version.GLES32) -cmd void glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) { - ObjectLabel(identifier, name, length, label) -} - -sub void ObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) { - // This is incorrect, fudging for a bug in Unity which has been fixed but not - // rolled out. - // See https://github.com/google/gapid/issues/459 for reference. - // TODO: Consider removing once the fixed version is mainstream. - consider_zero_length_nt := true - - str := readString(length, label, consider_zero_length_nt) - - ctx := GetContext() - switch (identifier) { - case GL_TEXTURE: { - if !(as!TextureId(name) in ctx.Objects.Textures) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Textures[as!TextureId(name)].Label = str - } - case GL_FRAMEBUFFER: { - if !(as!FramebufferId(name) in ctx.Objects.Framebuffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Framebuffers[as!FramebufferId(name)].Label = str - } - case GL_RENDERBUFFER: { - if !(as!RenderbufferId(name) in ctx.Objects.Renderbuffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Renderbuffers[as!RenderbufferId(name)].Label = str - } - case GL_BUFFER: { - if !(as!BufferId(name) in ctx.Objects.Buffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Buffers[as!BufferId(name)].Label = str - } - case GL_SHADER: { - if !(as!ShaderId(name) in ctx.Objects.Shaders) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Shaders[as!ShaderId(name)].Label = str - } - case GL_PROGRAM: { - if !(as!ProgramId(name) in ctx.Objects.Programs) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Programs[as!ProgramId(name)].Label = str - } - case GL_VERTEX_ARRAY: { - if !(as!VertexArrayId(name) in ctx.Objects.VertexArrays) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.VertexArrays[as!VertexArrayId(name)].Label = str - } - case GL_QUERY: { - if !(as!QueryId(name) in ctx.Objects.Queries) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Queries[as!QueryId(name)].Label = str - } - case GL_SAMPLER: { - if !(as!SamplerId(name) in ctx.Objects.Samplers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Samplers[as!SamplerId(name)].Label = str - } - case GL_TRANSFORM_FEEDBACK: { - if !(as!TransformFeedbackId(name) in ctx.Objects.TransformFeedbacks) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.TransformFeedbacks[as!TransformFeedbackId(name)].Label = str - } - case GL_PROGRAM_PIPELINE: { - if !(as!PipelineId(name) in ctx.Objects.Pipelines) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(name) - } - ctx.Objects.Pipelines[as!PipelineId(name)].Label = str - } - default: { - glErrorInvalidEnum(identifier) - } - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glObjectPtrLabel.xhtml", Version.GLES32) -cmd void glObjectPtrLabel(const void* ptr, GLsizei length, const GLchar* label) { - ObjectPtrLabel(ptr, length, label) -} - -sub void ObjectPtrLabel(const void* ptr, GLsizei length, const GLchar* label) { - ctx := GetContext() - sync := ctx.Objects.SyncObjects[as!GLsync(ptr)] - if sync == null { glErrorInvalidValue!GLsync(as!GLsync(ptr)) } - sync.Label = readString(length, label, false) -} - -@if(Version.GLES32) -@pop_user_marker -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPopDebugGroup.xhtml", Version.GLES32) -cmd void glPopDebugGroup() { - PopDebugGroup() -} - -sub void PopDebugGroup() { - // TODO -} - -@if(Version.GLES32) -@push_user_marker -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPushDebugGroup.xhtml", Version.GLES32) -cmd void glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message) { - PushDebugGroup(source, id, length, message) -} - -sub void PushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message) { - switch (source) { - case GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_SOURCE_THIRD_PARTY: { - // version 3.2 - } - default: { - glErrorInvalidEnum(source) - } - } - - // This is incorrect, fudging for a bug in Unity which has been fixed but not - // rolled out. - // See https://github.com/google/gapid/issues/459 for reference. - // TODO: Consider removing once the fixed version is mainstream. - consider_zero_length_nt := true - - _ = id // TODO - _ = readString(length, message, consider_zero_length_nt) -} diff --git a/gapis/api/gles/api/draw_commands.api b/gapis/api/gles/api/draw_commands.api deleted file mode 100644 index cb646ca0f2..0000000000 --- a/gapis/api/gles/api/draw_commands.api +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// TODO: What if the index buffer is written by shader? - -sub void checkPrimitiveType(GLenum draw_mode) { - switch (draw_mode) { - case GL_LINES, GL_LINE_LOOP, GL_LINE_STRIP, GL_POINTS, GL_TRIANGLES, GL_TRIANGLE_FAN, - GL_TRIANGLE_STRIP: { - // version 2.0 - } - @if(Version.GLES32) - case GL_LINES_ADJACENCY, GL_LINE_STRIP_ADJACENCY, GL_PATCHES, GL_TRIANGLES_ADJACENCY, - GL_TRIANGLE_STRIP_ADJACENCY: { - } - default: { - glErrorInvalidEnum(draw_mode) - } - } -} - -sub void checkIndicesType(GLenum indices_type) { - switch (indices_type) { - case GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT: { - // version 2.0 - } - @if(Version.GLES30) - case GL_UNSIGNED_INT: { - } - default: { - glErrorInvalidEnum(indices_type) - } - } -} - -sub bool isDrawCall() { - return !isTransformFeedback() -} - -sub bool isTransformFeedback() { - ctx := GetContext() - return ctx.Bound.TransformFeedback.Active == GL_TRUE -} - -@if(Version.GLES10) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawArrays.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawArrays.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawArrays.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawArrays.xhtml", Version.GLES32) -cmd void glDrawArrays(GLenum draw_mode, GLint first_index, GLsizei indices_count) { - checkPrimitiveType(draw_mode) - CheckGE!GLint(first_index, 0) // "Recommended behaviour" - CheckCountGE!GLsizei(indices_count, 0) - ctx := GetContext() - ReadVertexArrays(ctx, as!u32(first_index), as!u32(indices_count), 1) - WriteGPUFramebufferData(ctx) - DrawCommandDependencies(ctx, as!u32(indices_count), 1) -} - -// See GLES 3.2 spec '10.5 Drawing Commands Using Vertex Arrays' -class DrawArraysIndirectCommand { - u32 count - u32 instanceCount - u32 first - u32 reservedMustBeZero -} - -@if(Version.GLES31) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawArraysIndirect.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawArraysIndirect.xhtml", Version.GLES32) -cmd void glDrawArraysIndirect(GLenum draw_mode, const void* indirect) { - CheckNonDefaultVertexArrayBound() - ctx := GetContext() - if ctx.Bound.DrawIndirectBuffer == null { glErrorInvalidOperation() } - // TODO: INVALID_OPERATION error if the command would source data beyond the end of the buffer object. - // TODO: CheckEQ(as!u64(indirect) % 4, 0) - command := as!DrawArraysIndirectCommand*(indirect)[0] - DrawArraysInstanced(draw_mode, as!GLint(command.first), as!GLsizei(command.count), as!GLsizei(command.instanceCount)) -} - -@if(Version.GLES30) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawArraysInstanced.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawArraysInstanced.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawArraysInstanced.xhtml", Version.GLES32) -cmd void glDrawArraysInstanced(GLenum draw_mode, GLint first_index, GLsizei indices_count, GLsizei instance_count) { - DrawArraysInstanced(draw_mode, first_index, indices_count, instance_count) -} - -sub void DrawArraysInstanced(GLenum draw_mode, GLint first_index, GLsizei indices_count, GLsizei instance_count) { - checkPrimitiveType(draw_mode) - CheckGE!GLint(first_index, 0) // "Recommended behaviour" - CheckCountGE!GLsizei(indices_count, 0) - CheckCountGE!GLsizei(instance_count, 0) - ctx := GetContext() - ReadVertexArrays(ctx, as!u32(first_index), as!u32(indices_count), as!u32(instance_count)) - WriteGPUFramebufferData(ctx) - DrawCommandDependencies(ctx, as!u32(indices_count), as!u32(instance_count)) -} - -sub void DrawElements(ref!Context ctx, - GLenum draw_mode, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices, - GLsizei instance_count, - GLint base_vertex) { - checkPrimitiveType(draw_mode) - CheckCountGE!GLsizei(indices_count, 0) // SPEC: missing in pdf - checkIndicesType(indices_type) - CheckCountGE!GLsizei(instance_count, 0) // SPEC: missing in pdf - if indices_count > 0 { - count := as!u32(indices_count) - index_buffer := ctx.Bound.VertexArray.ElementArrayBuffer - if (index_buffer != null) { - // Element array buffer bound - indices is an offset on the buffer. - index_data := index_buffer.Data - offset := as!u64(indices) - - // Read the vertices - index_size := IndexSize(indices_type) - index_start := min!u64(offset, len(index_data)) // Clamp offset - index_end := min!u64(offset+as!u64(index_size*count), len(index_data)) // Clamp count - limits := IndexLimits(index_data[index_start:index_end], as!s32(index_size)) - ReadVertexArrays(ctx, limits.first + as!u32(base_vertex), limits.count, as!u32(instance_count)) - - // No need to read the indices - they're already in a GPU-side buffer. - } else { - // No element array buffer bound - indices is a pointer. - index_data := as!u8*(indices) - - // Read the vertices - index_size := IndexSize(indices_type) - limits := IndexLimits(index_data[0:index_size*count], as!s32(index_size)) - ReadVertexArrays(ctx, limits.first + as!u32(base_vertex), limits.count, as!u32(instance_count)) - - // Read the indices - read(index_data[0:count * IndexSize(indices_type)]) - } - } - WriteGPUFramebufferData(ctx) - DrawCommandDependencies(ctx, as!u32(indices_count), as!u32(instance_count)) -} - -@if(Version.GLES10) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDrawElements.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawElements.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawElements.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawElements.xhtml", Version.GLES32) -cmd void glDrawElements(GLenum draw_mode, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices) { - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, 1, 0) -} - -@if(Version.GLES32) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawElementsBaseVertex.xhtml", Version.GLES32) -cmd void glDrawElementsBaseVertex(GLenum draw_mode, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices, - GLint base_vertex) { - DrawElementsBaseVertex(draw_mode, indices_count, indices_type, indices, base_vertex) -} - -sub void DrawElementsBaseVertex(GLenum draw_mode, GLsizei indices_count, GLenum indices_type, IndicesPointer indices, GLint base_vertex) { - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, 1, base_vertex) -} - -// See GLES 3.2 spec '10.5 Drawing Commands Using Vertex Arrays' -class DrawElementsIndirectCommand { - u32 count - u32 instanceCount - u32 firstIndex - s32 baseVertex - u32 reservedMustBeZero -} - -@if(Version.GLES31) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawElementsIndirect.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawElementsIndirect.xhtml", Version.GLES32) -cmd void glDrawElementsIndirect(GLenum draw_mode, GLenum indices_type, const void* indirect) { - checkIndicesType(indices_type) - CheckNonDefaultVertexArrayBound() - // TODO: Error if enabled array is not bound or is mapped. - ctx := GetContext() - if ctx.Bound.DrawIndirectBuffer == null { glErrorInvalidOperation() } - // TODO: INVALID_OPERATION error if the command would source data beyond the end of the buffer object. - // TODO: CheckEQ(as!u64(indirect) % 4, 0) - - command := as!DrawElementsIndirectCommand*(indirect)[0] - // TODO: The following is the actual sepc implementation, yet it does not compile because of an seemly impossible cast. - // - // size_of_type := switch(indices_type) { - // case GL_UNSIGNED_BYTE: { 1 } - // case GL_UNSIGNED_SHORT: { 2 } - // case GL_UNSIGNED_INT: { 4 } - // } - // - // ## The cast as!void*() below fails: - // DrawElementsInstancedBaseVertex(draw_mode, as!GLsizei(command.count), indices_type, as!void*(command.firstIndex * as!u32(size_of_type)), as!GLsizei(command.instanceCount), as!GLint(command.baseVertex)) - - // TODO: once the cast issue above is fixed, we should be able to get rid of these three calls: - checkPrimitiveType(draw_mode) - WriteGPUFramebufferData(ctx) - _ = command // Necessary to use 'command' here, because DrawCommandDependencies() is @spy_disabled - DrawCommandDependencies(ctx, command.count, command.instanceCount) -} - -@if(Version.GLES30) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawElementsInstanced.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawElementsInstanced.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawElementsInstanced.xhtml", Version.GLES32) -cmd void glDrawElementsInstanced(GLenum draw_mode, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices, - GLsizei instance_count) { - DrawElementsInstanced(draw_mode, indices_count, indices_type, indices, instance_count) -} - -sub void DrawElementsInstanced(GLenum draw_mode, GLsizei indices_count, GLenum indices_type, IndicesPointer indices, GLsizei instance_count) { - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, instance_count, 0) -} - -@if(Version.GLES32) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawElementsInstancedBaseVertex.xhtml", Version.GLES32) -cmd void glDrawElementsInstancedBaseVertex(GLenum draw_mode, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices, - GLsizei instance_count, - GLint base_vertex) { - DrawElementsInstancedBaseVertex(draw_mode, indices_count, indices_type, indices, instance_count, base_vertex) -} - -sub void DrawElementsInstancedBaseVertex(GLenum draw_mode, GLsizei indices_count, GLenum indices_type, IndicesPointer indices, GLsizei instance_count, GLint base_vertex) { - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, instance_count, base_vertex) -} - -@if(Version.GLES30) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawRangeElements.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawRangeElements.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawRangeElements.xhtml", Version.GLES32) -cmd void glDrawRangeElements(GLenum draw_mode, - GLuint start, - GLuint end, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices) { - CheckGE!GLuint(end, start) - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, 1, 0) -} - -@if(Version.GLES32) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawRangeElementsBaseVertex.xhtml", Version.GLES32) -cmd void glDrawRangeElementsBaseVertex(GLenum draw_mode, - GLuint start, - GLuint end, - GLsizei indices_count, - GLenum indices_type, - IndicesPointer indices, - GLint base_vertex) { - DrawRangeElementsBaseVertex(draw_mode, start, end, indices_count, indices_type, indices, base_vertex) -} - -sub void DrawRangeElementsBaseVertex(GLenum draw_mode, GLuint start, GLuint end, GLsizei indices_count, GLenum indices_type, IndicesPointer indices, GLint base_vertex) { - CheckGE!GLuint(end, start) - ctx := GetContext() - DrawElements(ctx, draw_mode, indices_count, indices_type, indices, 1, base_vertex) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPatchParameteri.xhtml", Version.GLES32) -cmd void glPatchParameteri(GLenum pname, GLint value) { - PatchParameteri(pname, value) -} - -// TODO: Move to misc? -sub void PatchParameteri(GLenum pname, GLint value) { - if pname != GL_PATCH_VERTICES { glErrorInvalidEnum(pname) } - ctx := GetContext() - ctx.Vertex.PatchVertices = value -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPrimitiveBoundingBox.xhtml", Version.GLES32) -cmd void glPrimitiveBoundingBox(GLfloat minX, - GLfloat minY, - GLfloat minZ, - GLfloat minW, - GLfloat maxX, - GLfloat maxY, - GLfloat maxZ, - GLfloat maxW) { - PrimitiveBoundingBox(minX, minY, minZ, minW, maxX, maxY, maxZ, maxW) -} - -// TODO: Move to rasterization? -sub void PrimitiveBoundingBox(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW) { - ctx := GetContext() - ctx.Rasterization.PrimitiveBoundingBox.Min = Vec4f(minX, minY, minZ, minW) - ctx.Rasterization.PrimitiveBoundingBox.Max = Vec4f(maxX, maxY, maxZ, maxW) -} - -// WriteGPUFramebufferAttachment updates the data of the given FramebufferAttachment. -sub void WriteGPUFramebufferAttachment(FramebufferAttachment a) { - numViews := a.NumViews - for view in (0 .. numViews) { - layer := a.TextureLayer + as!GLint(view) - img := GetTextureImage(a.Texture, a.TextureLevel, layer) - if img != null { - if img.Data == null { - img.Data = ReadGPUTextureData(a.Texture, a.TextureLevel, layer) - } else { - copy(img.Data, ReadGPUTextureData(a.Texture, a.TextureLevel, layer)) - } - } - } -} - -// WriteGPUFramebufferData updates the data of currently bound framebuffer textures. -sub void WriteGPUFramebufferData(ref!Context ctx) { - fb := ctx.Bound.DrawFramebuffer - for _, _, a in fb.ColorAttachments { - WriteGPUFramebufferAttachment(a) - } - WriteGPUFramebufferAttachment(fb.DepthAttachment) - WriteGPUFramebufferAttachment(fb.StencilAttachment) -} - -// ReadGPUTextureData is used to read the texture updated by the GPU. -// This is typically done to read the result of a render-to-texture. -@internal -extern u8[] ReadGPUTextureData(ref!Texture texture, GLint level, GLint layer) - -////////////////// -// Dependencies // -////////////////// - -// ReadFramebufferAttachment creates a read on this FramebufferAttachment. -@spy_disabled -sub void ReadFramebufferAttachment(FramebufferAttachment a) { - switch (a.Type) { - case GL_FRAMEBUFFER_DEFAULT, GL_RENDERBUFFER: { - read(a.Renderbuffer.Image.Data) - } - case GL_TEXTURE: { - read(a.Texture.Image.Data) - } - case GL_NONE: { - // nothing to do - } - } -} - -// WriteFramebufferAttachment creates a write on this FramebufferAttachment. -@spy_disabled -sub void WriteFramebufferAttachment(FramebufferAttachment a) { - switch (a.Type) { - case GL_FRAMEBUFFER_DEFAULT, GL_RENDERBUFFER: { - write(a.Renderbuffer.Image.Data) - } - case GL_TEXTURE: { - write(a.Texture.Image.Data) - } - case GL_NONE: { - // nothing to do - } - } -} - -// DependencyReadTexture read all relevant fields of texture to create dependencies -@spy_disabled -sub void DependencyReadTexture(ref!Texture texture) { - // TODO(hevrard): Check minlod and maxlod - for _, idx, level in texture.Levels { - if (texture.BaseLevel <= idx) && (idx <= texture.MaxLevel) { - for _, _, image in level.Layers { - read(image.Data) - } - } - } - - // Sampling may be affected by all these parameters - _ = texture.SwizzleR - _ = texture.SwizzleG - _ = texture.SwizzleB - _ = texture.SwizzleA - _ = texture.BorderColor - _ = texture.BorderColorI - _ = texture.MinFilter - _ = texture.MagFilter - _ = texture.WrapS - _ = texture.WrapT - _ = texture.WrapR - _ = texture.MinLod - _ = texture.MaxLod - _ = texture.DepthStencilTextureMode - _ = texture.CompareMode - _ = texture.CompareFunc - _ = texture.MaxAnisotropy - _ = texture.DecodeSRGB -} - -// DrawCommandDependencies creates relevant dependencies of draw commands. -@spy_disabled -sub void DrawCommandDependencies(ref!Context ctx, u32 index_count, u32 instance_count) { - if (index_count > 0) && (instance_count > 0) { - read_fb := ctx.Bound.ReadFramebuffer - draw_fb := ctx.Bound.DrawFramebuffer - - _ = ctx.Rasterization.Viewport - - if ctx.Pixel.Stencil.Test == GL_TRUE { - ReadFramebufferAttachment(read_fb.StencilAttachment) - } - - if ctx.Pixel.Depth.Test == GL_TRUE { - ReadFramebufferAttachment(read_fb.DepthAttachment) - } - - for i in (0 .. ctx.Constants.MaxDrawBuffers) { - if draw_fb.DrawBuffer[i] != GL_NONE { - blendState := ctx.Pixel.Blend[as!DrawBufferIndex(i)] - if blendState.Enabled == GL_TRUE { - _ = blendState.SrcRgb - _ = blendState.SrcAlpha - _ = blendState.DstRgb - _ = blendState.DstAlpha - _ = blendState.EquationRgb - _ = blendState.EquationAlpha - } - } - } - - if ctx.Bound.Program != null { - for _, _, u in ctx.Bound.Program.UniformLocations { - // The program execution reads uniform values - read(u.Values) - - // Sampler uniform refers to a texture - texture_target := GetTextureTargetFromSamplerType(u.Type) - if texture_target != GL_NONE { - texture_unit := ctx.Objects.TextureUnits[as!TextureUnitId(u.Value[0])] - if texture_unit != null { - DependencyReadTexture(GetBoundTextureForUnit(texture_unit, texture_target)) - } - } - } - } - - // Vertex input - if !IsDefaultVertexArrayBound() { - // Read host-side vertex input data. glDraw*() typically calls ReadVertexArrays() which - // reads client-side vertex input data, the only necessary reads at capture time. - // Here the reads for host-side vertex input is done to create dependencies. - arrayBuffer := ctx.Bound.ArrayBuffer - read(arrayBuffer.Data) - for _, _, a in ctx.Bound.VertexArray.VertexAttributeArrays { - if a.Enabled == GL_TRUE { - _ = a.Size - _ = a.Stride - _ = a.Type - _ = a.Normalized - _ = a.Integer - _ = a.Pointer - _ = a.RelativeOffset - _ = a.Binding.Id - _ = a.Binding.Buffer - _ = a.Binding.Offset - _ = a.Binding.Stride - _ = a.Binding.Divisor - } - } - } - - for _, _, a in draw_fb.ColorAttachments { - ReadFramebufferAttachment(a) - WriteFramebufferAttachment(a) - } - - SharedDrawClearCommandDependencies(ctx) - } -} - -// SharedDrawClearCommandDependencies creates relevant dependencies which are shared between draw and clear commands. -@spy_disabled -sub void SharedDrawClearCommandDependencies(ref!Context ctx) { - scissorState := ctx.Pixel.Scissor - if scissorState.Test == GL_TRUE { - _ = scissorState.Box.X - _ = scissorState.Box.Y - _ = scissorState.Box.Width - _ = scissorState.Box.Height - } -} diff --git a/gapis/api/gles/api/egl.api b/gapis/api/gles/api/egl.api deleted file mode 100644 index c33a38010c..0000000000 --- a/gapis/api/gles/api/egl.api +++ /dev/null @@ -1,503 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -type int EGLBoolean -type void* EGLClientBuffer -type void* EGLConfig -type void* EGLContext -type void* EGLDisplay -@replay_remap @replay_custom_value type void* EGLImageKHR -type s32 EGLint -type int EGLNativeDisplayType -type void* EGLNativePixmapType -type void* EGLNativeWindowType -type void* EGLSurface -type void* EGLSyncKHR -type u64 EGLTimeKHR - -sub EGLint[] CloneAttribList(const EGLint* attrib_list) { - // TODO: Replace with proper loop control flow - length := make!s32(1) - length[0] = 0 - if (attrib_list != null) { - done := make!bool(1) - done[0] = false - for i in (0 .. 256) { - if !(done[0]) { - pair := attrib_list[i * 2:(i * 2) + 2] - if as!EGLenum(pair[0]) == EGL_NONE { - done[0] = true - length[0] = (i * 2) + 1 - } - } - } - } - return clone(attrib_list[0:length[0]]) -} - -sub GLenum EGLSizedFormat2GLSizedFormat(AndroidGraphicsBufferFormat eglSizedFormat) { - return switch eglSizedFormat { - case HAL_PIXEL_FORMAT_RGBA_8888: GL_RGBA8 - case HAL_PIXEL_FORMAT_RGBX_8888: GL_RGB8 // Does not have a precise match - case HAL_PIXEL_FORMAT_RGB_888: GL_RGB8 - case HAL_PIXEL_FORMAT_RGB_565: GL_RGB565 - case HAL_PIXEL_FORMAT_BGRA_8888: GL_BGRA8_EXT - case HAL_PIXEL_FORMAT_RGBA_5551: GL_RGB5_A1 - case HAL_PIXEL_FORMAT_RGBA_4444: GL_RGB4 - case HAL_PIXEL_FORMAT_YCrCb_420_SP: GL_RGB8 // Does not have a precise match - default: GL_RGBA8 // TODO: Report warning - } -} - -@internal -class EGLImage { - EGLImageKHR ID - EGLDisplay Display - EGLContext Context - EGLenum Target - EGLClientBuffer Buffer - EGLint[] AttribList - - @hidden ref!AndroidNativeBufferExtra Extra - @hidden map!(EGLint, ref!Image) Images -} - -@serialize map!(EGLContext, ref!Context) EGLContexts -@serialize map!(EGLImageKHR, ref!EGLImage) EGLImages - -@no_replay -cmd EGLBoolean eglGetConfigAttrib(EGLDisplay display, - EGLConfig config, - EGLint attribute, - EGLint* value) { - value[0] = ? - return ? -} - -@no_replay -cmd EGLBoolean eglBindAPI(EGLenum api) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglBindTexImage(EGLDisplay display, EGLSurface surface, EGLint buffer) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglChooseConfig(EGLDisplay display, - EGLint const* attrib_list, - EGLConfig* configs, - EGLint config_size, - EGLint* num_config) { - _ = CloneAttribList(attrib_list) - num := ? - num_config[0] = num - if configs != null { - write(configs[0:num]) - } - return ? -} - -@no_replay -cmd EGLint eglClientWaitSyncKHR(EGLDisplay dpy, - EGLSyncKHR sync, - EGLint sync_flags, - EGLTimeKHR timeout) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglCopyBuffers(EGLDisplay display, - EGLSurface surface, - EGLNativePixmapType native_pixmap) { - return ? // TODO -} - -@custom @no_replay -///http://www.khronos.org/registry/egl/sdk/docs/man/html/eglCreateContext.xhtml -cmd EGLContext eglCreateContext(EGLDisplay display, - EGLConfig config, - EGLContext share_context, - EGLint* attrib_list) { - _ = CloneAttribList(as!EGLint const*(attrib_list)) - handle := ? - ctx := CreateContext(EGLContexts[share_context]) - EGLContexts[handle] = ctx - return handle -} - -@no_replay -cmd EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay display, - EGLenum buftype, - EGLClientBuffer buffer, - EGLConfig config, - EGLint const* attrib_list) { - _ = CloneAttribList(attrib_list) - return ? // TODO -} - -@no_replay -cmd EGLSurface eglCreatePbufferSurface(EGLDisplay display, - EGLConfig config, - EGLint const* attrib_list) { - _ = CloneAttribList(attrib_list) - return ? // TODO -} - -@no_replay -cmd EGLSurface eglCreatePixmapSurface(EGLDisplay display, - EGLConfig config, - EGLNativePixmapType native_pixmap, - EGLint const* attrib_list) { - _ = CloneAttribList(attrib_list) - return ? // TODO -} - -@no_replay -cmd EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, - EGLenum type, - const EGLint* attrib_list) { - _ = CloneAttribList(attrib_list) - return ? // TODO -} - -@no_replay -cmd EGLSurface eglCreateWindowSurface(EGLDisplay display, - EGLConfig config, - EGLNativeWindowType native_window, - EGLint const* attrib_list) { - _ = CloneAttribList(attrib_list) - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglDestroyContext(EGLDisplay display, EGLContext context) { - if (context != null) && context in EGLContexts { - ctx := EGLContexts[context] - ctx.Other.Destroyed = true - } - return ? -} - -@no_replay -cmd EGLBoolean eglDestroySurface(EGLDisplay display, EGLSurface surface) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglGetConfigs(EGLDisplay display, - EGLConfig* configs, - EGLint config_size, - EGLint* num_config) { - num := ? - num_config[0] = num - if configs != null { - write(configs[0:num]) - } - return ? // TODO -} - -@no_replay -cmd EGLContext eglGetCurrentContext() { - return ? // TODO -} - -@no_replay -cmd EGLDisplay eglGetCurrentDisplay() { - return ? // TODO -} - -@no_replay -cmd EGLSurface eglGetCurrentSurface(EGLint readdraw) { - return ? // TODO -} - -@no_replay -cmd EGLDisplay eglGetDisplay(EGLNativeDisplayType native_display) { - return ? // TODO -} - -@no_replay -@ignore_reentry // Many drivers internally call eglGetError(). Silence warnings. -cmd EGLint eglGetError() { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint* value) { - return ? // TODO -} - -@no_replay -///http://www.khronos.org/registry/egl/sdk/docs/man/html/eglInitialize.xhtml -cmd EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) { - if major != null { - major[0] = ? - } - if major != null { - minor[0] = ? - } - return ? -} - -@custom @no_replay -///http://www.khronos.org/registry/egl/sdk/docs/man/html/eglMakeCurrent.xhtml -cmd EGLBoolean eglMakeCurrent(EGLDisplay display, - EGLSurface draw, - EGLSurface read, - EGLContext context) { - if (context == null) { - SetContext(null) - } else if context in EGLContexts { - ctx := EGLContexts[context] - if (draw == null) || (read == null) { - // TODO: Check whether this extension is supported: - // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_surfaceless_context.txt - // If not, error and abort. - } - if (ctx.Other.BoundOnThread != 0) && (ctx != Contexts[$Thread]) { - _ = newMsg(SEVERITY_ERROR, new!ERR_CONTEXT_BOUND(id: as!u64(context))) - abort - } - SetContext(ctx) - if !ctx.Other.Initialized { - ApplyStaticContextState(ctx, GetEGLStaticContextState(display, context)) - ApplyDynamicContextState(ctx, GetEGLDynamicContextState(display, draw, context), true) - } else { - ApplyDynamicContextState(ctx, GetEGLDynamicContextState(display, draw, context), false) - } - } else { - dynamicState := GetEGLDynamicContextState(display, draw, context) - staticState := GetEGLStaticContextState(display, context) - if (dynamicState != null) && (staticState != null) { - // We don't know anything about this context, but it existed at trace - // time. In this situation it is likely that the context was created - // before the interceptor was injected. The best thing we can do in this - // situation is to build the context now. - _ = newMsg(SEVERITY_WARNING, new!WARN_UNKNOWN_CONTEXT(id: as!u64(context))) - ctx := CreateContext(null) - EGLContexts[context] = ctx - SetContext(ctx) - // The current context is fetched by ApplyStaticContextState() and - // ApplyDynamicContextState() so SetContext() must be set before these - // calls. - ApplyStaticContextState(ctx, staticState) - ApplyDynamicContextState(ctx, dynamicState, false) - } else { - // TODO: onEGLError(EGL_BAD_CONTEXT) - _ = newMsg(SEVERITY_ERROR, new!ERR_CONTEXT_DOES_NOT_EXIST(id: as!u64(context))) - abort - } - } - return ? -} - -@no_replay -cmd EGLenum eglQueryAPI() { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglQueryContext(EGLDisplay display, EGLContext context, EGLint attribute, EGLint* value) { - value[0] = ? - return ? -} - -@no_replay -cmd EGLBoolean eglQuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value) { - value[0] = ? - return ? -} - -@no_replay -cmd const char* eglQueryString(EGLDisplay display, EGLint name) { - // TODO: EGL_CLIENT_APIS, EGL_VENDOR, EGL_VERSION, or EGL_EXTENSIONS - return ? -} - -@no_replay -cmd EGLBoolean eglReleaseTexImage(EGLDisplay display, - EGLSurface surface, - EGLint buffer) { - return ? -} - -@no_replay -cmd EGLBoolean eglReleaseThread() { - return ? -} - -@no_replay -cmd EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglSurfaceAttrib(EGLDisplay display, - EGLSurface surface, - EGLint attribute, - EGLint value) { - return ? // TODO -} - -@frame_start -@custom -///http://www.khronos.org/registry/egl/sdk/docs/man/html/eglSwapBuffers.xhtml -cmd EGLBoolean eglSwapBuffers(EGLDisplay display, void* surface) { - - // eglSwapBuffers leaves buffer contents undefined, so there cannot - // be dependencies on framebuffer attachement values across - // eglSwapBuffers. - // TODO(hevrard): there is a possible dependency on color buffer - // if EGL_SWAP_BEHAVIOR == EGL_BUFFER_PRESERVED - ctx := GetContext() - fb := ctx.Bound.DrawFramebuffer - for _, _, a in fb.ColorAttachments { - WriteFramebufferAttachment(a) - } - WriteFramebufferAttachment(fb.DepthAttachment) - WriteFramebufferAttachment(fb.StencilAttachment) - - return ? -} - -@frame_start -@no_replay -///https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt -cmd EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, - EGLSurface surface, - EGLint* rects, - EGLint n_rects) { - read(rects[0:n_rects * as!EGLint(4)]) - return ? -} - -@no_replay -cmd EGLBoolean eglSwapInterval(EGLDisplay display, EGLint interval) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglTerminate(EGLDisplay display) { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglWaitClient() { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglWaitGL() { - return ? // TODO -} - -@no_replay -cmd EGLBoolean eglWaitNative(EGLint engine) { - // TODO: EGL_CORE_NATIVE_ENGINE - return ? // TODO -} - -@if(Extension.EGL_KHR_image_base) -@doc("https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt", Extension.EGL_KHR_image_base) -@custom @no_replay -cmd EGLImageKHR eglCreateImageKHR(EGLDisplay display, - EGLContext context, - EGLenum target, - EGLClientBuffer buffer, - const EGLint* attrib_list) { - attribList := CloneAttribList(attrib_list) - id := ? - eglImage := new!EGLImage( - ID: id, - Display: display, - Context: context, - Target: target, - Buffer: buffer, - AttribList: attribList) - switch target { - case EGL_GL_TEXTURE_2D: { - c := EGLContexts[context] - assert(c != null) // EGL_BAD_CONTEXT - image := GetTextureImage(c.Objects.Textures[as!TextureId(as!u64(buffer))], 0, 0) - assert(image != null) // EGL_BAD_PARAMETER - eglImage.Images[0] = image - } - case EGL_NATIVE_BUFFER_ANDROID: { - info := GetAndroidNativeBufferExtra(as!void*(buffer)) - sf := EGLSizedFormat2GLSizedFormat(info.Format) - sfInfo := GetSizedFormatInfo(sf) - eglImage.Extra = info - for i in 0 .. max!u32(info.LayerCount, 1) { - image := new!Image( - Width: as!GLsizei(info.Width), - Height: as!GLsizei(info.Height), - SizedFormat: sf, - InternalFormat: sf, - DataFormat: sfInfo.UnsizedFormat, - DataType: sfInfo.DataType, - ) - size := uncompressedImageSize(image.Width, image.Height, image.DataFormat, image.DataType) - image.Data = make!u8(size) - eglImage.Images[as!EGLint(i)] = image - } - } - } - EGLImages[id] = eglImage - return id -} - -@if(Extension.EGL_KHR_image_base) -@doc("https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt", Extension.EGL_KHR_image_base) -@no_replay -cmd EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) { - // TODO - return ? -} - -@if(Extension.EGL_ANDROID_create_native_client_buffer) -@doc("https://www.khronos.org/registry/egl/extensions/ANDROID/EGL_ANDROID_create_native_client_buffer.txt", Extension.EGL_ANDROID_create_native_client_buffer) -@no_replay -cmd EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint* attrib_list) { - _ = CloneAttribList(attrib_list) - // TODO - return ? -} - -@no_replay -cmd EGLClientBuffer eglGetNativeClientBufferANDROID(AHardwareBuffer buffer) { - return ? // TODO -} - -@if(Extension.EGL_ANDROID_native_fence_sync) -@doc("https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt", Extension.EGL_ANDROID_native_fence_sync) -@no_replay -cmd EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync) { - return ? // TODO -} - -@if(Extension.EGL_KHR_wait_sync) -@doc("https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_wait_sync.txt", Extension.EGL_KHR_wait_sync) -@no_replay -cmd EGLint eglWaitSyncKHR(EGLDisplay dpy, - EGLSyncKHR sync, - EGLint flags) { - return ? // TODO -} diff --git a/gapis/api/gles/api/eglenum.api b/gapis/api/gles/api/eglenum.api deleted file mode 100644 index 15f031c9a8..0000000000 --- a/gapis/api/gles/api/eglenum.api +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@analyze_usage -enum EGLenum { - EGL_ALPHA_FORMAT = 0x3088, - EGL_ALPHA_FORMAT_NONPRE = 0x308B, - EGL_ALPHA_FORMAT_PRE = 0x308C, - EGL_ALPHA_MASK_SIZE = 0x303E, - EGL_ALPHA_SIZE = 0x3021, - EGL_BACK_BUFFER = 0x3084, - EGL_BAD_ACCESS = 0x3002, - EGL_BAD_ALLOC = 0x3003, - EGL_BAD_ATTRIBUTE = 0x3004, - EGL_BAD_CONFIG = 0x3005, - EGL_BAD_CONTEXT = 0x3006, - EGL_BAD_CURRENT_SURFACE = 0x3007, - EGL_BAD_DISPLAY = 0x3008, - EGL_BAD_MATCH = 0x3009, - EGL_BAD_NATIVE_PIXMAP = 0x300A, - EGL_BAD_NATIVE_WINDOW = 0x300B, - EGL_BAD_PARAMETER = 0x300C, - EGL_BAD_SURFACE = 0x300D, - EGL_BIND_TO_TEXTURE_RGB = 0x3039, - EGL_BIND_TO_TEXTURE_RGBA = 0x303A, - EGL_BLUE_SIZE = 0x3022, - EGL_BUFFER_DESTROYED = 0x3095, - EGL_BUFFER_PRESERVED = 0x3094, - EGL_BUFFER_SIZE = 0x3020, - EGL_CL_EVENT_HANDLE = 0x309C, - EGL_CLIENT_APIS = 0x308D, - EGL_COLOR_BUFFER_TYPE = 0x303F, - EGL_COLORSPACE = 0x3087, - EGL_COLORSPACE_LINEAR = 0x308A, - EGL_COLORSPACE_sRGB = 0x3089, - EGL_CONDITION_SATISFIED = 0x30F6, - EGL_CONFIG_CAVEAT = 0x3027, - EGL_CONFIG_ID = 0x3028, - EGL_CONFORMANT = 0x3042, - EGL_CONTEXT_CLIENT_TYPE = 0x3097, - EGL_CONTEXT_CLIENT_VERSION = 0x3098, - EGL_CONTEXT_LOST = 0x300E, - EGL_CONTEXT_MAJOR_VERSION = 0x3098, - EGL_CONTEXT_MINOR_VERSION = 0x30FB, - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x0002, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x0001, - EGL_CONTEXT_OPENGL_DEBUG = 0x31B0, - EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1, - EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD, - EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD, - EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2, - EGL_CORE_NATIVE_ENGINE = 0x305B, - EGL_DEPTH_SIZE = 0x3025, - EGL_DISPLAY_SCALING = 10000 , - EGL_DRAW = 0x3059, - EGL_EXTENSIONS = 0x3055, - EGL_FALSE = 0x0000, - EGL_GL_COLORSPACE = 0x309D, - EGL_GL_COLORSPACE_LINEAR = 0x308A, - EGL_GL_COLORSPACE_SRGB = 0x3089, - EGL_GL_RENDERBUFFER = 0x30B9, - EGL_GL_TEXTURE_2D = 0x30B1, - EGL_GL_TEXTURE_3D = 0x30B2, - EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x30B4, - EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x30B6, - EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x30B8, - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x30B3, - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x30B5, - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x30B7, - EGL_GL_TEXTURE_LEVEL = 0x30BC, - EGL_GL_TEXTURE_ZOFFSET = 0x30BD, - EGL_GREEN_SIZE = 0x3023, - EGL_HEIGHT = 0x3056, - EGL_HORIZONTAL_RESOLUTION = 0x3090, - EGL_IMAGE_PRESERVED = 0x30D2, - EGL_LARGEST_PBUFFER = 0x3058, - EGL_LEVEL = 0x3029, - EGL_LOSE_CONTEXT_ON_RESET = 0x31BF, - EGL_LUMINANCE_BUFFER = 0x308F, - EGL_LUMINANCE_SIZE = 0x303D, - EGL_MATCH_NATIVE_PIXMAP = 0x3041, - EGL_MAX_PBUFFER_HEIGHT = 0x302A, - EGL_MAX_PBUFFER_PIXELS = 0x302B, - EGL_MAX_PBUFFER_WIDTH = 0x302C, - EGL_MAX_SWAP_INTERVAL = 0x303C, - EGL_MIN_SWAP_INTERVAL = 0x303B, - EGL_MIPMAP_LEVEL = 0x3083, - EGL_MIPMAP_TEXTURE = 0x3082, - EGL_MULTISAMPLE_RESOLVE = 0x3099, - EGL_MULTISAMPLE_RESOLVE_BOX = 0x309B, - EGL_MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200, - EGL_MULTISAMPLE_RESOLVE_DEFAULT = 0x309A, - EGL_NATIVE_RENDERABLE = 0x302D, - EGL_NATIVE_VISUAL_ID = 0x302E, - EGL_NATIVE_VISUAL_TYPE = 0x302F, - EGL_NO_CONTEXT = 0x0000, - EGL_NO_DISPLAY = 0x0000, - EGL_NO_IMAGE = 0x0000, - EGL_NO_RESET_NOTIFICATION = 0x31BE, - EGL_NO_SURFACE = 0x0000, - EGL_NO_SYNC = 0x0000, - EGL_NO_TEXTURE = 0x305C, - EGL_NON_CONFORMANT_CONFIG = 0x3051, - EGL_NONE = 0x3038, - EGL_NOT_INITIALIZED = 0x3001, - EGL_OPENGL_API = 0x30A2, - EGL_OPENGL_BIT = 0x0008, - EGL_OPENGL_ES2_BIT = 0x0004, - EGL_OPENGL_ES3_BIT = 0x0040, - EGL_OPENGL_ES_API = 0x30A0, - EGL_OPENGL_ES_BIT = 0x0001, - EGL_OPENVG_API = 0x30A1, - EGL_OPENVG_BIT = 0x0002, - EGL_OPENVG_IMAGE = 0x3096, - EGL_PBUFFER_BIT = 0x0001, - EGL_PIXEL_ASPECT_RATIO = 0x3092, - EGL_PIXMAP_BIT = 0x0002, - EGL_READ = 0x305A, - EGL_RED_SIZE = 0x3024, - EGL_RENDER_BUFFER = 0x3086, - EGL_RENDERABLE_TYPE = 0x3040, - EGL_RGB_BUFFER = 0x308E, - EGL_SAMPLE_BUFFERS = 0x3032, - EGL_SAMPLES = 0x3031, - EGL_SIGNALED = 0x30F2, - EGL_SINGLE_BUFFER = 0x3085, - EGL_SLOW_CONFIG = 0x3050, - EGL_STENCIL_SIZE = 0x3026, - EGL_SUCCESS = 0x3000, - EGL_SURFACE_TYPE = 0x3033, - EGL_SWAP_BEHAVIOR = 0x3093, - EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400, - EGL_SYNC_CL_EVENT = 0x30FE, - EGL_SYNC_CL_EVENT_COMPLETE = 0x30FF, - EGL_SYNC_CONDITION = 0x30F8, - EGL_SYNC_FENCE = 0x30F9, - EGL_SYNC_FLUSH_COMMANDS_BIT = 0x0001, - EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 0x30F0, - EGL_SYNC_STATUS = 0x30F1, - EGL_SYNC_TYPE = 0x30F7, - EGL_TEXTURE_2D = 0x305F, - EGL_TEXTURE_FORMAT = 0x3080, - EGL_TEXTURE_RGB = 0x305D, - EGL_TEXTURE_RGBA = 0x305E, - EGL_TEXTURE_TARGET = 0x3081, - EGL_TIMEOUT_EXPIRED = 0x30F5, - EGL_TRANSPARENT_BLUE_VALUE = 0x3035, - EGL_TRANSPARENT_GREEN_VALUE = 0x3036, - EGL_TRANSPARENT_RED_VALUE = 0x3037, - EGL_TRANSPARENT_RGB = 0x3052, - EGL_TRANSPARENT_TYPE = 0x3034, - EGL_TRUE = 0x0001, - EGL_UNSIGNALED = 0x30F3, - EGL_VENDOR = 0x3053, - EGL_VERSION = 0x3054, - EGL_VERTICAL_RESOLUTION = 0x3091, - EGL_VG_ALPHA_FORMAT = 0x3088, - EGL_VG_ALPHA_FORMAT_NONPRE = 0x308B, - EGL_VG_ALPHA_FORMAT_PRE = 0x308C, - EGL_VG_ALPHA_FORMAT_PRE_BIT = 0x0040, - EGL_VG_COLORSPACE = 0x3087, - EGL_VG_COLORSPACE_LINEAR = 0x308A, - EGL_VG_COLORSPACE_LINEAR_BIT = 0x0020, - EGL_VG_COLORSPACE_sRGB = 0x3089, - EGL_WIDTH = 0x3057, - EGL_WINDOW_BIT = 0x0004, - EGL_CONTEXT_MAJOR_VERSION_KHR = 0x3098, - EGL_NATIVE_BUFFER_ANDROID = 0x3140, // ANDROID_image_native_buffer -} diff --git a/gapis/api/gles/api/errors.api b/gapis/api/gles/api/errors.api deleted file mode 100644 index a2329a16d1..0000000000 --- a/gapis/api/gles/api/errors.api +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -extern void onGlError(GLenum v) - -sub void supportsBits(GLbitfield seenBits, GLbitfield validBits) { - CheckEQ!GLbitfield((seenBits & validBits), seenBits) -} - -sub void glErrorInvalidEnum(GLenum value) { - glErrorInvalidEnumMsg(new!ERR_INVALID_ENUM(value: as!u32(value))) -} - -sub void glErrorInvalidEnumMsg(message m) { - onGlError(GL_INVALID_ENUM) - _ = newMsg(SEVERITY_ERROR, m) - abort -} - -sub void glErrorInvalidValue!T(T value) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE(value: as!s64(value))) -} - -sub void glErrorInvalidObjectName!T(T value) { - glErrorInvalidValueMsg(new!ERR_INVALID_OBJECT_NAME(value: as!s64(value))) -} - -sub void glErrorInvalidValueMsg(message m) { - onGlError(GL_INVALID_VALUE) - _ = newMsg(SEVERITY_ERROR, m) - abort -} - -sub void glErrorInvalidOperation() { - glErrorInvalidOperationMsg(new!ERR_INVALID_OPERATION()) -} - -sub void glErrorInvalidOperationMsg(message m) { - onGlError(GL_INVALID_OPERATION) - _ = newMsg(SEVERITY_ERROR, m) - abort -} - -sub void CheckEQ!T(T value, T constraint) { - if !(as!s64(value) == as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_EQ(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckNE!T(T value, T constraint) { - if !(as!s64(value) != as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_NE(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckGE!T(T value, T constraint) { - if !(as!s64(value) >= as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_GE(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckGT!T(T value, T constraint) { - if !(as!s64(value) > as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_GT(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckLE!T(T value, T constraint) { - if !(as!s64(value) <= as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_LE(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckLT!T(T value, T constraint) { - if !(as!s64(value) < as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_LT(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckLocationLT!T(T value, T constraint) { - if !(as!s64(value) < as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_LOCATION_LT(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckCountGE!T(T value, T constraint) { - if !(as!s64(value) >= as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_COUNT_GE(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void CheckSizeGE!T(T value, T constraint) { - if !(as!s64(value) >= as!s64(constraint)) { - glErrorInvalidValueMsg(new!ERR_INVALID_VALUE_CHECK_SIZE_GE(value: as!s64(value), constraint: as!s64(constraint))) - } -} - -sub void glErrorInvalidOperation_ObjectDoesNotExist!T(T id) { - glErrorInvalidOperationMsg(new!ERR_INVALID_OPERATION_OBJECT_DOES_NOT_EXIST(id: as!u64(id))) -} diff --git a/gapis/api/gles/api/extensions.api b/gapis/api/gles/api/extensions.api deleted file mode 100644 index a5d4118aa3..0000000000 --- a/gapis/api/gles/api/extensions.api +++ /dev/null @@ -1,3335 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@post_fence -extern void GetEGLImageData(EGLImageKHR img, GLsizei width, GLsizei height) - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glActiveShaderProgramEXT(PipelineId pipeline, ProgramId program) { - // TODO -} - -@if(Extension.GL_QCOM_alpha_test) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_alpha_test.txt", Extension.GL_QCOM_alpha_test) -cmd void glAlphaFuncQCOM(GLenum func, GLclampf ref) { - // TODO -} - -@if(Extension.GL_INTEL_framebuffer_CMAA) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_framebuffer_CMAA.txt", Extension.GL_INTEL_framebuffer_CMAA) -cmd void glApplyFramebufferAttachmentCMAAINTEL() { - // TODO -} - -@if(Extension.GL_NV_conditional_render) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_conditional_render.txt", Extension.GL_NV_conditional_render) -cmd void glBeginConditionalRenderNV(GLuint id, GLenum mode) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glBeginPerfMonitorAMD(GLuint monitor) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glBeginPerfQueryINTEL(GLuint queryHandle) { - // TODO -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glBeginQueryEXT(GLenum target, QueryId query) { - -} - -@if(Extension.GL_EXT_blend_func_extended) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_blend_func_extended.txt", Extension.GL_EXT_blend_func_extended) -cmd void glBindFragDataLocationEXT(ProgramId program, GLuint color, const GLchar* name) { - _ = as!string(as!char*(name)) -} - -@if(Extension.GL_EXT_blend_func_extended) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_blend_func_extended.txt", Extension.GL_EXT_blend_func_extended) -cmd void glBindFragDataLocationIndexedEXT(ProgramId program, - GLuint colorNumber, - GLuint index, - const GLchar* name) { - _ = as!string(as!char*(name)) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glBindProgramPipelineEXT(PipelineId pipeline) { - // TODO -} - -@if(Extension.GL_OES_vertex_array_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt", Extension.GL_OES_vertex_array_object) -cmd void glBindVertexArrayOES(VertexArrayId array) { - BindVertexArray(array) -} - -@if(Extension.GL_NV_blend_equation_advanced) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_blend_equation_advanced.txt", Extension.GL_NV_blend_equation_advanced) -cmd void glBlendBarrierNV() { - BlendBarrier() -} - -@if(Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -cmd void glBlendEquationSeparateiOES(DrawBufferIndex buf, GLenum modeRGB, GLenum modeAlpha) { - BlendEquationSeparatei(buf, modeRGB, modeAlpha) -} - -@if(Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -cmd void glBlendEquationiOES(DrawBufferIndex buf, GLenum mode) { - BlendEquationi(buf, mode) -} - -@if(Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -cmd void glBlendFuncSeparateiOES(DrawBufferIndex buf, - GLenum srcRGB, - GLenum dstRGB, - GLenum srcAlpha, - GLenum dstAlpha) { - BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha) -} - -@if(Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -cmd void glBlendFunciOES(DrawBufferIndex buf, GLenum src, GLenum dst) { - BlendFunci(buf, src, dst) -} - -@if(Extension.GL_NV_blend_equation_advanced) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_blend_equation_advanced.txt", Extension.GL_NV_blend_equation_advanced) -cmd void glBlendParameteriNV(GLenum pname, GLint value) { - // TODO -} - -@if(Extension.GL_ANGLE_framebuffer_blit) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_framebuffer_blit.txt", Extension.GL_ANGLE_framebuffer_blit) -cmd void glBlitFramebufferANGLE(GLint srcX0, - GLint srcY0, - GLint srcX1, - GLint srcY1, - GLint dstX0, - GLint dstY0, - GLint dstX1, - GLint dstY1, - GLbitfield mask, - GLenum filter) { - // TODO -} - -@if(Extension.GL_NV_framebuffer_blit) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_blit.txt", Extension.GL_NV_framebuffer_blit) -cmd void glBlitFramebufferNV(GLint srcX0, - GLint srcY0, - GLint srcX1, - GLint srcY1, - GLint dstX0, - GLint dstY0, - GLint dstX1, - GLint dstY1, - GLbitfield mask, - GLenum filter) { - BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) -} - -@if(Extension.GL_EXT_buffer_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_buffer_storage.txt", Extension.GL_EXT_buffer_storage) -cmd void glBufferStorageEXT(GLenum target, GLsizeiptr size, const void* data, GLbitfield flag) { - // TODO -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd GLenum glClientWaitSyncAPPLE(GLsync sync, GLbitfield flag, GLuint64 timeout) { - ClientWaitSync(sync, flag, timeout) - return ? -} - -@if(Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -cmd void glColorMaskiOES(DrawBufferIndex index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - ColorMaski(index, r, g, b, a) -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glCompressedTexImage3DOES(GLenum target, - GLint level, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLint border, - GLsizei image_size, - TexturePointer data) { - CompressedTexImage3D(target, level, internalformat, width, height, depth, border, image_size, data) -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glCompressedTexSubImage3DOES(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLenum format, - GLsizei image_size, - TexturePointer data) { - CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, image_size, data) -} - -@if(Extension.GL_NV_copy_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_copy_buffer.txt", Extension.GL_NV_copy_buffer) -cmd void glCopyBufferSubDataNV(GLenum readTarget, - GLenum writeTarget, - GLintptr readOffset, - GLintptr writeOffset, - GLsizeiptr size) { - CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size) -} - -@if(Extension.GL_OES_copy_image) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_copy_image.txt", Extension.GL_OES_copy_image) -cmd void glCopyImageSubDataOES(SrcImageId srcName, - GLenum srcTarget, - GLint srcLevel, - GLint srcX, - GLint srcY, - GLint srcZ, - DstImageId dstName, - GLenum dstTarget, - GLint dstLevel, - GLint dstX, - GLint dstY, - GLint dstZ, - GLsizei srcWidth, - GLsizei srcHeight, - GLsizei srcDepth) { - CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glCopyPathNV(GLuint resultPath, GLuint srcPath) { - // TODO -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glCopyTexSubImage3DOES(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) -} - -@if(Extension.GL_APPLE_copy_texture_levels) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_copy_texture_levels.txt", Extension.GL_APPLE_copy_texture_levels) -cmd void glCopyTextureLevelsAPPLE(GLuint destinationTexture, - GLuint sourceTexture, - GLint sourceBaseLevel, - GLsizei sourceLevelCount) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glCoverFillPathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLenum coverMode, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glCoverFillPathNV(GLuint path, GLenum coverMode) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glCoverStrokePathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLenum coverMode, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glCoverStrokePathNV(GLuint path, GLenum coverMode) { - // TODO -} - -@if(Extension.GL_NV_coverage_sample) -@doc("https://www.khronos.org/registry/gles/extensions/NV/EGL_NV_coverage_sample.txt", Extension.GL_NV_coverage_sample) -cmd void glCoverageMaskNV(GLboolean mask) { - // TODO -} - -@if(Extension.GL_NV_framebuffer_mixed_samples) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_mixed_samples.txt", Extension.GL_NV_framebuffer_mixed_samples) -cmd void glCoverageModulationNV(GLenum components) { - // TODO -} - -@if(Extension.GL_NV_framebuffer_mixed_samples) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_mixed_samples.txt", Extension.GL_NV_framebuffer_mixed_samples) -cmd void glCoverageModulationTableNV(GLsizei n, const GLfloat* v) { - // TODO -} - -@if(Extension.GL_NV_coverage_sample) -@doc("https://www.khronos.org/registry/gles/extensions/NV/EGL_NV_coverage_sample.txt", Extension.GL_NV_coverage_sample) -cmd void glCoverageOperationNV(GLenum operation) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glCreatePerfQueryINTEL(GLuint queryId, GLuint* queryHandle) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd GLuint glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLchar** strings) { - // TODO - return ? -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd void glDeleteFencesNV(GLsizei n, const GLuint* fences) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glDeletePathsNV(GLuint path, GLsizei range) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glDeletePerfMonitorsAMD(GLsizei n, GLuint* monitors) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glDeletePerfQueryINTEL(GLuint queryHandle) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glDeleteProgramPipelinesEXT(GLsizei n, const PipelineId* pipelines) { - DeleteProgramPipelines(n, pipelines) -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glDeleteQueriesEXT(GLsizei count, const QueryId* queries) { - DeleteQueries(count, queries) -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd void glDeleteSyncAPPLE(GLsync sync) { - DeleteSync(sync) -} - -@if(Extension.GL_OES_vertex_array_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt", Extension.GL_OES_vertex_array_object) -cmd void glDeleteVertexArraysOES(GLsizei count, const VertexArrayId* arrays) { - DeleteVertexArrays(count, arrays) -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glDepthRangeArrayfvNV(GLuint first, GLsizei count, const GLfloat* v) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glDepthRangeIndexedfNV(GLuint index, GLfloat n, GLfloat f) { - // TODO -} - -@if(Extension.GL_QCOM_driver_control) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_driver_control.txt", Extension.GL_QCOM_driver_control) -cmd void glDisableDriverControlQCOM(GLuint driverControl) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glDisableiNV(GLenum target, GLuint index) { - Disablei(target, index) -} - -@if(Extension.GL_OES_draw_buffers_indexed || Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glDisableiOES(GLenum target, GLuint index) { - Disablei(target, index) -} - -@if(Extension.GL_EXT_discard_framebuffer) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt", Extension.GL_EXT_discard_framebuffer) -cmd void glDiscardFramebufferEXT(GLenum target, - GLsizei numAttachments, - const GLenum* attachments) { - InvalidateFramebuffer(target, numAttachments, attachments) -} - -@if(Extension.GL_ANGLE_instanced_arrays) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt", Extension.GL_ANGLE_instanced_arrays) -cmd void glDrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { - DrawArraysInstanced(mode, first, count, primcount) -} - -@if(Extension.GL_EXT_base_instance) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_base_instance.txt", Extension.GL_EXT_base_instance) -cmd void glDrawArraysInstancedBaseInstanceEXT(GLenum mode, - GLint first, - GLsizei count, - GLsizei instancecount, - GLuint baseinstance) { - // TODO -} - -@if(Extension.GL_EXT_draw_instanced || Extension.GL_EXT_instanced_arrays) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_instanced.txt", Extension.GL_EXT_draw_instanced) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_instanced_arrays.txt", Extension.GL_EXT_instanced_arrays) -cmd void glDrawArraysInstancedEXT(GLenum mode, GLint start, GLsizei count, GLsizei primcount) { - DrawArraysInstanced(mode, start, count, primcount) -} - -@if(Extension.GL_NV_draw_instanced) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_draw_instanced.txt", Extension.GL_NV_draw_instanced) -cmd void glDrawArraysInstancedNV(GLenum mode, GLint first, GLsizei count, GLsizei primcount) { - DrawArraysInstanced(mode, first, count, primcount) -} - -@if(Extension.GL_EXT_draw_buffers) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_buffers.txt", Extension.GL_EXT_draw_buffers) -cmd void glDrawBuffersEXT(GLsizei n, const GLenum* bufs) { - DrawBuffers(n, bufs) -} - -@if(Extension.GL_EXT_multiview_draw_buffers) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multiview_draw_buffers.txt", Extension.GL_EXT_multiview_draw_buffers) -cmd void glDrawBuffersIndexedEXT(GLint n, const GLenum* location, const GLint* indices) { - // TODO -} - -@if(Extension.GL_NV_draw_buffers) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_draw_buffers.txt", Extension.GL_NV_draw_buffers) -cmd void glDrawBuffersNV(GLsizei n, const GLenum* bufs) { - DrawBuffers(n, bufs) -} - -@if(Extension.GL_EXT_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_elements_base_vertex.txt", Extension.GL_EXT_draw_elements_base_vertex) -cmd void glDrawElementsBaseVertexEXT(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLint basevertex) { - DrawElementsBaseVertex(mode, count, type, indices, basevertex) -} - -@if(Extension.GL_OES_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_elements_base_vertex.txt", Extension.GL_OES_draw_elements_base_vertex) -cmd void glDrawElementsBaseVertexOES(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLint basevertex) { - DrawElementsBaseVertex(mode, count, type, indices, basevertex) -} - -@if(Extension.GL_ANGLE_instanced_arrays) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt", Extension.GL_ANGLE_instanced_arrays) -cmd void glDrawElementsInstancedANGLE(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLsizei primcount) { - DrawElementsInstanced(mode, count, type, indices, primcount) -} - -@if(Extension.GL_EXT_base_instance) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_base_instance.txt", Extension.GL_EXT_base_instance) -cmd void glDrawElementsInstancedBaseInstanceEXT(GLenum mode, - GLsizei count, - GLenum type, - const void* indices, - GLsizei instancecount, - GLuint baseinstance) { - // TODO -} - -@if(Extension.GL_EXT_base_instance) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_base_instance.txt", Extension.GL_EXT_base_instance) -cmd void glDrawElementsInstancedBaseVertexBaseInstanceEXT(GLenum mode, - GLsizei count, - GLenum type, - const void* indices, - GLsizei instancecount, - GLint basevertex, - GLuint baseinstance) { - // TODO -} - -@if(Extension.GL_EXT_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_elements_base_vertex.txt", Extension.GL_EXT_draw_elements_base_vertex) -cmd void glDrawElementsInstancedBaseVertexEXT(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLsizei instancecount, - GLint basevertex) { - DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex) -} - -@if(Extension.GL_OES_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_elements_base_vertex.txt", Extension.GL_OES_draw_elements_base_vertex) -cmd void glDrawElementsInstancedBaseVertexOES(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLsizei instancecount, - GLint basevertex) { - DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex) -} - -@if(Extension.GL_EXT_draw_instanced || Extension.GL_EXT_instanced_arrays) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_instanced.txt", Extension.GL_EXT_draw_instanced) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_instanced_arrays.txt", Extension.GL_EXT_instanced_arrays) -cmd void glDrawElementsInstancedEXT(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLsizei primcount) { - DrawElementsInstanced(mode, count, type, indices, primcount) -} - -@if(Extension.GL_NV_draw_instanced) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_draw_instanced.txt", Extension.GL_NV_draw_instanced) -cmd void glDrawElementsInstancedNV(GLenum mode, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLsizei primcount) { - DrawElementsInstanced(mode, count, type, indices, primcount) -} - -@if(Extension.GL_EXT_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_elements_base_vertex.txt", Extension.GL_EXT_draw_elements_base_vertex) -cmd void glDrawRangeElementsBaseVertexEXT(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLint basevertex) { - DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex) -} - -@if(Extension.GL_OES_draw_elements_base_vertex) -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_elements_base_vertex.txt", Extension.GL_OES_draw_elements_base_vertex) -cmd void glDrawRangeElementsBaseVertexOES(GLenum mode, - GLuint start, - GLuint end, - GLsizei count, - GLenum type, - IndicesPointer indices, - GLint basevertex) { - DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex) -} - -@if(Extension.GL_OES_EGL_image) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image.txt", Extension.GL_OES_EGL_image) -cmd void glEGLImageTargetRenderbufferStorageOES(GLenum target, EGLImageKHR image) { - -} - -@if(Extension.GL_OES_EGL_image || Extension.GL_EXT_EGL_image_array || Extension.GL_OES_EGL_image_external) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image.txt", Extension.GL_OES_EGL_image) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_EGL_image_array.txt", Extension.GL_EXT_EGL_image_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt", Extension.GL_OES_EGL_image_external) -cmd void glEGLImageTargetTexture2DOES(GLenum target, EGLImageKHR image) { - switch (target) { - @if(Extension.GL_OES_EGL_image) - case GL_TEXTURE_2D: {} - @if(Extension.GL_EXT_EGL_image_array) - case GL_TEXTURE_2D_ARRAY: {} - @if(Extension.GL_OES_EGL_image_external) - case GL_TEXTURE_EXTERNAL_OES: {} - default: - glErrorInvalidEnum(target) - } - eglImage := EGLImages[as!EGLImageKHR(image)] - if eglImage == null { - glErrorInvalidOperation_ObjectDoesNotExist!EGLImageKHR(image) - } - t := GetBoundTextureOrErrorInvalidEnum(target) - - for _, l, img in eglImage.Images { - SetTextureImage(t, 0, as!GLint(l), img) - if l == 0 { - t.EGLImage = eglImage - GetEGLImageData(eglImage.ID, img.Width, img.Height) - } - } -} - -@if(Extension.GL_QCOM_driver_control) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_driver_control.txt", Extension.GL_QCOM_driver_control) -cmd void glEnableDriverControlQCOM(GLuint driverControl) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glEnableiNV(GLenum target, GLuint index) { - Enablei(target, index) -} - -@if(Extension.GL_OES_draw_buffers_indexed || Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glEnableiOES(GLenum target, GLuint index) { - Enablei(target, index) -} - -@if(Extension.GL_NV_conditional_render) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_conditional_render.txt", Extension.GL_NV_conditional_render) -cmd void glEndConditionalRenderNV() { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glEndPerfMonitorAMD(GLuint monitor) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glEndPerfQueryINTEL(GLuint queryHandle) { - // TODO -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glEndQueryEXT(GLenum target) { - -} - -@if(Extension.GL_QCOM_tiled_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_tiled_rendering.txt", Extension.GL_QCOM_tiled_rendering) -cmd void glEndTilingQCOM(GLbitfield preserve_mask) { - -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetBufferPointervQCOM(GLenum target, void** params) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetBuffersQCOM(BufferId* buffers, GLint maxBuffers, GLint* numBuffers) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetFramebuffersQCOM(FramebufferId* framebuffers, - GLint maxFramebuffers, - GLint* numFramebuffers) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get2) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get2.txt", Extension.GL_QCOM_extended_get2) -cmd void glExtGetProgramBinarySourceQCOM(ProgramId program, - GLenum shadertype, - GLchar* source, - GLint* length) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get2) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get2.txt", Extension.GL_QCOM_extended_get2) -cmd void glExtGetProgramsQCOM(ProgramId* programs, GLint maxPrograms, GLint* numPrograms) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetRenderbuffersQCOM(RenderbufferId* renderbuffers, - GLint maxRenderbuffers, - GLint* numRenderbuffers) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get2) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get2.txt", Extension.GL_QCOM_extended_get2) -cmd void glExtGetShadersQCOM(ShaderId* shaders, GLint maxShaders, GLint* numShaders) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetTexLevelParameterivQCOM(TextureId texture, - GLenum face, - GLint level, - GLenum pname, - GLint* params) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetTexSubImageQCOM(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLenum format, - GLenum type, - void* texels) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtGetTexturesQCOM(TextureId* textures, GLint maxTextures, GLint* numTextures) { - // TODO -} - -@if(Extension.GL_QCOM_extended_get2) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get2.txt", Extension.GL_QCOM_extended_get2) -cmd GLboolean glExtIsProgramBinaryQCOM(ProgramId program) { - // TODO - return ? -} - -@if(Extension.GL_QCOM_extended_get) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_extended_get.txt", Extension.GL_QCOM_extended_get) -cmd void glExtTexObjectStateOverrideiQCOM(GLenum target, GLenum pname, GLint param) { - // TODO -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd GLsync glFenceSyncAPPLE(GLenum condition, GLbitfield flag) { - sync := ? - FenceSync(condition, flag, sync) - return sync -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd void glFinishFenceNV(GLuint fence) { - // TODO -} - -@if(Extension.GL_EXT_map_buffer_range) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_map_buffer_range.txt", Extension.GL_EXT_map_buffer_range) -cmd void glFlushMappedBufferRangeEXT(GLenum target, GLintptr offset, GLsizeiptr length) { - FlushMappedBufferRange(target, offset, length) -} - -@if(Extension.GL_NV_fragment_coverage_to_color) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fragment_coverage_to_color.txt", Extension.GL_NV_fragment_coverage_to_color) -cmd void glFragmentCoverageColorNV(GLuint color) { - // TODO -} - -@if(Extension.GL_NV_sample_locations) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_sample_locations.txt", Extension.GL_NV_sample_locations) -cmd void glFramebufferSampleLocationsfvNV(GLenum target, - GLuint start, - GLsizei count, - const GLfloat* v) { - // TODO -} - -@if(Extension.GL_EXT_multisampled_render_to_texture) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multisampled_render_to_texture.txt", Extension.GL_EXT_multisampled_render_to_texture) -cmd void glFramebufferTexture2DMultisampleEXT(GLenum target, - GLenum attachment, - GLenum textarget, - TextureId texture, - GLint level, - GLsizei samples) { - // TODO: Handle the multi-sampling instead of ignoring it. - FramebufferTexture2D(target, attachment, textarget, texture, level) -} - -@if(Extension.GL_IMG_multisampled_render_to_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_multisampled_render_to_texture.txt", Extension.GL_IMG_multisampled_render_to_texture) -cmd void glFramebufferTexture2DMultisampleIMG(GLenum target, - GLenum attachment, - GLenum textarget, - TextureId texture, - GLint level, - GLsizei samples) { - // TODO -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glFramebufferTexture3DOES(GLenum target, - GLenum attachment, - GLenum textarget, - TextureId texture, - GLint level, - GLint zoffset) { - // TODO -} - -@if(Extension.GL_OVR_multiview) -@doc("https://www.khronos.org/registry/gles/extensions/OVR/OVR_multiview.txt", Extension.GL_OVR_multiview) -cmd void glFramebufferTextureMultiviewOVR(GLenum target, - GLenum attachment, - TextureId texture, - GLint level, - GLint baseViewIndex, - GLsizei numViews) { - FramebufferTextureMultiviewOVR(target, attachment, texture, level, baseViewIndex, numViews) -} - -sub void FramebufferTextureMultiviewOVR(GLenum target, - GLenum attachment, - TextureId texture, - GLint level, - GLint baseViewIndex, - GLsizei numViews) { - ctx := GetContext() - attachment_info := FramebufferAttachment() - if (texture != 0) { - if !(texture in ctx.Objects.Textures) { glErrorInvalidObjectName!TextureId(texture) } - attachment_info.Type = GL_TEXTURE - attachment_info.Texture = ctx.Objects.Textures[texture] - attachment_info.TextureLevel = level - attachment_info.TextureLayer = baseViewIndex - attachment_info.NumViews = numViews - } - SetFramebufferAttachment(target, attachment, attachment_info) -} - -@if(Extension.GL_OES_geometry_shader) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_geometry_shader.txt", Extension.GL_OES_geometry_shader) -cmd void glFramebufferTextureOES(GLenum target, GLenum attachment, TextureId texture, GLint level) { - FramebufferTexture(target, attachment, texture, level) -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd void glGenFencesNV(GLsizei n, GLuint* fences) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLuint glGenPathsNV(GLsizei range) { - // TODO - return ? -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGenPerfMonitorsAMD(GLsizei n, GLuint* monitors) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glGenProgramPipelinesEXT(GLsizei n, PipelineId* pipelines) { - GenProgramPipelines(n, pipelines) -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glGenQueriesEXT(GLsizei count, QueryId* queries) { - GenQueries(count, queries) -} - -@if(Extension.GL_OES_vertex_array_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt", Extension.GL_OES_vertex_array_object) -cmd void glGenVertexArraysOES(GLsizei count, VertexArrayId* arrays) { - GenVertexArrays(count, arrays) -} - -@if(Extension.GL_OES_mapbuffer) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt", Extension.GL_OES_mapbuffer) -cmd void glGetBufferPointervOES(GLenum target, GLenum pname, void** params) { - GetBufferPointerv(target, pname, params) -} - -@if(Extension.GL_NV_framebuffer_mixed_samples) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_mixed_samples.txt", Extension.GL_NV_framebuffer_mixed_samples) -cmd void glGetCoverageModulationTableNV(GLsizei bufsize, GLfloat* v) { - // TODO -} - -@if(Extension.GL_QCOM_driver_control) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_driver_control.txt", Extension.GL_QCOM_driver_control) -cmd void glGetDriverControlStringQCOM(GLuint driverControl, - GLsizei bufSize, - GLsizei* length, - GLchar* driverControlString) { - // TODO -} - -@if(Extension.GL_QCOM_driver_control) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_driver_control.txt", Extension.GL_QCOM_driver_control) -cmd void glGetDriverControlsQCOM(GLint* num, GLsizei size, GLuint* driverControls) { - // TODO -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd void glGetFenceivNV(GLuint fence, GLenum pname, GLint* params) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetFirstPerfQueryIdINTEL(GLuint* queryId) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glGetFloati_vNV(GLenum target, GLuint index, GLfloat* data) { - // TODO -} - -@if(Extension.GL_EXT_blend_func_extended) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_blend_func_extended.txt", Extension.GL_EXT_blend_func_extended) -cmd GLint glGetFragDataIndexEXT(ProgramId program, const GLchar* name) { - _ = as!string(as!char*(name)) - return ? -} - -@if(Extension.GL_EXT_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_robustness.txt", Extension.GL_EXT_robustness) -cmd GLenum glGetGraphicsResetStatusEXT() { - - return ? -} - -@if(Extension.GL_KHR_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_robustness.txt", Extension.GL_KHR_robustness) -cmd GLenum glGetGraphicsResetStatusKHR() { - GetGraphicsResetStatus() - return ? -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd GLuint64 glGetImageHandleNV(TextureId texture, - GLint level, - GLboolean layered, - GLint layer, - GLenum format) { - // TODO - return ? -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd void glGetInteger64vAPPLE(GLenum pname, GLint64* params) { - GetInteger64v(pname, params) -} - -@if(Extension.GL_EXT_multiview_draw_buffers) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multiview_draw_buffers.txt", Extension.GL_EXT_multiview_draw_buffers) -cmd void glGetIntegeri_vEXT(GLenum target, GLuint index, GLint* data) { - // TODO -} - -@if(Extension.GL_NV_internalformat_sample_query) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_internalformat_sample_query.txt", Extension.GL_NV_internalformat_sample_query) -cmd void glGetInternalformatSampleivNV(GLenum target, - GLenum internalformat, - GLsizei samples, - GLenum pname, - GLsizei bufSize, - GLint* params) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetNextPerfQueryIdINTEL(GLuint queryId, GLuint* nextQueryId) { - // TODO -} - -@if(Extension.GL_EXT_debug_label) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_debug_label.txt", Extension.GL_EXT_debug_label) -cmd void glGetObjectLabelEXT(GLenum type, - GLuint object, - GLsizei bufSize, - GLsizei* length, - GLchar* label) { - - switch (type) { - case GL_TEXTURE, GL_FRAMEBUFFER, GL_RENDERBUFFER, - GL_BUFFER_OBJECT_EXT, GL_SHADER_OBJECT_EXT, GL_PROGRAM_OBJECT_EXT, - GL_VERTEX_ARRAY_OBJECT_EXT, GL_QUERY_OBJECT_EXT, GL_SAMPLER, GL_TRANSFORM_FEEDBACK, - GL_PROGRAM_PIPELINE_OBJECT_EXT: { - // GL_EXT_debug_label - } - default: { - glErrorInvalidEnum(type) - } - } - - _ = object // TODO - writeString(bufSize, length, label) -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathCommandsNV(GLuint path, GLubyte* commands) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathCoordsNV(GLuint path, GLfloat* coords) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathDashArrayNV(GLuint path, GLfloat* dashArray) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLfloat glGetPathLengthNV(GLuint path, GLsizei startSegment, GLsizei numSegments) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathMetricRangeNV(GLbitfield metricQueryMask, - GLuint firstPathName, - GLsizei numPaths, - GLsizei stride, - GLfloat* metrics) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathMetricsNV(GLbitfield metricQueryMask, - GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLsizei stride, - GLfloat* metrics) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathParameterfvNV(GLuint path, GLenum pname, GLfloat* value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathParameterivNV(GLuint path, GLenum pname, GLint* value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetPathSpacingNV(GLenum pathListMode, - GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLfloat advanceScale, - GLfloat kerningScale, - GLenum transformType, - GLfloat* returnedSpacing) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetPerfCounterInfoINTEL(GLuint queryId, - GLuint counterId, - GLuint counterNameLength, - GLchar* counterName, - GLuint counterDescLength, - GLchar* counterDesc, - GLuint* counterOffset, - GLuint* counterDataSize, - GLuint* counterTypeEnum, - GLuint* counterDataTypeEnum, - GLuint64* rawCounterMaxValue) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorCounterDataAMD(GLuint monitor, - GLenum pname, - GLsizei dataSize, - GLuint* data, - GLint* bytesWritten) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum pname, void* data) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorCounterStringAMD(GLuint group, - GLuint counter, - GLsizei bufSize, - GLsizei* length, - GLchar* counterString) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorCountersAMD(GLuint group, - GLint* numCounters, - GLint* maxActiveCounters, - GLsizei counterSize, - GLuint* counters) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorGroupStringAMD(GLuint group, - GLsizei bufSize, - GLsizei* length, - GLchar* groupString) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glGetPerfMonitorGroupsAMD(GLint* numGroups, GLsizei groupsSize, GLuint* groups) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetPerfQueryDataINTEL(GLuint queryHandle, - GLuint flag, - GLsizei dataSize, - GLvoid* data, - GLuint* bytesWritten) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetPerfQueryIdByNameINTEL(GLchar* queryName, GLuint* queryId) { - // TODO -} - -@if(Extension.GL_INTEL_performance_query) -@doc("https://www.khronos.org/registry/gles/extensions/INTEL/INTEL_performance_query.txt", Extension.GL_INTEL_performance_query) -cmd void glGetPerfQueryInfoINTEL(GLuint queryId, - GLuint queryNameLength, - GLchar* queryName, - GLuint* dataSize, - GLuint* noCounters, - GLuint* noInstances, - GLuint* capsMask) { - // TODO -} - -@if(Extension.GL_OES_get_program_binary) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_get_program_binary.txt", Extension.GL_OES_get_program_binary) -cmd void glGetProgramBinaryOES(ProgramId program, - GLsizei buffer_size, - GLsizei* bytes_written, - GLenum* binary_format, - void* binary) { - GetProgramBinary(program, buffer_size, bytes_written, binary_format, binary) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glGetProgramPipelineInfoLogEXT(PipelineId pipeline, - GLsizei bufSize, - GLsizei* length, - GLchar* infoLog) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glGetProgramPipelineivEXT(PipelineId pipeline, GLenum pname, GLint* params) { - // TODO -} - -@if(Extension.GL_EXT_blend_func_extended) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_blend_func_extended.txt", Extension.GL_EXT_blend_func_extended) -cmd GLint glGetProgramResourceLocationIndexEXT(ProgramId program, - GLenum programInterface, - const GLchar* name) { - _ = as!string(as!char*(name)) - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glGetProgramResourcefvNV(ProgramId program, - GLenum programInterface, - GLuint index, - GLsizei propCount, - const GLenum* props, - GLsizei bufSize, - GLsizei* length, - GLfloat* params) { - // TODO -} - -@if(Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -cmd void glGetQueryObjecti64vEXT(QueryId query, GLenum parameter, GLint64* value) { - - value[0] = ? -} - -@if(Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -cmd void glGetQueryObjectivEXT(QueryId query, GLenum parameter, GLint* value) { - - value[0] = ? -} - -@if(Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -cmd void glGetQueryObjectui64vEXT(QueryId query, GLenum parameter, GLuint64* value) { - - value[0] = ? -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glGetQueryObjectuivEXT(QueryId query, GLenum parameter, GLuint* value) { - - value[0] = ? -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd void glGetQueryivEXT(GLenum target, GLenum parameter, GLint* value) { - - value[0] = ? -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glGetSamplerParameterIivOES(SamplerId sampler, GLenum pname, GLint* params) { - GetSamplerParameterIiv(sampler, pname, params) -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glGetSamplerParameterIuivOES(SamplerId sampler, GLenum pname, GLuint* params) { - GetSamplerParameterIuiv(sampler, pname, params) -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd void glGetSyncivAPPLE(GLsync sync, - GLenum pname, - GLsizei bufSize, - GLsizei* length, - GLint* values) { - GetSynciv(sync, pname, bufSize, length, values) -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glGetTexParameterIivOES(GLenum target, GLenum pname, GLint* params) { - GetTexParameterIiv(target, pname, params) -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glGetTexParameterIuivOES(GLenum target, GLenum pname, GLuint* params) { - GetTexParameterIuiv(target, pname, params) -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd GLuint64 glGetTextureHandleNV(TextureId texture) { - // TODO - return ? -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd GLuint64 glGetTextureSamplerHandleNV(TextureId texture, SamplerId sampler) { - // TODO - return ? -} - -@if(Extension.GL_ANGLE_translated_shader_source) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_translated_shader_source.txt", Extension.GL_ANGLE_translated_shader_source) -cmd void glGetTranslatedShaderSourceANGLE(ShaderId shader, - GLsizei bufsize, - GLsizei* length, - GLchar* source) { - // TODO -} - -@if(Extension.GL_EXT_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_robustness.txt", Extension.GL_EXT_robustness) -cmd void glGetnUniformfvEXT(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLfloat* params) { - // TODO -} - -@if(Extension.GL_KHR_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_robustness.txt", Extension.GL_KHR_robustness) -cmd void glGetnUniformfvKHR(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLfloat* params) { - GetnUniformfv!GLfloat*(program, location, bufSize, params) -} - -@if(Extension.GL_EXT_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_robustness.txt", Extension.GL_EXT_robustness) -cmd void glGetnUniformivEXT(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLint* params) { - // TODO -} - -@if(Extension.GL_KHR_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_robustness.txt", Extension.GL_KHR_robustness) -cmd void glGetnUniformivKHR(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLint* params) { - GetnUniformiv(program, location, bufSize, params) -} - -@if(Extension.GL_KHR_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_robustness.txt", Extension.GL_KHR_robustness) -cmd void glGetnUniformuivKHR(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLuint* params) { - GetnUniformuiv(program, location, bufSize, params) -} - -@if(Extension.GL_EXT_debug_marker) -@user_marker -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_debug_marker.txt", Extension.GL_EXT_debug_marker) -cmd void glInsertEventMarkerEXT(GLsizei length, const GLchar* marker) { - - if length > 0 { - read(marker[0:length]) - } else { - // TODO: Remove the extra cast. - _ = as!string(as!char*(marker)) - } -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glInterpolatePathsNV(GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd GLboolean glIsEnablediNV(GLenum target, GLuint index) { - return IsEnabledi(target, index) -} - -@if(Extension.GL_OES_draw_buffers_indexed || Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_buffers_indexed.txt", Extension.GL_OES_draw_buffers_indexed) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd GLboolean glIsEnablediOES(GLenum target, GLuint index) { - return IsEnabledi(target, index) -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd GLboolean glIsFenceNV(GLuint fence) { - // TODO - return ? -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd GLboolean glIsImageHandleResidentNV(GLuint64 handle) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLboolean glIsPathNV(GLuint path) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLboolean glIsPointInFillPathNV(GLuint path, GLuint mask, GLfloat x, GLfloat y) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLboolean glIsPointInStrokePathNV(GLuint path, GLfloat x, GLfloat y) { - // TODO - return ? -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd GLboolean glIsProgramPipelineEXT(PipelineId pipeline) { - // TODO - return ? -} - -@if(Extension.GL_EXT_disjoint_timer_query || Extension.GL_EXT_occlusion_query_boolean) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_occlusion_query_boolean.txt", Extension.GL_EXT_occlusion_query_boolean) -cmd GLboolean glIsQueryEXT(QueryId query) { - - ctx := GetContext() - return toGLboolean(query in ctx.Objects.Queries) -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd GLboolean glIsSyncAPPLE(GLsync sync) { - return IsSync(sync) -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd GLboolean glIsTextureHandleResidentNV(GLuint64 handle) { - // TODO - return ? -} - -@if(Extension.GL_OES_vertex_array_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt", Extension.GL_OES_vertex_array_object) -cmd GLboolean glIsVertexArrayOES(VertexArrayId array) { - return IsVertexArray(array) -} - -@if(Extension.GL_EXT_debug_label) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_debug_label.txt", Extension.GL_EXT_debug_label) -cmd void glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar* label) { - - // GL_EXT_debug_label has different string semantics, even different from glObjectLabel - str := switch label != null { - case true: - switch length == 0 { - case true: - // Zero length implies null-terminated string - as!string(as!char*(label)) - case false: - as!string(as!char[](label[0:length])) - } - case false: - as!string(null) - } - - ctx := GetContext() - switch (type) { - case GL_TEXTURE: { - if !(as!TextureId(object) in ctx.Objects.Textures) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Textures[as!TextureId(object)].Label = str - } - case GL_FRAMEBUFFER: { - if !(as!FramebufferId(object) in ctx.Objects.Framebuffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Framebuffers[as!FramebufferId(object)].Label = str - } - case GL_RENDERBUFFER: { - if !(as!RenderbufferId(object) in ctx.Objects.Renderbuffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Renderbuffers[as!RenderbufferId(object)].Label = str - } - case GL_BUFFER_OBJECT_EXT: { - if !(as!BufferId(object) in ctx.Objects.Buffers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Buffers[as!BufferId(object)].Label = str - } - case GL_SHADER_OBJECT_EXT: { - if !(as!ShaderId(object) in ctx.Objects.Shaders) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Shaders[as!ShaderId(object)].Label = str - } - case GL_PROGRAM_OBJECT_EXT: { - if !(as!ProgramId(object) in ctx.Objects.Programs) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Programs[as!ProgramId(object)].Label = str - } - case GL_VERTEX_ARRAY_OBJECT_EXT: { - if !(as!VertexArrayId(object) in ctx.Objects.VertexArrays) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.VertexArrays[as!VertexArrayId(object)].Label = str - } - case GL_QUERY_OBJECT_EXT: { - if !(as!QueryId(object) in ctx.Objects.Queries) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Queries[as!QueryId(object)].Label = str - } - case GL_SAMPLER: { - if !(as!SamplerId(object) in ctx.Objects.Samplers) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Samplers[as!SamplerId(object)].Label = str - } - case GL_TRANSFORM_FEEDBACK: { - if !(as!TransformFeedbackId(object) in ctx.Objects.TransformFeedbacks) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.TransformFeedbacks[as!TransformFeedbackId(object)].Label = str - } - case GL_PROGRAM_PIPELINE_OBJECT_EXT: { - if !(as!PipelineId(object) in ctx.Objects.Pipelines) { - glErrorInvalidOperation_ObjectDoesNotExist!GLuint(object) - } - ctx.Objects.Pipelines[as!PipelineId(object)].Label = str - } - default: { - glErrorInvalidEnum(type) - } - } -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glMakeImageHandleNonResidentNV(GLuint64 handle) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glMakeImageHandleResidentNV(GLuint64 handle, GLenum access) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glMakeTextureHandleNonResidentNV(GLuint64 handle) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glMakeTextureHandleResidentNV(GLuint64 handle) { - // TODO -} - -@if(Extension.GL_OES_mapbuffer) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt", Extension.GL_OES_mapbuffer) -cmd void* glMapBufferOES(GLenum target, GLenum access) { - ptr := ? - MapBuffer(target, access, as!u8*(ptr)) - return ptr -} - -@if(Extension.GL_EXT_map_buffer_range) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_map_buffer_range.txt", Extension.GL_EXT_map_buffer_range) -cmd void* glMapBufferRangeEXT(GLenum target, - GLintptr offset, - GLsizeiptr length, - GLbitfield access) { - ptr := ? - MapBufferRange(target, offset, length, access, as!u8*(ptr)) - return ptr -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixLoad3x2fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixLoad3x3fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixLoadTranspose3x3fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixMult3x2fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixMult3x3fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glMatrixMultTranspose3x3fNV(GLenum matrixMode, const GLfloat* m) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixLoadfEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixLoaddEXT(GLenum matrixMode, const f64 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixMultfEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixMultdEXT(GLenum matrixMode, const f64 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixLoadTransposefEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixLoadTransposedEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixMultTransposefEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixMultTransposedEXT(GLenum matrixMode, const f32 *m) { - read(m[0:16]) // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixLoadIdentityEXT(GLenum matrixMode) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixRotatefEXT(GLenum matrixMode, f32 angle, f32 x, f32 y, f32 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixRotatedEXT(GLenum matrixMode, f64 angle, f64 x, f64 y, f64 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixScalefEXT(GLenum matrixMode, f32 x, f32 y, f32 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixScaledEXT(GLenum matrixMode, f64 x, f64 y, f64 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixTranslatefEXT(GLenum matrixMode, f32 x, f32 y, f32 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixTranslatedEXT(GLenum matrixMode, f64 x, f64 y, f64 z) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixOrthoEXT(GLenum matrixMode, f64 l, f64 r, f64 b, f64 t, f64 n, f64 f) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixFrustumEXT(GLenum matrixMode, f64 l, f64 r, f64 b, f64 t, f64 n, f64 f) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixPushEXT(GLenum matrixMode) { - // TODO -} - -@if(Extension.GL_EXT_direct_state_access) -@doc("https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_direct_state_access.txt", Extension.GL_EXT_direct_state_access) -cmd void MatrixPopEXT(GLenum matrixMode) { - // TODO -} - -@if(Extension.GL_EXT_multi_draw_arrays) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multi_draw_arrays.txt", Extension.GL_EXT_multi_draw_arrays) -cmd void glMultiDrawArraysEXT(GLenum mode, - const GLint* first, - const GLsizei* count, - GLsizei primcount) { - // TODO -} - -@if(Extension.GL_EXT_multi_draw_indirect) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multi_draw_indirect.txt", Extension.GL_EXT_multi_draw_indirect) -cmd void glMultiDrawArraysIndirectEXT(GLenum mode, - const void* indirect, - GLsizei drawcount, - GLsizei stride) { - // TODO -} - -@if(Extension.GL_EXT_draw_elements_base_vertex) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_elements_base_vertex.txt", Extension.GL_EXT_draw_elements_base_vertex) -cmd void glMultiDrawElementsBaseVertexEXT(GLenum mode, - const GLsizei* count, - GLenum type, - const void* const* indices, - GLsizei primcount, - const GLint* basevertex) { - // TODO -} - -@if(Extension.GL_OES_draw_elements_base_vertex) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_elements_base_vertex.txt", Extension.GL_OES_draw_elements_base_vertex) -cmd void glMultiDrawElementsBaseVertexOES(GLenum mode, - const GLsizei* count, - GLenum type, - const void* const* indices, - GLsizei primcount, - const GLint* basevertex) { - // TODO -} - -@if(Extension.GL_EXT_multi_draw_arrays) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multi_draw_arrays.txt", Extension.GL_EXT_multi_draw_arrays) -cmd void glMultiDrawElementsEXT(GLenum mode, - const GLsizei* count, - GLenum type, - const void* const* indices, - GLsizei primcount) { - // TODO -} - -@if(Extension.GL_EXT_multi_draw_indirect) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multi_draw_indirect.txt", Extension.GL_EXT_multi_draw_indirect) -cmd void glMultiDrawElementsIndirectEXT(GLenum mode, - GLenum type, - const void* indirect, - GLsizei drawcount, - GLsizei stride) { - // TODO -} - -@if(Extension.GL_NV_sample_locations) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_sample_locations.txt", Extension.GL_NV_sample_locations) -cmd void glNamedFramebufferSampleLocationsfvNV(FramebufferId framebuffer, - GLuint start, - GLsizei count, - const GLfloat* v) { - // TODO -} - -@if(Extension.GL_OES_tessellation_shader) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_tessellation_shader.txt", Extension.GL_OES_tessellation_shader) -cmd void glPatchParameteriOES(GLenum pname, GLint value) { - PatchParameteri(pname, value) -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathCommandsNV(GLuint path, - GLsizei numCommands, - const GLubyte* commands, - GLsizei numCoords, - GLenum coordType, - const void* coords) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathCoordsNV(GLuint path, GLsizei numCoords, GLenum coordType, const void* coords) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathCoverDepthFuncNV(GLenum func) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathDashArrayNV(GLuint path, GLsizei dashCount, const GLfloat* dashArray) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLenum glPathGlyphIndexArrayNV(GLuint firstPathName, - GLenum fontTarget, - const void* fontName, - GLbitfield fontStyle, - GLuint firstGlyphIndex, - GLsizei numGlyphs, - GLuint pathParameterTemplate, - GLfloat emScale) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLenum glPathGlyphIndexRangeNV(GLenum fontTarget, - const void* fontName, - GLbitfield fontStyle, - GLuint pathParameterTemplate, - GLfloat emScale, - GLuint baseAndCount) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathGlyphRangeNV(GLuint firstPathName, - GLenum fontTarget, - const void* fontName, - GLbitfield fontStyle, - GLuint firstGlyph, - GLsizei numGlyphs, - GLenum handleMissingGlyphs, - GLuint pathParameterTemplate, - GLfloat emScale) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathGlyphsNV(GLuint firstPathName, - GLenum fontTarget, - const void* fontName, - GLbitfield fontStyle, - GLsizei numGlyphs, - GLenum type, - const void* charcodes, - GLenum handleMissingGlyphs, - GLuint pathParameterTemplate, - GLfloat emScale) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLenum glPathMemoryGlyphIndexArrayNV(GLuint firstPathName, - GLenum fontTarget, - GLsizeiptr fontSize, - const void* fontData, - GLsizei faceIndex, - GLuint firstGlyphIndex, - GLsizei numGlyphs, - GLuint pathParameterTemplate, - GLfloat emScale) { - // TODO - return ? -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathParameterfNV(GLuint path, GLenum pname, GLfloat value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathParameterfvNV(GLuint path, GLenum pname, const GLfloat* value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathParameteriNV(GLuint path, GLenum pname, GLint value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathParameterivNV(GLuint path, GLenum pname, const GLint* value) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathStencilDepthOffsetNV(GLfloat factor, GLfloat units) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathStencilFuncNV(GLenum func, GLint ref, GLuint mask) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathStringNV(GLuint path, GLenum format, GLsizei length, const void* pathString) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathSubCommandsNV(GLuint path, - GLsizei commandStart, - GLsizei commandsToDelete, - GLsizei numCommands, - const GLubyte* commands, - GLsizei numCoords, - GLenum coordType, - const void* coords) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glPathSubCoordsNV(GLuint path, - GLsizei coordStart, - GLsizei numCoords, - GLenum coordType, - const void* coords) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd GLboolean glPointAlongPathNV(GLuint path, - GLsizei startSegment, - GLsizei numSegments, - GLfloat distance, - GLfloat* x, - GLfloat* y, - GLfloat* tangentX, - GLfloat* tangentY) { - // TODO - return ? -} - -@if(Extension.GL_NV_polygon_mode) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_polygon_mode.txt", Extension.GL_NV_polygon_mode) -cmd void glPolygonModeNV(GLenum face, GLenum mode) { - // TODO -} - -@if(Extension.GL_EXT_debug_marker) -@pop_user_marker -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_debug_marker.txt", Extension.GL_EXT_debug_marker) -cmd void glPopGroupMarkerEXT() { -} - -@if(Extension.GL_OES_primitive_bounding_box) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_primitive_bounding_box.txt", Extension.GL_OES_primitive_bounding_box) -cmd void glPrimitiveBoundingBoxOES(GLfloat minX, - GLfloat minY, - GLfloat minZ, - GLfloat minW, - GLfloat maxX, - GLfloat maxY, - GLfloat maxZ, - GLfloat maxW) { - PrimitiveBoundingBox(minX, minY, minZ, minW, maxX, maxY, maxZ, maxW) -} - -@if(Extension.GL_OES_get_program_binary) -@custom -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_get_program_binary.txt", Extension.GL_OES_get_program_binary) -cmd void glProgramBinaryOES(ProgramId program, - GLenum binary_format, - const void* binary, - GLint binary_size) { - // TODO: spec - 'binary_size' changed type - ProgramBinary(program, binary_format, binary, as!GLsizei(binary_size)) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramParameteriEXT(ProgramId program, GLenum pname, GLint value) { - ProgramParameteri(program, pname, value) -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glProgramPathFragmentInputGenNV(ProgramId program, - GLint location, - GLenum genMode, - GLint components, - const GLfloat* coeffs) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1fEXT(ProgramId program, UniformLocation location, GLfloat v0) { - ProgramUniform1f(program, location, v0) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* value) { - ProgramUniform1fv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1iEXT(ProgramId program, UniformLocation location, GLint v0) { - ProgramUniform1i(program, location, v0) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1ivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* value) { - ProgramUniform1iv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1uiEXT(ProgramId program, UniformLocation location, GLuint v0) { - ProgramUniform1ui(program, location, v0) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform1uivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* value) { - ProgramUniform1uiv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2fEXT(ProgramId program, - UniformLocation location, - GLfloat v0, - GLfloat v1) { - ProgramUniform2f(program, location, v0, v1) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* value) { - ProgramUniform2fv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2iEXT(ProgramId program, UniformLocation location, GLint v0, GLint v1) { - ProgramUniform2i(program, location, v0, v1) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2ivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* value) { - ProgramUniform2iv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2uiEXT(ProgramId program, UniformLocation location, GLuint v0, GLuint v1) { - ProgramUniform2ui(program, location, v0, v1) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform2uivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* value) { - ProgramUniform2uiv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3fEXT(ProgramId program, - UniformLocation location, - GLfloat v0, - GLfloat v1, - GLfloat v2) { - ProgramUniform3f(program, location, v0, v1, v2) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* value) { - ProgramUniform3fv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3iEXT(ProgramId program, - UniformLocation location, - GLint v0, - GLint v1, - GLint v2) { - ProgramUniform3i(program, location, v0, v1, v2) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3ivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* value) { - ProgramUniform3iv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3uiEXT(ProgramId program, - UniformLocation location, - GLuint v0, - GLuint v1, - GLuint v2) { - ProgramUniform3ui(program, location, v0, v1, v2) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform3uivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* value) { - ProgramUniform3uiv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4fEXT(ProgramId program, - UniformLocation location, - GLfloat v0, - GLfloat v1, - GLfloat v2, - GLfloat v3) { - ProgramUniform4f(program, location, v0, v1, v2, v3) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* value) { - ProgramUniform4fv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4iEXT(ProgramId program, - UniformLocation location, - GLint v0, - GLint v1, - GLint v2, - GLint v3) { - ProgramUniform4i(program, location, v0, v1, v2, v3) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4ivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* value) { - ProgramUniform4iv(program, location, count, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4uiEXT(ProgramId program, - UniformLocation location, - GLuint v0, - GLuint v1, - GLuint v2, - GLuint v3) { - ProgramUniform4ui(program, location, v0, v1, v2, v3) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniform4uivEXT(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* value) { - ProgramUniform4uiv(program, location, count, value) -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glProgramUniformHandleui64NV(ProgramId program, UniformLocation location, GLuint64 value) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glProgramUniformHandleui64vNV(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint64* values) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix2fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix2fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix2x3fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix2x3fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix2x4fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix2x4fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix3fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix3fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix3x2fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix3x2fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix3x4fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix3x4fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix4fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix4fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix4x2fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix4x2fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glProgramUniformMatrix4x3fvEXT(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - ProgramUniformMatrix4x3fv(program, location, count, transpose, value) -} - -@if(Extension.GL_EXT_debug_marker) -@push_user_marker -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_debug_marker.txt", Extension.GL_EXT_debug_marker) -cmd void glPushGroupMarkerEXT(GLsizei length, const GLchar* marker) { - if length > 0 { - read(marker[0:length]) - } else { - _ = as!string(as!char*(marker)) - } -} - -@if(Extension.GL_EXT_disjoint_timer_query) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt", Extension.GL_EXT_disjoint_timer_query) -cmd void glQueryCounterEXT(QueryId query, GLenum target) { - -} - -@if(Extension.GL_EXT_raster_multisample || Extension.GL_EXT_texture_filter_minmax || Extension.GL_NV_framebuffer_mixed_samples) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_raster_multisample.txt", Extension.GL_EXT_raster_multisample) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_filter_minmax.txt", Extension.GL_EXT_texture_filter_minmax) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_mixed_samples.txt", Extension.GL_NV_framebuffer_mixed_samples) -cmd void glRasterSamplesEXT(GLuint samples, GLboolean fixedsamplelocations) { - // TODO -} - -@if(Extension.GL_EXT_multiview_draw_buffers) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multiview_draw_buffers.txt", Extension.GL_EXT_multiview_draw_buffers) -cmd void glReadBufferIndexedEXT(GLenum src, GLint index) { - // TODO -} - -@if(Extension.GL_NV_read_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_read_buffer.txt", Extension.GL_NV_read_buffer) -cmd void glReadBufferNV(GLenum mode) { - // TODO -} - -@if(Extension.GL_EXT_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_robustness.txt", Extension.GL_EXT_robustness) -cmd void glReadnPixelsEXT(GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLsizei bufSize, - void* data) { - ReadnPixels(x, y, width, height, format, type, bufSize, data) -} - -@if(Extension.GL_KHR_robustness) -@doc("https://www.khronos.org/registry/gles/extensions/KHR/KHR_robustness.txt", Extension.GL_KHR_robustness) -cmd void glReadnPixelsKHR(GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLsizei bufSize, - void* data) { - ReadnPixels(x, y, width, height, format, type, bufSize, data) -} - -@if(Extension.GL_ANGLE_framebuffer_multisample) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_framebuffer_multisample.txt", Extension.GL_ANGLE_framebuffer_multisample) -cmd void glRenderbufferStorageMultisampleANGLE(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - // TODO -} - -@if(Extension.GL_APPLE_framebuffer_multisample) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_framebuffer_multisample.txt", Extension.GL_APPLE_framebuffer_multisample) -cmd void glRenderbufferStorageMultisampleAPPLE(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - // TODO -} - -@if(Extension.GL_EXT_multisampled_render_to_texture) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_multisampled_render_to_texture.txt", Extension.GL_EXT_multisampled_render_to_texture) -cmd void glRenderbufferStorageMultisampleEXT(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - RenderbufferStorageMultisample(target, samples, internalformat, width, height) -} - -@if(Extension.GL_IMG_multisampled_render_to_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_multisampled_render_to_texture.txt", Extension.GL_IMG_multisampled_render_to_texture) -cmd void glRenderbufferStorageMultisampleIMG(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - // TODO -} - -@if(Extension.GL_NV_framebuffer_multisample) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_framebuffer_multisample.txt", Extension.GL_NV_framebuffer_multisample) -cmd void glRenderbufferStorageMultisampleNV(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - RenderbufferStorageMultisample(target, samples, internalformat, width, height) -} - -@if(Extension.GL_NV_sample_locations) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_sample_locations.txt", Extension.GL_NV_sample_locations) -cmd void glResolveDepthValuesNV() { - // TODO -} - -@if(Extension.GL_APPLE_framebuffer_multisample) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_framebuffer_multisample.txt", Extension.GL_APPLE_framebuffer_multisample) -cmd void glResolveMultisampleFramebufferAPPLE() { - // TODO -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glSamplerParameterIivOES(SamplerId sampler, GLenum pname, const GLint* param) { - SamplerParameterIiv(sampler, pname, param) -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glSamplerParameterIuivOES(SamplerId sampler, GLenum pname, const GLuint* param) { - SamplerParameterIuiv(sampler, pname, param) -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glScissorArrayvNV(GLuint first, GLsizei count, const GLint* v) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glScissorIndexedNV(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glScissorIndexedvNV(GLuint index, const GLint* v) { - // TODO -} - -@if(Extension.GL_AMD_performance_monitor) -@doc("https://www.khronos.org/registry/gles/extensions/AMD/AMD_performance_monitor.txt", Extension.GL_AMD_performance_monitor) -cmd void glSelectPerfMonitorCountersAMD(GLuint monitor, - GLboolean enable, - GLuint group, - GLint numCounters, - GLuint* counterList) { - // TODO -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd void glSetFenceNV(GLuint fence, GLenum condition) { - // TODO -} - -@if(Extension.GL_QCOM_tiled_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/QCOM/QCOM_tiled_rendering.txt", Extension.GL_QCOM_tiled_rendering) -cmd void glStartTilingQCOM(GLuint x, - GLuint y, - GLuint width, - GLuint height, - GLbitfield preserveMask) { - -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilFillPathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLenum fillMode, - GLuint mask, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilFillPathNV(GLuint path, GLenum fillMode, GLuint mask) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilStrokePathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLint reference, - GLuint mask, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilStrokePathNV(GLuint path, GLint reference, GLuint mask) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilThenCoverFillPathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLenum fillMode, - GLuint mask, - GLenum coverMode, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilThenCoverFillPathNV(GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilThenCoverStrokePathInstancedNV(GLsizei numPaths, - GLenum pathNameType, - const void* paths, - GLuint pathBase, - GLint reference, - GLuint mask, - GLenum coverMode, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glStencilThenCoverStrokePathNV(GLuint path, - GLint reference, - GLuint mask, - GLenum coverMode) { - // TODO -} - -@if(Extension.GL_NV_conservative_raster) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_conservative_raster.txt", Extension.GL_NV_conservative_raster) -cmd void glSubpixelPrecisionBiasNV(GLuint xbits, GLuint ybits) { - // TODO -} - -@if(Extension.GL_NV_fence) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_fence.txt", Extension.GL_NV_fence) -cmd GLboolean glTestFenceNV(GLuint fence) { - // TODO - return ? -} - -@if(Extension.GL_OES_texture_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_buffer.txt", Extension.GL_OES_texture_buffer) -cmd void glTexBufferOES(GLenum target, GLenum internalformat, BufferId buffer) { - TexBuffer(target, internalformat, buffer) -} - -@if(Extension.GL_OES_texture_buffer) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_buffer.txt", Extension.GL_OES_texture_buffer) -cmd void glTexBufferRangeOES(GLenum target, - GLenum internalformat, - BufferId buffer, - GLintptr offset, - GLsizeiptr size) { - TexBufferRange(target, internalformat, buffer, offset, size) -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glTexImage3DOES(GLenum target, - GLint level, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLint border, - GLenum format, - GLenum type, - TexturePointer pixels) { - // TODO: spec - 'internalformat' changed type - TexImage3D(target, level, as!GLint(internalformat), width, height, depth, border, format, type, pixels) -} - -@if(Extension.GL_EXT_sparse_texture) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_sparse_texture.txt", Extension.GL_EXT_sparse_texture) -cmd void glTexPageCommitmentEXT(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLboolean commit) { - // TODO -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glTexParameterIivOES(GLenum target, GLenum pname, const GLint* params) { - TexParameterIiv(target, pname, params) -} - -@if(Extension.GL_OES_texture_border_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_border_clamp.txt", Extension.GL_OES_texture_border_clamp) -cmd void glTexParameterIuivOES(GLenum target, GLenum pname, const GLuint* params) { - TexParameterIuiv(target, pname, params) -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { - -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTexStorage2DEXT(GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height) { - TexStorage2D(target, levels, internalformat, width, height) -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTexStorage3DEXT(GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth) { - TexStorage3D(target, levels, internalformat, width, height, depth) -} - -@if(Extension.GL_OES_texture_3D) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt", Extension.GL_OES_texture_3D) -cmd void glTexSubImage3DOES(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLenum format, - GLenum type, - TexturePointer pixels) { - TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTextureStorage1DEXT(TextureId texture, - GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width) { - -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTextureStorage2DEXT(TextureId texture, - GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height) { - -} - -@if(Extension.GL_EXT_texture_storage) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_storage.txt", Extension.GL_EXT_texture_storage) -cmd void glTextureStorage3DEXT(TextureId texture, - GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth) { - -} - -@if(Extension.GL_EXT_texture_view) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_view.txt", Extension.GL_EXT_texture_view) -cmd void glTextureViewEXT(TextureId texture, - GLenum target, - GLuint origtexture, - GLenum internalformat, - GLuint minlevel, - GLuint numlevels, - GLuint minlayer, - GLuint numlayers) { - // TODO -} - -@if(Extension.GL_OES_texture_view) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_view.txt", Extension.GL_OES_texture_view) -cmd void glTextureViewOES(TextureId texture, - GLenum target, - GLuint origtexture, - GLenum internalformat, - GLuint minlevel, - GLuint numlevels, - GLuint minlayer, - GLuint numlayers) { - // TODO -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glTransformPathNV(GLuint resultPath, - GLuint srcPath, - GLenum transformType, - const GLfloat* transformValues) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glUniformHandleui64NV(UniformLocation location, GLuint64 value) { - // TODO -} - -@if(Extension.GL_NV_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_bindless_texture.txt", Extension.GL_NV_bindless_texture) -cmd void glUniformHandleui64vNV(UniformLocation location, GLsizei count, const GLuint64* value) { - // TODO -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix2x3fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix2x3fv(location, count, transpose, value) -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix2x4fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix2x4fv(location, count, transpose, value) -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix3x2fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix3x2fv(location, count, transpose, value) -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix3x4fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix3x4fv(location, count, transpose, value) -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix4x2fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix4x2fv(location, count, transpose, value) -} - -@if(Extension.GL_NV_non_square_matrices) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_non_square_matrices.txt", Extension.GL_NV_non_square_matrices) -cmd void glUniformMatrix4x3fvNV(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* value) { - UniformMatrix4x3fv(location, count, transpose, value) -} - -@if(Extension.GL_OES_mapbuffer) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt", Extension.GL_OES_mapbuffer) -cmd GLboolean glUnmapBufferOES(GLenum target) { - UnmapBuffer(target) - return ? -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glUseProgramStagesEXT(PipelineId pipeline, GLbitfield stages, ProgramId program) { - // TODO -} - -@if(Extension.GL_EXT_separate_shader_objects) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_separate_shader_objects.gles.txt", Extension.GL_EXT_separate_shader_objects) -cmd void glValidateProgramPipelineEXT(PipelineId pipeline) { - // TODO -} - -@if(Extension.GL_ANGLE_instanced_arrays) -@doc("https://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt", Extension.GL_ANGLE_instanced_arrays) -cmd void glVertexAttribDivisorANGLE(AttributeLocation index, GLuint divisor) { - VertexAttribDivisor(index, divisor) -} - -@if(Extension.GL_EXT_instanced_arrays) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_instanced_arrays.txt", Extension.GL_EXT_instanced_arrays) -cmd void glVertexAttribDivisorEXT(AttributeLocation index, GLuint divisor) { - VertexAttribDivisor(index, divisor) -} - -@if(Extension.GL_NV_instanced_arrays) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_instanced_arrays.txt", Extension.GL_NV_instanced_arrays) -cmd void glVertexAttribDivisorNV(AttributeLocation index, GLuint divisor) { - VertexAttribDivisor(index, divisor) -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glViewportArrayvNV(GLuint first, GLsizei count, const GLfloat* v) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glViewportIndexedfNV(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) { - // TODO -} - -@if(Extension.GL_NV_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_array.txt", Extension.GL_NV_viewport_array) -cmd void glViewportIndexedfvNV(GLuint index, const GLfloat* v) { - // TODO -} - -@if(Extension.GL_APPLE_sync) -@doc("https://www.khronos.org/registry/gles/extensions/APPLE/APPLE_sync.txt", Extension.GL_APPLE_sync) -cmd void glWaitSyncAPPLE(GLsync sync, GLbitfield flag, GLuint64 timeout) { - WaitSync(sync, flag, timeout) -} - -@if(Extension.GL_NV_path_rendering) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_path_rendering.txt", Extension.GL_NV_path_rendering) -cmd void glWeightPathsNV(GLuint resultPath, - GLsizei numPaths, - const GLuint* paths, - const GLfloat* weights) { - // TODO -} - -@if(Extension.GL_EXT_shader_pixel_local_storage2) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_pixel_local_storage2.txt", Extension.GL_EXT_shader_pixel_local_storage2) -cmd void glClearPixelLocalStorageuiEXT(GLsizei offset, GLsizei n, const GLuint* values) { -} - -@if(Extension.GL_EXT_clear_texture) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_clear_texture.txt", Extension.GL_EXT_clear_texture) -cmd void glClearTexImageEXT(GLuint texture, GLint level, GLenum format, GLenum type, const void* data) { -} - -@if(Extension.GL_EXT_clear_texture) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_clear_texture.txt", Extension.GL_EXT_clear_texture) -cmd void glClearTexSubImageEXT(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* data) { -} - -@if(Extension.GL_NV_conservative_raster_pre_snap_triangles) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_conservative_raster_pre_snap_triangles.txt", Extension.GL_NV_conservative_raster_pre_snap_triangles) -cmd void glConservativeRasterParameteriNV(GLenum pname, GLint param) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glDepthRangeArrayfvOES(GLuint first, GLsizei count, const GLfloat* v) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glDepthRangeIndexedfOES(GLuint index, GLfloat n, GLfloat f) { -} - -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@if(Extension.GL_EXT_draw_transform_feedback) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_transform_feedback.txt", Extension.GL_EXT_draw_transform_feedback) -cmd void glDrawTransformFeedbackEXT(GLenum mode, GLuint id) { -} - -@draw_call(isDrawCall()) -@transform_feedback(isTransformFeedback()) -@if(Extension.GL_EXT_draw_transform_feedback) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_draw_transform_feedback.txt", Extension.GL_EXT_draw_transform_feedback) -cmd void glDrawTransformFeedbackInstancedEXT(GLenum mode, GLuint id, GLsizei instancecount) { -} - -@if(Extension.GL_EXT_shader_pixel_local_storage2) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_pixel_local_storage2.txt", Extension.GL_EXT_shader_pixel_local_storage2) -cmd void glFramebufferPixelLocalStorageSizeEXT(GLuint target, GLsizei size) { -} - -@if(Extension.GL_IMG_framebuffer_downsample) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_framebuffer_downsample.txt", Extension.GL_IMG_framebuffer_downsample) -cmd void glFramebufferTexture2DDownsampleIMG(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint xscale, GLint yscale) { -} - -@if(Extension.GL_IMG_framebuffer_downsample) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_framebuffer_downsample.txt", Extension.GL_IMG_framebuffer_downsample) -cmd void glFramebufferTextureLayerDownsampleIMG(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer, GLint xscale, GLint yscale) { -} - -@if(Extension.GL_OVR_multiview_multisampled_render_to_texture) -@doc("https://www.khronos.org/registry/gles/extensions/OVR/OVR_multiview_multisampled_render_to_texture.txt", Extension.GL_OVR_multiview_multisampled_render_to_texture) -cmd void glFramebufferTextureMultisampleMultiviewOVR(GLenum target, GLenum attachment, TextureId texture, GLint level, GLsizei samples, GLint baseViewIndex, GLsizei numViews) { - // TODO: Handle the multi-sampling instead of ignoring it. - FramebufferTextureMultiviewOVR(target, attachment, texture, level, baseViewIndex, numViews) -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glGetFloati_vOES(GLenum target, GLuint index, GLfloat* data) { -} - -@if(Extension.GL_EXT_shader_pixel_local_storage2) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_pixel_local_storage2.txt", Extension.GL_EXT_shader_pixel_local_storage2) -cmd GLsizei glGetFramebufferPixelLocalStorageSizeEXT(GLuint target) { - return ? -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd GLuint64 glGetTextureHandleIMG(GLuint texture) { - return ? -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd GLuint64 glGetTextureSamplerHandleIMG(GLuint texture, GLuint sampler) { - return ? -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glGetUniformi64vNV(GLuint program, GLint location, GLint64EXT* params) { -} - -@if(Extension.GL_EXT_polygon_offset_clamp) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_polygon_offset_clamp.txt", Extension.GL_EXT_polygon_offset_clamp) -cmd void glPolygonOffsetClampEXT(GLfloat factor, GLfloat units, GLfloat clamp) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform1i64NV(GLuint program, GLint location, GLint64EXT x) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform1i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform1ui64NV(GLuint program, GLint location, GLuint64EXT x) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform1ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform2i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform2i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform2ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform2ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform3i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform3i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform3ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform3ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform4i64NV(GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform4i64vNV(GLuint program, GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform4ui64NV(GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glProgramUniform4ui64vNV(GLuint program, GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd void glProgramUniformHandleui64IMG(GLuint program, GLint location, GLuint64 value) { -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd void glProgramUniformHandleui64vIMG(GLuint program, GLint location, GLsizei count, const GLuint64* values) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glScissorArrayvOES(GLuint first, GLsizei count, const GLint* v) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glScissorIndexedOES(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glScissorIndexedvOES(GLuint index, const GLint* v) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform1i64NV(GLint location, GLint64EXT x) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform1i64vNV(GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform1ui64NV(GLint location, GLuint64EXT x) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform1ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform2i64NV(GLint location, GLint64EXT x, GLint64EXT y) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform2i64vNV(GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform2ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform2ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform3i64NV(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform3i64vNV(GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform3ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform3ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform4i64NV(GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform4i64vNV(GLint location, GLsizei count, const GLint64EXT* value) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform4ui64NV(GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w) { -} - -@if(Extension.GL_NV_gpu_shader5) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_gpu_shader5.txt", Extension.GL_NV_gpu_shader5) -cmd void glUniform4ui64vNV(GLint location, GLsizei count, const GLuint64EXT* value) { -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd void glUniformHandleui64IMG(GLint location, GLuint64 value) { -} - -@if(Extension.GL_IMG_bindless_texture) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_bindless_texture.txt", Extension.GL_IMG_bindless_texture) -cmd void glUniformHandleui64vIMG(GLint location, GLsizei count, const GLuint64* value) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glViewportArrayvOES(GLuint first, GLsizei count, const GLfloat* v) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glViewportIndexedfOES(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) { -} - -@if(Extension.GL_OES_viewport_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_viewport_array.txt", Extension.GL_OES_viewport_array) -cmd void glViewportIndexedfvOES(GLuint index, const GLfloat* v) { -} - -@if(Extension.GL_NV_viewport_swizzle) -@doc("https://www.khronos.org/registry/gles/extensions/NV/NV_viewport_swizzle.txt", Extension.GL_NV_viewport_swizzle) -cmd void glViewportSwizzleNV(GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew) { -} - -@if(Extension.GL_EXT_window_rectangles) -@doc("https://www.khronos.org/registry/gles/extensions/EXT/EXT_window_rectangles.txt", Extension.GL_EXT_window_rectangles) -cmd void glWindowRectanglesEXT(GLenum mode, GLsizei count, const GLint* box) { -} diff --git a/gapis/api/gles/api/extras.api b/gapis/api/gles/api/extras.api deleted file mode 100644 index 6e00cd89df..0000000000 --- a/gapis/api/gles/api/extras.api +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// StaticContextState is an command extra used to describe a context's non-changing state. -@internal -class StaticContextState { - Constants Constants - string ThreadName -} - -@post_fence -extern ref!StaticContextState GetEGLStaticContextState(EGLDisplay display, EGLContext context) - -// DynamicContextState is an command extra used to describe a context's potentially changing state. -@internal -class DynamicContextState { - GLsizei BackbufferWidth - GLsizei BackbufferHeight - GLenum BackbufferColorFmt - GLenum BackbufferDepthFmt - GLenum BackbufferStencilFmt - bool PreserveBuffersOnSwap - // TODO: Currently unused - @unused GLuint RedSize - @unused GLuint GreenSize - @unused GLuint BlueSize - @unused GLuint AlphaSize - @unused GLuint DepthSize - @unused GLuint StencilSize -} - -@post_fence -extern ref!DynamicContextState GetEGLDynamicContextState(EGLDisplay display, EGLSurface surface, EGLContext context) - - -@internal -class UniformTypeInfo { - // The total size is: primitiveSize * vectorSize * vectorCount - u32 primitiveSize // Size of primitive type in bytes. - u32 vectorSize // Number of primitives in a vector. Numbers of columns for matrix. - u32 vectorCount // Always 1 for all non-matrix types. Numbers of rows for matrix. -} - -// GetUniformTypeInfo returns information about given unifrom type. -sub UniformTypeInfo GetUniformTypeInfo(GLenum ty) { - return switch ty { - case GL_FLOAT: UniformTypeInfo(4, 1, 1) - case GL_FLOAT_VEC2: UniformTypeInfo(4, 2, 1) - case GL_FLOAT_VEC3: UniformTypeInfo(4, 3, 1) - case GL_FLOAT_VEC4: UniformTypeInfo(4, 4, 1) - case GL_DOUBLE: UniformTypeInfo(8, 1, 1) - case GL_DOUBLE_VEC2: UniformTypeInfo(8, 2, 1) - case GL_DOUBLE_VEC3: UniformTypeInfo(8, 3, 1) - case GL_DOUBLE_VEC4: UniformTypeInfo(8, 4, 1) - case GL_INT: UniformTypeInfo(4, 1, 1) - case GL_INT_VEC2: UniformTypeInfo(4, 2, 1) - case GL_INT_VEC3: UniformTypeInfo(4, 3, 1) - case GL_INT_VEC4: UniformTypeInfo(4, 4, 1) - case GL_UNSIGNED_INT: UniformTypeInfo(4, 1, 1) - case GL_UNSIGNED_INT_VEC2: UniformTypeInfo(4, 2, 1) - case GL_UNSIGNED_INT_VEC3: UniformTypeInfo(4, 3, 1) - case GL_UNSIGNED_INT_VEC4: UniformTypeInfo(4, 4, 1) - case GL_BOOL: UniformTypeInfo(4, 1, 1) - case GL_BOOL_VEC2: UniformTypeInfo(4, 2, 1) - case GL_BOOL_VEC3: UniformTypeInfo(4, 3, 1) - case GL_BOOL_VEC4: UniformTypeInfo(4, 4, 1) - case GL_FLOAT_MAT2: UniformTypeInfo(4, 2, 2) - case GL_FLOAT_MAT3: UniformTypeInfo(4, 3, 3) - case GL_FLOAT_MAT4: UniformTypeInfo(4, 4, 4) - case GL_FLOAT_MAT2x3: UniformTypeInfo(4, 2, 3) - case GL_FLOAT_MAT2x4: UniformTypeInfo(4, 2, 4) - case GL_FLOAT_MAT3x2: UniformTypeInfo(4, 3, 2) - case GL_FLOAT_MAT3x4: UniformTypeInfo(4, 3, 4) - case GL_FLOAT_MAT4x2: UniformTypeInfo(4, 4, 2) - case GL_FLOAT_MAT4x3: UniformTypeInfo(4, 4, 3) - case GL_DOUBLE_MAT2: UniformTypeInfo(8, 2, 2) - case GL_DOUBLE_MAT3: UniformTypeInfo(8, 3, 3) - case GL_DOUBLE_MAT4: UniformTypeInfo(8, 4, 4) - case GL_DOUBLE_MAT2x3: UniformTypeInfo(8, 2, 3) - case GL_DOUBLE_MAT2x4: UniformTypeInfo(8, 2, 4) - case GL_DOUBLE_MAT3x2: UniformTypeInfo(8, 3, 2) - case GL_DOUBLE_MAT3x4: UniformTypeInfo(8, 3, 4) - case GL_DOUBLE_MAT4x2: UniformTypeInfo(8, 4, 2) - case GL_DOUBLE_MAT4x3: UniformTypeInfo(8, 4, 3) - - case GL_SAMPLER_1D, - GL_SAMPLER_2D, - GL_SAMPLER_3D, - GL_SAMPLER_CUBE, - GL_SAMPLER_1D_SHADOW, - GL_SAMPLER_2D_SHADOW, - GL_SAMPLER_1D_ARRAY, - GL_SAMPLER_2D_ARRAY, - GL_SAMPLER_1D_ARRAY_SHADOW, - GL_SAMPLER_2D_ARRAY_SHADOW, - GL_SAMPLER_2D_MULTISAMPLE, - GL_SAMPLER_2D_MULTISAMPLE_ARRAY, - GL_SAMPLER_CUBE_SHADOW, - GL_SAMPLER_BUFFER, - GL_SAMPLER_2D_RECT, - GL_SAMPLER_2D_RECT_SHADOW, - GL_INT_SAMPLER_1D, - GL_INT_SAMPLER_2D, - GL_INT_SAMPLER_3D, - GL_INT_SAMPLER_CUBE, - GL_INT_SAMPLER_1D_ARRAY, - GL_INT_SAMPLER_2D_ARRAY, - GL_INT_SAMPLER_2D_MULTISAMPLE, - GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, - GL_INT_SAMPLER_BUFFER, - GL_INT_SAMPLER_2D_RECT, - GL_UNSIGNED_INT_SAMPLER_1D, - GL_UNSIGNED_INT_SAMPLER_2D, - GL_UNSIGNED_INT_SAMPLER_3D, - GL_UNSIGNED_INT_SAMPLER_CUBE, - GL_UNSIGNED_INT_SAMPLER_1D_ARRAY, - GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, - GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE, - GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, - GL_UNSIGNED_INT_SAMPLER_BUFFER, - GL_UNSIGNED_INT_SAMPLER_2D_RECT, - GL_IMAGE_1D, - GL_IMAGE_2D, - GL_IMAGE_3D, - GL_IMAGE_2D_RECT, - GL_IMAGE_CUBE, - GL_IMAGE_BUFFER, - GL_IMAGE_1D_ARRAY, - GL_IMAGE_2D_ARRAY, - GL_IMAGE_2D_MULTISAMPLE, - GL_IMAGE_2D_MULTISAMPLE_ARRAY, - GL_INT_IMAGE_1D, - GL_INT_IMAGE_2D, - GL_INT_IMAGE_3D, - GL_INT_IMAGE_2D_RECT, - GL_INT_IMAGE_CUBE, - GL_INT_IMAGE_BUFFER, - GL_INT_IMAGE_1D_ARRAY, - GL_INT_IMAGE_2D_ARRAY, - GL_INT_IMAGE_2D_MULTISAMPLE, - GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY, - GL_UNSIGNED_INT_IMAGE_1D, - GL_UNSIGNED_INT_IMAGE_2D, - GL_UNSIGNED_INT_IMAGE_3D, - GL_UNSIGNED_INT_IMAGE_2D_RECT, - GL_UNSIGNED_INT_IMAGE_CUBE, - GL_UNSIGNED_INT_IMAGE_BUFFER, - GL_UNSIGNED_INT_IMAGE_1D_ARRAY, - GL_UNSIGNED_INT_IMAGE_2D_ARRAY, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY, - GL_UNSIGNED_INT_ATOMIC_COUNTER, - GL_SAMPLER_EXTERNAL_OES: - UniformTypeInfo(4, 1, 1) - default: - UniformTypeInfo() - } -} - -// hintAtAttributeType simply return the single argument unaltered. -// It is used to add enum name hint information for static analysis. -sub GLenum hintAtAttributeType(GLenum ty) { - return switch ty { - case GL_FLOAT, - GL_FLOAT_VEC2, - GL_FLOAT_VEC3, - GL_FLOAT_VEC4, - GL_FLOAT_MAT2, - GL_FLOAT_MAT3, - GL_FLOAT_MAT4, - GL_FLOAT_MAT2x3, - GL_FLOAT_MAT2x4, - GL_FLOAT_MAT3x2, - GL_FLOAT_MAT3x4, - GL_FLOAT_MAT4x2, - GL_FLOAT_MAT4x3, - GL_INT, - GL_INT_VEC2, - GL_INT_VEC3, - GL_INT_VEC4, - GL_UNSIGNED_INT, - GL_UNSIGNED_INT_VEC2, - GL_UNSIGNED_INT_VEC3, - GL_UNSIGNED_INT_VEC4, - GL_DOUBLE, - GL_DOUBLE_VEC2, - GL_DOUBLE_VEC3, - GL_DOUBLE_VEC4, - GL_DOUBLE_MAT2, - GL_DOUBLE_MAT3, - GL_DOUBLE_MAT4, - GL_DOUBLE_MAT2x3, - GL_DOUBLE_MAT2x4, - GL_DOUBLE_MAT3x2, - GL_DOUBLE_MAT3x4, - GL_DOUBLE_MAT4x2, - GL_DOUBLE_MAT4x3: - ty - default: - ty - } -} diff --git a/gapis/api/gles/api/fragment_operations.api b/gapis/api/gles/api/fragment_operations.api deleted file mode 100644 index 833ce7909c..0000000000 --- a/gapis/api/gles/api/fragment_operations.api +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -type GLuint DrawBufferIndex - -@internal -class ScissorState { - // Table 21.13: Pixel Operations - GLboolean Test = GL_FALSE - Rect Box // TODO: init -} - -@internal -class StencilState { - // Table 21.13: Pixel Operations - GLboolean Test = GL_FALSE - GLenum Func = GL_ALWAYS - GLint Ref = 0 - GLuint ValueMask = 0xFFFFFFFF - GLenum Fail = GL_KEEP - GLenum PassDepthFail = GL_KEEP - GLenum PassDepthPass = GL_KEEP - GLenum BackFunc = GL_ALWAYS - GLint BackRef = 0 - GLuint BackValueMask = 0xFFFFFFFF - GLenum BackFail = GL_KEEP - GLenum BackPassDepthFail = GL_KEEP - GLenum BackPassDepthPass = GL_KEEP -} - -@internal -class DepthState { - // Table 21.13: Pixel Operations - GLboolean Test = GL_FALSE - GLenum Func = GL_LESS -} - -@internal -class BlendState { - // Table 21.13: Pixel Operations - GLboolean Enabled = GL_FALSE - GLenum SrcRgb = GL_ONE - GLenum SrcAlpha = GL_ONE - GLenum DstRgb = GL_ZERO - GLenum DstAlpha = GL_ZERO - GLenum EquationRgb = GL_FUNC_ADD - GLenum EquationAlpha = GL_FUNC_ADD -} - -@internal -class Mask { - GLboolean R = GL_TRUE - GLboolean G = GL_TRUE - GLboolean B = GL_TRUE - GLboolean A = GL_TRUE -} - -@internal -class PixelState { - ScissorState Scissor - StencilState Stencil - DepthState Depth - map!(DrawBufferIndex, ref!BlendState) Blend // One per draw buffer. - - // Table 21.13: Pixel Operations - Color BlendColor // TODO: = Color(0.0,0.0,0.0,0.0) - GLboolean Dither = GL_TRUE - - // GL_EXT_sRGB_write_control - GLboolean FramebufferSrgb = GL_TRUE - - // Table 21.14: Framebuffer Control - map!(DrawBufferIndex, Mask) ColorWritemask - GLboolean DepthWritemask = GL_TRUE - GLuint StencilWritemask = 0xFFFFFFFF - GLuint StencilBackWritemask = 0xFFFFFFFF - Vec4f ColorClearValue = Vec4f(0.0, 0.0, 0.0, 0.0) - GLfloat DepthClearValue = 1 - GLint StencilClearValue = 0 -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendBarrier.xhtml", Version.GLES32) -cmd void glBlendBarrier() { - BlendBarrier() -} - -sub void BlendBarrier() { - // TODO -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendColor.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlendColor.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlendColor.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendColor.xhtml", Version.GLES32) -cmd void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - ctx := GetContext() - ctx.Pixel.BlendColor = Color(red, green, blue, alpha) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendEquation.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlendEquation.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlendEquation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendEquation.xhtml", Version.GLES32) -cmd void glBlendEquation(GLenum equation) { - ctx := GetContext() - SetBlendEquation(0, len(ctx.Pixel.Blend), equation, equation) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendEquationSeparate.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlendEquationSeparate.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlendEquationSeparate.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendEquationSeparate.xhtml", Version.GLES32) -cmd void glBlendEquationSeparate(GLenum rgb, GLenum alpha) { - ctx := GetContext() - SetBlendEquation(0, len(ctx.Pixel.Blend), rgb, alpha) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendEquationSeparate.xhtml", Version.GLES32) -cmd void glBlendEquationSeparatei(DrawBufferIndex buf, GLenum modeRGB, GLenum modeAlpha) { - BlendEquationSeparatei(buf, modeRGB, modeAlpha) -} - -sub void BlendEquationSeparatei(DrawBufferIndex buf, GLenum modeRGB, GLenum modeAlpha) { - SetBlendEquation(buf, 1, modeRGB, modeAlpha) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendEquation.xhtml", Version.GLES32) -cmd void glBlendEquationi(DrawBufferIndex buf, GLenum mode) { - BlendEquationi(buf, mode) -} - -sub void BlendEquationi(DrawBufferIndex buf, GLenum mode) { - SetBlendEquation(buf, 1, mode, mode) -} - -sub void CheckBlendEquation(GLenum equation) { - switch (equation) { - @if(Version.GLES20) - case GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT, GL_FUNC_SUBTRACT: { - } - @if(Version.GLES30) - case GL_MAX, GL_MIN: { - } - default: { - glErrorInvalidEnum(equation) - } - } -} - -sub void SetBlendEquation(DrawBufferIndex first_buffer, s32 buffer_count, GLenum rgb, GLenum alpha) { - CheckBlendEquation(rgb) - CheckBlendEquation(alpha) - ctx := GetContext() - for i in (first_buffer .. (first_buffer + as!DrawBufferIndex(buffer_count))) { - blend := ctx.Pixel.Blend[i] - blend.EquationRgb = rgb - blend.EquationAlpha = alpha - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendFunc.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlendFunc.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlendFunc.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendFunc.xhtml", Version.GLES32) -cmd void glBlendFunc(GLenum src_factor, GLenum dst_factor) { - ctx := GetContext() - SetBlendFunc(0, len(ctx.Pixel.Blend), src_factor, dst_factor, src_factor, dst_factor) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBlendFuncSeparate.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlendFuncSeparate.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlendFuncSeparate.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendFuncSeparate.xhtml", Version.GLES32) -cmd void glBlendFuncSeparate(GLenum src_factor_rgb, - GLenum dst_factor_rgb, - GLenum src_factor_alpha, - GLenum dst_factor_alpha) { - ctx := GetContext() - SetBlendFunc(0, len(ctx.Pixel.Blend), src_factor_rgb, dst_factor_rgb, src_factor_alpha, dst_factor_alpha) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendFuncSeparate.xhtml", Version.GLES32) -cmd void glBlendFuncSeparatei(DrawBufferIndex buf, - GLenum srcRGB, - GLenum dstRGB, - GLenum srcAlpha, - GLenum dstAlpha) { - BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha) -} - -sub void BlendFuncSeparatei(DrawBufferIndex buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { - SetBlendFunc(buf, 1, srcRGB, dstRGB, srcAlpha, dstAlpha) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlendFunc.xhtml", Version.GLES32) -cmd void glBlendFunci(DrawBufferIndex buf, GLenum src, GLenum dst) { - BlendFunci(buf, src, dst) -} - -sub void BlendFunci(DrawBufferIndex buf, GLenum src, GLenum dst) { - SetBlendFunc(buf, 1, src, dst, src, dst) -} - -sub void CheckBlendFunc(GLenum factor) { - switch (factor) { - @if(Version.GLES20) - case GL_CONSTANT_ALPHA, GL_CONSTANT_COLOR, GL_DST_ALPHA, GL_DST_COLOR, GL_ONE, - GL_ONE_MINUS_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE_MINUS_DST_ALPHA, - GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, - GL_SRC_ALPHA_SATURATE, GL_SRC_COLOR, GL_ZERO: { - } - default: { - glErrorInvalidEnum(factor) - } - } -} - -sub void SetBlendFunc(DrawBufferIndex first_buffer, s32 buffer_count, - GLenum srcRgb, GLenum dstRgb, GLenum srcAlpha, GLenum dstAlpha) { - CheckBlendFunc(srcRgb) - CheckBlendFunc(dstRgb) - CheckBlendFunc(srcAlpha) - CheckBlendFunc(dstAlpha) - ctx := GetContext() - for i in (first_buffer .. (first_buffer + as!DrawBufferIndex(buffer_count))) { - blend := ctx.Pixel.Blend[i] - blend.SrcRgb = srcRgb - blend.DstRgb = dstRgb - blend.SrcAlpha = srcAlpha - blend.DstAlpha = dstAlpha - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDepthFunc.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDepthFunc.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDepthFunc.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDepthFunc.xhtml", Version.GLES32) -cmd void glDepthFunc(GLenum function) { - switch (function) { - case GL_ALWAYS, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_LEQUAL, GL_LESS, GL_NEVER, GL_NOTEQUAL: { - // version 2.0 - } - default: { - glErrorInvalidEnum(function) - } - } - - ctx := GetContext() - ctx.Pixel.Depth.Func = function -} - -// TODO: Move to rasterization? -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glSampleCoverage.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glSampleCoverage.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSampleCoverage.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSampleCoverage.xhtml", Version.GLES32) -cmd void glSampleCoverage(GLfloat value, GLboolean invert) { - - ctx := GetContext() - ctx.Rasterization.SampleCoverageValue = value - ctx.Rasterization.SampleCoverageInvert = invert -} - -// TODO: Move to rasterization? -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSampleMaski.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSampleMaski.xhtml", Version.GLES32) -cmd void glSampleMaski(GLuint maskNumber, GLbitfield mask) { - ctx := GetContext() - CheckLT!GLuint(maskNumber, as!GLuint(ctx.Constants.MaxSampleMaskWords)) - ctx.Rasterization.SampleMaskValue[maskNumber] = mask -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glScissor.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glScissor.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glScissor.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glScissor.xhtml", Version.GLES32) -cmd void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { - CheckSizeGE!GLsizei(width, 0) - CheckSizeGE!GLsizei(height, 0) - ctx := GetContext() - ctx.Pixel.Scissor.Box = Rect(x, y, width, height) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilFunc.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilFunc.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilFunc.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilFunc.xhtml", Version.GLES32) -cmd void glStencilFunc(GLenum func, GLint ref, GLuint mask) { - StencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilFuncSeparate.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilFuncSeparate.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilFuncSeparate.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilFuncSeparate.xhtml", Version.GLES32) -cmd void glStencilFuncSeparate(GLenum face, GLenum function, GLint reference_value, GLuint mask) { - StencilFuncSeparate(face, function, reference_value, mask) -} - -sub void StencilFuncSeparate(GLenum face, GLenum function, GLint reference_value, GLuint mask) { - switch (face) { - case GL_BACK, GL_FRONT, GL_FRONT_AND_BACK: { - // version 2.0 - } - default: { - glErrorInvalidEnum(face) - } - } - switch (function) { - case GL_ALWAYS, GL_EQUAL, GL_GEQUAL, GL_GREATER, GL_LEQUAL, GL_LESS, GL_NEVER, GL_NOTEQUAL: { - // version 2.0 - } - default: { - glErrorInvalidEnum(function) - } - } - ctx := GetContext() - if ((face == GL_FRONT) || (face == GL_FRONT_AND_BACK)) { - ctx.Pixel.Stencil.Func = function - ctx.Pixel.Stencil.Ref = reference_value - ctx.Pixel.Stencil.ValueMask = mask - } - if ((face == GL_BACK) || (face == GL_FRONT_AND_BACK)) { - ctx.Pixel.Stencil.BackFunc = function - ctx.Pixel.Stencil.BackRef = reference_value - ctx.Pixel.Stencil.BackValueMask = mask - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilOp.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilOp.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilOp.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilOp.xhtml", Version.GLES32) -cmd void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { - StencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilOpSeparate.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilOpSeparate.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilOpSeparate.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilOpSeparate.xhtml", Version.GLES32) -cmd void glStencilOpSeparate(GLenum face, - GLenum stencil_fail, - GLenum stencil_pass_depth_fail, - GLenum stencil_pass_depth_pass) { - StencilOpSeparate(face, stencil_fail, stencil_pass_depth_fail, stencil_pass_depth_pass) -} - -sub void CheckStencilOp(GLenum op) { - switch (op) { - case GL_DECR, GL_DECR_WRAP, GL_INCR, GL_INCR_WRAP, GL_INVERT, GL_KEEP, GL_REPLACE, GL_ZERO: { - // version 2.0 - } - default: { - glErrorInvalidEnum(op) - } - } -} - -sub void StencilOpSeparate(GLenum face, GLenum fail, GLenum pass_depth_fail, GLenum pass_depth_pass) { - switch (face) { - case GL_BACK, GL_FRONT, GL_FRONT_AND_BACK: { - // version 2.0 - } - default: { - glErrorInvalidEnum(face) - } - } - CheckStencilOp(fail) - CheckStencilOp(pass_depth_fail) - CheckStencilOp(pass_depth_pass) - ctx := GetContext() - if ((face == GL_FRONT) || (face == GL_FRONT_AND_BACK)) { - ctx.Pixel.Stencil.Fail = fail - ctx.Pixel.Stencil.PassDepthFail = pass_depth_fail - ctx.Pixel.Stencil.PassDepthPass = pass_depth_pass - } - if ((face == GL_BACK) || (face == GL_FRONT_AND_BACK)) { - ctx.Pixel.Stencil.BackFail = fail - ctx.Pixel.Stencil.BackPassDepthFail = pass_depth_fail - ctx.Pixel.Stencil.BackPassDepthPass = pass_depth_pass - } -} diff --git a/gapis/api/gles/api/framebuffer.api b/gapis/api/gles/api/framebuffer.api deleted file mode 100644 index 0617a5d588..0000000000 --- a/gapis/api/gles/api/framebuffer.api +++ /dev/null @@ -1,1177 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class Framebuffer { - FramebufferId ID - - map!(GLint, FramebufferAttachment) ColorAttachments - FramebufferAttachment DepthAttachment - FramebufferAttachment StencilAttachment - - // Table 21.15: Framebuffer (state per framebuffer object) - map!(GLint, GLenum) DrawBuffer - @unused GLenum ReadBuffer = GL_COLOR_ATTACHMENT0 - GLint DefaultWidth = 0 - GLint DefaultHeight = 0 - GLint DefaultLayers = 0 - GLint DefaultSamples = 0 - GLboolean DefaultFixedSampleLocations = GL_FALSE - - @unused string Label // SPEC: Missing -} - -@internal -class FramebufferAttachment { - // Table 21.16: Framebuffer (state per attachment point) - GLenum Type = GL_NONE - ref!Texture Texture - ref!Renderbuffer Renderbuffer - GLint TextureLevel = 0 - GLint TextureLayer = 0 - GLboolean Layered = GL_FALSE - // OVR_multiview - GLsizei NumViews = 1 -/* TODO - GLenum ColorEncoding - GLenum ComponentType - GLuint RedSize - GLuint GreenSize - GLuint BlueSize - GLuint AlphaSize - GLuint DepthSize - GLuint StencilSize - string ObjectLabel - */ -} - -@internal -class Renderbuffer { - RenderbufferId ID - ref!Image Image - - // Table 21.17: Renderbuffer (state per renderbuffer object) - /* TODO - GLuint RedSize = 0 - GLuint GreenSize = 0 - GLuint BlueSize = 0 - GLuint AlphaSize = 0 - GLuint DepthSize = 0 - GLuint StencilSize = 0 - */ - - @unused string Label -} - -/* TODO -@internal -class FramebufferDependentValues { - // Table 21.56: Framebuffer Dependent Values - GLint SampleBuffers = 0 - GLuint Samples = 0 - GLuint MaxSamples = 4 - GLuint RedBits - GLuint GreenBits - GLuint BlueBits - GLuint AlphaBits - GLuint DepthBits - GLuint StencilBits - GLenum ImplementationColorReadType - GLenum ImplementationColorReadFormat - GLfloat[2][] SamplePosition // TODO: impl-dependent -} -*/ - -sub ref!Framebuffer GetBoundFramebufferOrErrorInvalidEnum(GLenum framebuffer_target) { - ctx := GetContext() - return switch (framebuffer_target) { - @if(Version.GLES20) case GL_FRAMEBUFFER: ctx.Bound.DrawFramebuffer - @if(Version.GLES30) case GL_DRAW_FRAMEBUFFER: ctx.Bound.DrawFramebuffer - @if(Version.GLES30) case GL_READ_FRAMEBUFFER: ctx.Bound.ReadFramebuffer - default: ctx.Bound.DrawFramebuffer // TODO: glErrorInvalidEnum(framebuffer_target) - } -} - -sub void CheckNonDefaultFramebuffer(ref!Framebuffer framebuffer) { - ctx := GetContext() - if framebuffer == ctx.Objects.Framebuffers[0] { - glErrorInvalidOperationMsg(new!ERR_INVALID_OPERATION_DEFAULT_FRAMEBUFFER_BOUND()) - } -} - -sub bool IsDefaultFramebuffer(ref!Framebuffer framebuffer) { - ctx := GetContext() - return framebuffer == ctx.Objects.Framebuffers[0] -} - -sub void SetFramebufferAttachment(GLenum framebuffer_target, - GLenum framebuffer_attachment, - FramebufferAttachment attachment) { - ctx := GetContext() - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(framebuffer_target) - CheckNonDefaultFramebuffer(framebuffer) - switch (framebuffer_attachment) { - case GL_COLOR_ATTACHMENT0: - framebuffer.ColorAttachments[0] = attachment - case GL_DEPTH_ATTACHMENT: - framebuffer.DepthAttachment = attachment - case GL_STENCIL_ATTACHMENT: - framebuffer.StencilAttachment = attachment - @if(Version.GLES30) - case GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11, GL_COLOR_ATTACHMENT12, - GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, GL_COLOR_ATTACHMENT15, GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8, GL_COLOR_ATTACHMENT9: { - i := as!GLint(framebuffer_attachment - GL_COLOR_ATTACHMENT0) - if (i < 0) || (i >= ctx.Constants.MaxColorAttachments) { glErrorInvalidOperation() } - framebuffer.ColorAttachments[i] = attachment - } - @if(Version.GLES30) - case GL_DEPTH_STENCIL_ATTACHMENT: { - framebuffer.DepthAttachment = attachment - framebuffer.StencilAttachment = attachment - } - default: { - glErrorInvalidEnum(framebuffer_attachment) - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindFramebuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindFramebuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindFramebuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindFramebuffer.xhtml", Version.GLES32) -cmd void glBindFramebuffer(GLenum target, FramebufferId framebuffer) { - ctx := GetContext() - switch (target) { - case GL_FRAMEBUFFER: { - // version 2.0 - fb := GetOrCreateFramebuffer(framebuffer) - ctx.Bound.ReadFramebuffer = fb - ctx.Bound.DrawFramebuffer = fb - } - @if(Version.GLES30) - case GL_READ_FRAMEBUFFER: { - ctx.Bound.ReadFramebuffer = GetOrCreateFramebuffer(framebuffer) - } - @if(Version.GLES30) - case GL_DRAW_FRAMEBUFFER: { - ctx.Bound.DrawFramebuffer = GetOrCreateFramebuffer(framebuffer) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -sub ref!Framebuffer GetOrCreateFramebuffer(FramebufferId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.Framebuffers[id] == null) { - fb := new!Framebuffer(ID: id) - for i in (as!GLint(0) .. ctx.Constants.MaxColorAttachments) { - fb.ColorAttachments[i] = FramebufferAttachment() - } - fb.DrawBuffer[0] = GL_COLOR_ATTACHMENT0 - for i in (as!GLint(1) .. ctx.Constants.MaxDrawBuffers) { - fb.DrawBuffer[i] = GL_NONE - } - ctx.Objects.Framebuffers[id] = fb - ctx.Objects.GeneratedNames.Framebuffers[id] = true - } - return ctx.Objects.Framebuffers[id] -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindRenderbuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindRenderbuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindRenderbuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindRenderbuffer.xhtml", Version.GLES32) -cmd void glBindRenderbuffer(GLenum target, RenderbufferId renderbuffer) { - ctx := GetContext() - switch (target) { - case GL_RENDERBUFFER: { - ctx.Bound.Renderbuffer = GetOrCreateRenderbuffer(renderbuffer) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -sub ref!Renderbuffer GetOrCreateRenderbuffer(RenderbufferId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.Renderbuffers[id] == null) { - ctx.Objects.Renderbuffers[id] = new!Renderbuffer(ID: id) - ctx.Objects.GeneratedNames.Renderbuffers[id] = true - } - return ctx.Objects.Renderbuffers[id] -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBlitFramebuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBlitFramebuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBlitFramebuffer.xhtml", Version.GLES32) -cmd void glBlitFramebuffer(GLint srcX0, - GLint srcY0, - GLint srcX1, - GLint srcY1, - GLint dstX0, - GLint dstY0, - GLint dstX1, - GLint dstY1, - GLbitfield mask, - GLenum filter) { - BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) -} - -sub void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { - supportsBits(mask, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) - if (GL_COLOR_BUFFER_BIT in mask) { - } - if (GL_DEPTH_BUFFER_BIT in mask) { - } - if (GL_STENCIL_BUFFER_BIT in mask) { - } - switch (filter) { - case GL_LINEAR, GL_NEAREST: { - // version 3.0 - } - default: { - glErrorInvalidEnum(filter) - } - } - _ = srcX0 // TODO - _ = srcY0 // TODO - _ = srcX1 // TODO - _ = srcY1 // TODO - _ = dstX0 // TODO - _ = dstY0 // TODO - _ = dstX1 // TODO - _ = dstY1 // TODO -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCheckFramebufferStatus.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCheckFramebufferStatus.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCheckFramebufferStatus.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCheckFramebufferStatus.xhtml", Version.GLES32) -cmd GLenum glCheckFramebufferStatus(GLenum target) { - switch (target) { - case GL_FRAMEBUFFER: { - // version 2.0 - } - @if(Version.GLES30) - case GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER: { - } - default: { - glErrorInvalidEnum(target) - } - } - - return ? -} - -@clear -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glClear.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClear.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClear.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClear.xhtml", Version.GLES32) -cmd void glClear(GLbitfield mask) { - supportsBits(mask, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) - - ctx := GetContext() - fb := ctx.Bound.DrawFramebuffer - - if (GL_COLOR_BUFFER_BIT in mask) { - _ = ctx.Pixel.ColorClearValue - for _, _, a in fb.ColorAttachments { - WriteGPUFramebufferAttachment(a) - WriteFramebufferAttachment(a) - } - } - - if (GL_DEPTH_BUFFER_BIT in mask) { - _ = ctx.Pixel.DepthClearValue - WriteGPUFramebufferAttachment(fb.DepthAttachment) - WriteFramebufferAttachment(fb.DepthAttachment) - } - - if (GL_STENCIL_BUFFER_BIT in mask) { - _ = ctx.Pixel.StencilClearValue - WriteGPUFramebufferAttachment(fb.StencilAttachment) - WriteFramebufferAttachment(fb.StencilAttachment) - } - - SharedDrawClearCommandDependencies(ctx) -} - -@clear -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearBuffer.xhtml", Version.GLES32) -cmd void glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) { - // TODO: WriteGPUFramebufferAttachment - switch (buffer) { - case GL_DEPTH_STENCIL: { - CheckEQ!GLint(drawbuffer, 0) - } - default: { - glErrorInvalidEnum(buffer) - } - } -} - -@clear -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearBuffer.xhtml", Version.GLES32) -cmd void glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value) { - // TODO: WriteGPUFramebufferAttachment - switch (buffer) { - case GL_COLOR: { - ctx := GetContext() - CheckLT!GLint(drawbuffer, ctx.Constants.MaxDrawBuffers) - read(value[0:4]) - } - case GL_DEPTH: { - CheckEQ!GLint(drawbuffer, 0) - read(value[0:1]) - } - default: { - glErrorInvalidEnum(buffer) - } - } -} - -@clear -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearBuffer.xhtml", Version.GLES32) -cmd void glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value) { - // TODO: WriteGPUFramebufferAttachment - switch (buffer) { - case GL_COLOR: { - ctx := GetContext() - CheckLT!GLint(drawbuffer, ctx.Constants.MaxDrawBuffers) - read(value[0:4]) - } - case GL_STENCIL: { - CheckEQ!GLint(drawbuffer, 0) - read(value[0:1]) - } - default: { - glErrorInvalidEnum(buffer) - } - } -} - -@clear -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearBuffer.xhtml", Version.GLES32) -cmd void glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value) { - // TODO: WriteGPUFramebufferAttachment - switch (buffer) { - case GL_COLOR: { - ctx := GetContext() - CheckLT!GLint(drawbuffer, ctx.Constants.MaxDrawBuffers) - read(value[0:4]) - } - default: { - glErrorInvalidEnum(buffer) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glClearColor.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearColor.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearColor.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearColor.xhtml", Version.GLES32) -cmd void glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - ctx := GetContext() - ctx.Pixel.ColorClearValue = Vec4f(r, g, b, a) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glClearDepthf.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearDepthf.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearDepthf.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearDepthf.xhtml", Version.GLES32) -cmd void glClearDepthf(GLfloat depth) { - ctx := GetContext() - ctx.Pixel.DepthClearValue = depth -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glClearStencil.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClearStencil.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClearStencil.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClearStencil.xhtml", Version.GLES32) -cmd void glClearStencil(GLint stencil) { - ctx := GetContext() - ctx.Pixel.StencilClearValue = stencil -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glColorMask.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glColorMask.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glColorMask.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glColorMask.xhtml", Version.GLES32) -cmd void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - ctx := GetContext() - for i in (0 .. as!DrawBufferIndex(len(ctx.Pixel.ColorWritemask))) { - ctx.Pixel.ColorWritemask[i] = Mask(red, green, blue, alpha) - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glColorMask.xhtml", Version.GLES32) -cmd void glColorMaski(DrawBufferIndex index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - ColorMaski(index, r, g, b, a) -} - -sub void ColorMaski(DrawBufferIndex index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) { - ctx := GetContext() - ctx.Pixel.ColorWritemask[index] = Mask(r, g, b, a) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteFramebuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteFramebuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteFramebuffers.xhtml", Version.GLES32) -cmd void glDeleteFramebuffers(GLsizei count, const FramebufferId* framebuffers) { - CheckCountGE!GLsizei(count, 0) - - f := framebuffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := f[i] - if id != 0 { - // TODO: This is not really an error according to the spec. - // However, we need to ensure the command is removed, - // or else the invalid ID breaks remapping in replay. - if !(id in ctx.Objects.Framebuffers) { glErrorInvalidValue!FramebufferId(id) } - delete(ctx.Objects.Framebuffers, id) - delete(ctx.Objects.GeneratedNames.Framebuffers, id) - if id == ctx.Bound.ReadFramebuffer.ID { - ctx.Bound.ReadFramebuffer = ctx.Objects.Default.Framebuffer - } - if id == ctx.Bound.DrawFramebuffer.ID { - ctx.Bound.DrawFramebuffer = ctx.Objects.Default.Framebuffer - } - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteRenderbuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteRenderbuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteRenderbuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteRenderbuffers.xhtml", Version.GLES32) -cmd void glDeleteRenderbuffers(GLsizei count, const RenderbufferId* renderbuffers) { - CheckCountGE!GLsizei(count, 0) - - r := renderbuffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := r[i] - if id != 0 { - delete(ctx.Objects.Renderbuffers, id) - delete(ctx.Objects.GeneratedNames.Renderbuffers, id) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDepthMask.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDepthMask.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDepthMask.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDepthMask.xhtml", Version.GLES32) -cmd void glDepthMask(GLboolean enabled) { - - ctx := GetContext() - ctx.Pixel.DepthWritemask = enabled -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDrawBuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDrawBuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDrawBuffers.xhtml", Version.GLES32) -cmd void glDrawBuffers(GLsizei n, const GLenum* bufs) { - DrawBuffers(n, bufs) -} - -sub void DrawBuffers(GLsizei n, const GLenum* buffers) { - ctx := GetContext() - - CheckCountGE!GLsizei(n, 0) - CheckLE!GLsizei(n, as!GLsizei(ctx.Constants.MaxDrawBuffers)) - - b := buffers[0:n] - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(GL_DRAW_FRAMEBUFFER) - - // For the default framebuffer - if (framebuffer.ID == 0) && (n != 1) { - glErrorInvalidOperation() - } - - for i in (0 .. as!GLint(n)) { - switch (b[i]) { - case GL_NONE: { - // Always accepted. - } - case GL_BACK: { - // Only accepted for the default framebuffer. - if (framebuffer.ID != 0) { - glErrorInvalidOperation() - } - } - case GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, GL_COLOR_ATTACHMENT15, - GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8, GL_COLOR_ATTACHMENT9: { - // Not valid for the default framebuffer. - if (framebuffer.ID == 0) { - glErrorInvalidOperation() - } - } - default: { - glErrorInvalidEnum(b[i]) - } - } - } - - for i in (0 .. as!GLint(n)) { - framebuffer.DrawBuffer[i] = b[i] - } - for i in (as!GLint(n) .. ctx.Constants.MaxDrawBuffers) { - framebuffer.DrawBuffer[i] = GL_NONE - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFramebufferParameteri.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFramebufferParameteri.xhtml", Version.GLES32) -cmd void glFramebufferParameteri(GLenum target, GLenum pname, GLint param) { - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(target) - CheckNonDefaultFramebuffer(framebuffer) - switch (pname) { - case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: { - switch param { - case 0: framebuffer.DefaultFixedSampleLocations = GL_TRUE - default: framebuffer.DefaultFixedSampleLocations = GL_FALSE - } - } - case GL_FRAMEBUFFER_DEFAULT_HEIGHT: { - framebuffer.DefaultHeight = param - } - case GL_FRAMEBUFFER_DEFAULT_SAMPLES: { - framebuffer.DefaultSamples = param - } - case GL_FRAMEBUFFER_DEFAULT_WIDTH: { - framebuffer.DefaultWidth = param - } - @if(Version.GLES32) - case GL_FRAMEBUFFER_DEFAULT_LAYERS: { - framebuffer.DefaultLayers = param - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFramebufferRenderbuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFramebufferRenderbuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFramebufferRenderbuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFramebufferRenderbuffer.xhtml", Version.GLES32) -cmd void glFramebufferRenderbuffer(GLenum framebuffer_target, - GLenum framebuffer_attachment, - GLenum renderbuffer_target, - RenderbufferId renderbuffer) { - ctx := GetContext() - if renderbuffer_target != GL_RENDERBUFFER { glErrorInvalidEnum(renderbuffer_target) } - // SPEC: Only PDF spec mentions this: - if (renderbuffer != 0) && !(renderbuffer in ctx.Objects.Renderbuffers) { - glErrorInvalidOperation_ObjectDoesNotExist!RenderbufferId(renderbuffer) - } - - attachment := FramebufferAttachment() - if (renderbuffer != 0) { - attachment.Type = GL_RENDERBUFFER - attachment.Renderbuffer = ctx.Objects.Renderbuffers[renderbuffer] - } - SetFramebufferAttachment(framebuffer_target, framebuffer_attachment, attachment) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFramebufferTexture.xhtml", Version.GLES32) -cmd void glFramebufferTexture(GLenum target, GLenum attachment, TextureId texture, GLint level) { - FramebufferTexture(target, attachment, texture, level) -} - -sub void FramebufferTexture(GLenum target, GLenum attachment, TextureId texture, GLint level) { - ctx := GetContext() - attachment_info := FramebufferAttachment() - if (texture != 0) { - if !(texture in ctx.Objects.Textures) { glErrorInvalidValue!TextureId(texture) } - attachment_info.Type = GL_TEXTURE - attachment_info.Texture = ctx.Objects.Textures[texture] - attachment_info.TextureLevel = level - attachment_info.Layered = GL_TRUE // TODO: Set correct. It is 'maybe layered' now. - } - SetFramebufferAttachment(target, attachment, attachment_info) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFramebufferTexture2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFramebufferTexture2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFramebufferTexture2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFramebufferTexture2D.xhtml", Version.GLES32) -cmd void glFramebufferTexture2D(GLenum framebuffer_target, - GLenum framebuffer_attachment, - GLenum texture_target, - TextureId texture, - GLint level) { - FramebufferTexture2D(framebuffer_target, framebuffer_attachment, texture_target, texture, level) -} - -sub void FramebufferTexture2D(GLenum framebuffer_target, - GLenum framebuffer_attachment, - GLenum texture_target, - TextureId texture, - GLint level) { - switch (texture_target) { - case GL_TEXTURE_2D, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z: { - // version 2.0 - } - @if(Version.GLES31) - case GL_TEXTURE_2D_MULTISAMPLE: { - } - default: { - glErrorInvalidEnum(texture_target) - } - } - // TODO: Level must be 0 in GLES20 - - ctx := GetContext() - attachment := FramebufferAttachment() - if (texture != 0) { - if !(texture in ctx.Objects.Textures) { - glErrorInvalidOperation_ObjectDoesNotExist!TextureId(texture) - } - kind := switch (texture_target) { - case GL_TEXTURE_2D: - GL_TEXTURE_2D - case GL_TEXTURE_2D_MULTISAMPLE: - GL_TEXTURE_2D_MULTISAMPLE - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - GL_TEXTURE_CUBE_MAP - default: - as!GLenum(0) - } - // TODO: Handle texture 0 - if ctx.Objects.Textures[texture].Kind != kind { glErrorInvalidOperation() } - attachment.Type = GL_TEXTURE - attachment.Texture = ctx.Objects.Textures[texture] - attachment.TextureLevel = level - attachment.TextureLayer = CubemapFaceToLayer(texture_target) - } - SetFramebufferAttachment(framebuffer_target, framebuffer_attachment, attachment) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFramebufferTextureLayer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFramebufferTextureLayer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFramebufferTextureLayer.xhtml", Version.GLES32) -cmd void glFramebufferTextureLayer(GLenum target, - GLenum attachment, - TextureId texture, - GLint level, - GLint layer) { - ctx := GetContext() - attachment_info := FramebufferAttachment() - if (texture != 0) { - if !(texture in ctx.Objects.Textures) { glErrorInvalidValue!TextureId(texture) } - attachment_info.Type = GL_TEXTURE - attachment_info.Texture = ctx.Objects.Textures[texture] - attachment_info.TextureLevel = level - attachment_info.TextureLayer = layer - } - SetFramebufferAttachment(target, attachment, attachment_info) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenFramebuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenFramebuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenFramebuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenFramebuffers.xhtml", Version.GLES32) -cmd void glGenFramebuffers(GLsizei count, FramebufferId* framebuffers) { - CheckCountGE!GLsizei(count, 0) - f := framebuffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!FramebufferId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Framebuffers[id] = true - f[i] = id - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenRenderbuffers.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenRenderbuffers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenRenderbuffers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenRenderbuffers.xhtml", Version.GLES32) -cmd void glGenRenderbuffers(GLsizei count, RenderbufferId* renderbuffers) { - CheckCountGE!GLsizei(count, 0) - r := renderbuffers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!RenderbufferId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Renderbuffers[id] = true - r[i] = id - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetFramebufferAttachmentParameteriv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetFramebufferAttachmentParameteriv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetFramebufferAttachmentParameteriv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetFramebufferAttachmentParameteriv.xhtml", Version.GLES32) -cmd void glGetFramebufferAttachmentParameteriv(GLenum framebuffer_target, - GLenum attachment, - GLenum parameter, - GLint* value) { - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(framebuffer_target) - a := switch (attachment) { - case GL_COLOR_ATTACHMENT0, GL_BACK: - framebuffer.ColorAttachments[0] - case GL_DEPTH_ATTACHMENT: - framebuffer.DepthAttachment - case GL_STENCIL_ATTACHMENT: - framebuffer.StencilAttachment - @if(Version.GLES30) - case GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, GL_COLOR_ATTACHMENT15, - GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8, GL_COLOR_ATTACHMENT9: { - // TODO: if i < 0 || i >= ctx.Constants.MaxColorAttachments { glErrorInvalidOperation() } - framebuffer.ColorAttachments[as!GLint(attachment - GL_COLOR_ATTACHMENT0)] - } - @if(Version.GLES30) - case GL_DEPTH_STENCIL_ATTACHMENT: { - // TODO: check framebuffer.DepthAttachment == framebuffer.StencilAttachment - framebuffer.DepthAttachment - } - default: { - // TODO: glErrorInvalidEnum(attachment) - framebuffer.ColorAttachments[0] - } - } - if (a.Type == GL_NONE) && - (parameter != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) && (parameter != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) { - glErrorInvalidOperation() - } - switch (parameter) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: value[0] = as!GLint(a.Type) - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: - switch a.Type { - case GL_NONE: value[0] = as!GLint(0) - case GL_TEXTURE: value[0] = as!GLint(a.Texture.ID) - case GL_RENDERBUFFER: value[0] = as!GLint(a.Renderbuffer.ID) - } - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: value[0] = as!GLint(a.TextureLevel) - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: value[0] = ? // TODO - @if(Version.GLES32) - case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: value[0] = as!GLint(a.Layered) - @if(Version.GLES30) - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER: value[0] = as!GLint(a.TextureLayer) - @if(Version.GLES30) - case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, - GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, - GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, - GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - value[0] = ? - default: - glErrorInvalidEnum(parameter) - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetFramebufferParameteriv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetFramebufferParameteriv.xhtml", Version.GLES32) -cmd void glGetFramebufferParameteriv(GLenum target, GLenum pname, GLint* params) { - switch (pname) { - case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS, GL_FRAMEBUFFER_DEFAULT_HEIGHT, - GL_FRAMEBUFFER_DEFAULT_SAMPLES, GL_FRAMEBUFFER_DEFAULT_WIDTH: { - // version 3.1 - } - @if(Version.GLES32) - case GL_FRAMEBUFFER_DEFAULT_LAYERS: { - } - default: { - glErrorInvalidEnum(pname) - } - } - - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(target) - CheckNonDefaultFramebuffer(framebuffer) - params[0] = switch (pname) { - case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS: as!GLint(framebuffer.DefaultFixedSampleLocations) - case GL_FRAMEBUFFER_DEFAULT_HEIGHT: framebuffer.DefaultHeight - case GL_FRAMEBUFFER_DEFAULT_SAMPLES: framebuffer.DefaultSamples - case GL_FRAMEBUFFER_DEFAULT_WIDTH: framebuffer.DefaultWidth - case GL_FRAMEBUFFER_DEFAULT_LAYERS: framebuffer.DefaultLayers - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetRenderbufferParameteriv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetRenderbufferParameteriv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetRenderbufferParameteriv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetRenderbufferParameteriv.xhtml", Version.GLES32) -cmd void glGetRenderbufferParameteriv(GLenum target, GLenum parameter, GLint* values) { - switch (target) { - case GL_RENDERBUFFER: { - // version 2.0 - } - default: { - glErrorInvalidEnum(target) - } - } - switch (parameter) { - case GL_RENDERBUFFER_ALPHA_SIZE, GL_RENDERBUFFER_BLUE_SIZE, GL_RENDERBUFFER_DEPTH_SIZE, - GL_RENDERBUFFER_GREEN_SIZE, GL_RENDERBUFFER_HEIGHT, GL_RENDERBUFFER_INTERNAL_FORMAT, - GL_RENDERBUFFER_RED_SIZE, GL_RENDERBUFFER_STENCIL_SIZE, GL_RENDERBUFFER_WIDTH: { - // version 2.0 - } - @if(Version.GLES30) - case GL_RENDERBUFFER_SAMPLES: { - } - default: { - glErrorInvalidEnum(parameter) - } - } - - ctx := GetContext() - rb := ctx.Bound.Renderbuffer - if rb == null { glErrorInvalidOperation() } - if rb.Image == null { - values[0] = 0 - } else { - switch (parameter) { - case GL_RENDERBUFFER_WIDTH: values[0] = as!GLint(rb.Image.Width) - case GL_RENDERBUFFER_HEIGHT: values[0] = as!GLint(rb.Image.Height) - case GL_RENDERBUFFER_INTERNAL_FORMAT: values[0] = as!GLint(rb.Image.SizedFormat) - // TODO: - case GL_RENDERBUFFER_RED_SIZE: values[0] = ? - case GL_RENDERBUFFER_GREEN_SIZE: values[0] = ? - case GL_RENDERBUFFER_BLUE_SIZE: values[0] = ? - case GL_RENDERBUFFER_ALPHA_SIZE: values[0] = ? - case GL_RENDERBUFFER_DEPTH_SIZE: values[0] = ? - case GL_RENDERBUFFER_STENCIL_SIZE: values[0] = ? - default: { glErrorInvalidEnum(parameter) } - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glInvalidateFramebuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glInvalidateFramebuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glInvalidateFramebuffer.xhtml", Version.GLES32) -cmd void glInvalidateFramebuffer(GLenum target, GLsizei count, const GLenum* attachments) { - InvalidateFramebuffer(target, count, attachments) -} - -sub void InvalidateFramebuffer(GLenum target, GLsizei count, const GLenum* attachments) { - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(target) - a := attachments[0:count] - if IsDefaultFramebuffer(framebuffer) { - for i in 0 .. count { - switch a[i] { - case GL_COLOR, GL_DEPTH, GL_STENCIL: { } - default: { - glErrorInvalidEnum(a[i]) - } - } - } - } else { - for i in 0 .. count { - switch a[i] { - case GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT10, GL_COLOR_ATTACHMENT11, - GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, GL_COLOR_ATTACHMENT15, - GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8, GL_COLOR_ATTACHMENT9, - GL_DEPTH_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT: { } - default: { - glErrorInvalidEnum(a[i]) - } - } - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glInvalidateSubFramebuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glInvalidateSubFramebuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glInvalidateSubFramebuffer.xhtml", Version.GLES32) -cmd void glInvalidateSubFramebuffer(GLenum target, - GLsizei numAttachments, - const GLenum* attachments, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - switch (target) { - case GL_FRAMEBUFFER: { - // version 3.0 - } - default: { - glErrorInvalidEnum(target) - } - } - - // TODO - read(attachments[0:numAttachments]) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsFramebuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsFramebuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsFramebuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsFramebuffer.xhtml", Version.GLES32) -cmd GLboolean glIsFramebuffer(FramebufferId framebuffer) { - - ctx := GetContext() - return toGLboolean(framebuffer in ctx.Objects.Framebuffers) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsRenderbuffer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsRenderbuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsRenderbuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsRenderbuffer.xhtml", Version.GLES32) -cmd GLboolean glIsRenderbuffer(RenderbufferId renderbuffer) { - - ctx := GetContext() - return toGLboolean(renderbuffer in ctx.Objects.Renderbuffers) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glReadBuffer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glReadBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glReadBuffer.xhtml", Version.GLES32) -cmd void glReadBuffer(GLenum src) { - switch (src) { - case GL_BACK, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT10, - GL_COLOR_ATTACHMENT11, GL_COLOR_ATTACHMENT12, GL_COLOR_ATTACHMENT13, GL_COLOR_ATTACHMENT14, - GL_COLOR_ATTACHMENT15, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7, GL_COLOR_ATTACHMENT8, - GL_COLOR_ATTACHMENT9, GL_NONE: { - // version 3.0 - } - default: { - glErrorInvalidEnum(src) - } - } - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(GL_READ_FRAMEBUFFER) - framebuffer.ReadBuffer = src -} - -sub void checkReadPixels(GLsizei width, - GLsizei height, - GLenum format, - GLenum type) { - switch (format) { - case GL_ALPHA, GL_RGB, GL_RGBA: { - // version 2.0 - } - @if(Version.GLES30) - case GL_RED, GL_RED_INTEGER, GL_RG, GL_RG_INTEGER, GL_RGB_INTEGER, GL_LUMINANCE_ALPHA, GL_LUMINANCE: { - } - default: { - glErrorInvalidEnum(format) - } - } - switch (type) { - case GL_UNSIGNED_SHORT_5_6_5: { - // version 2.0 - if format != GL_RGB { glErrorInvalidOperation() } - } - case GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1: { - // version 2.0 - if format != GL_RGBA { glErrorInvalidOperation() } - } - case GL_UNSIGNED_BYTE: { - // version 2.0 - } - @if(Version.GLES30) - case GL_FLOAT, GL_INT, GL_UNSIGNED_INT, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV: { - // TODO(dsrbecky) - implement additional 'type compatible with format' - // validation. PDF spec contains a table with for these. - } - default: { - glErrorInvalidEnum(type) - } - } - CheckSizeGE!GLsizei(width, 0) - CheckSizeGE!GLsizei(height, 0) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glReadPixels.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glReadPixels.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glReadPixels.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glReadPixels.xhtml", Version.GLES32) -cmd void glReadPixels(GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - void* data) { - checkReadPixels(width, height, format, type) - - ctx := GetContext() - if (ctx.Bound.PixelPackBuffer == null) && (data != null) { - requiredSize := uncompressedImageSize(width, height, format, type) - write(data[0:requiredSize]) - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glReadPixels.xhtml", Version.GLES32) -cmd void glReadnPixels(GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - GLsizei bufSize, - void* data) { - ReadnPixels(x, y, width, height, format, type, bufSize, data) -} - -sub void ReadnPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void* data) { - checkReadPixels(width, height, format, type) - ctx := GetContext() - if (ctx.Bound.PixelPackBuffer == null) && (data != null) { - requiredSize := uncompressedImageSize(width, height, format, type) - if as!GLsizei(requiredSize) > bufSize { glErrorInvalidOperation() } - write(data[0:requiredSize]) - } - - _ = x // TODO - _ = y // TODO - _ = width // TODO - _ = height // TODO -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glRenderbufferStorage.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glRenderbufferStorage.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glRenderbufferStorage.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glRenderbufferStorage.xhtml", Version.GLES32) -cmd void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { - RenderbufferStorageMultisample(target, 0 /* samples */, internalformat, width, height) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glRenderbufferStorageMultisample.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glRenderbufferStorageMultisample.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glRenderbufferStorageMultisample.xhtml", Version.GLES32) -cmd void glRenderbufferStorageMultisample(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height) { - RenderbufferStorageMultisample(target, samples, internalformat, width, height) -} - -sub void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) { - if target != GL_RENDERBUFFER { glErrorInvalidEnum(target) } - // TODO: Not all formats are required to be supported as renderbuffer. - sizedFormatInfo := GetSizedFormatInfoOrEnumError(internalformat) - if sizedFormatInfo.Compression != Uncompressed { - glErrorInvalidEnum(internalformat) - } - CheckSizeGE!GLsizei(width, 0) - CheckSizeGE!GLsizei(height, 0) - - ctx := GetContext() - CheckLE!GLsizei(width, as!GLsizei(ctx.Constants.MaxRenderbufferSize)) - CheckLE!GLsizei(height, as!GLsizei(ctx.Constants.MaxRenderbufferSize)) - - rb := ctx.Bound.Renderbuffer - if rb == null { glErrorInvalidOperation() } - rb.Image = new!Image( - Width: width, - Height: height, - Samples: samples, - SizedFormat: internalformat, - DataFormat: sizedFormatInfo.UnsizedFormat, - DataType: sizedFormatInfo.DataType, - ) - rb.Image.Data = make!u8(uncompressedImageSize(width, height, sizedFormatInfo.UnsizedFormat, sizedFormatInfo.DataType)) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilMask.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilMask.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilMask.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilMask.xhtml", Version.GLES32) -cmd void glStencilMask(GLuint mask) { - - ctx := GetContext() - ctx.Pixel.StencilWritemask = mask - ctx.Pixel.StencilBackWritemask = mask -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glStencilMaskSeparate.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glStencilMaskSeparate.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glStencilMaskSeparate.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glStencilMaskSeparate.xhtml", Version.GLES32) -cmd void glStencilMaskSeparate(GLenum face, GLuint mask) { - ctx := GetContext() - switch (face) { - case GL_BACK: - ctx.Pixel.StencilBackWritemask = mask - case GL_FRONT: - ctx.Pixel.StencilWritemask = mask - case GL_FRONT_AND_BACK: { - ctx.Pixel.StencilWritemask = mask - ctx.Pixel.StencilBackWritemask = mask - } - default: { - glErrorInvalidEnum(face) - } - } -} diff --git a/gapis/api/gles/api/gl.api b/gapis/api/gles/api/gl.api deleted file mode 100644 index 3c14c68b40..0000000000 --- a/gapis/api/gles/api/gl.api +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Desktop OpenGL commands (used for replay) - -cmd void glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels) { - ctx := GetContext() - t := GetBoundTextureForUnit(ctx.Bound.TextureUnit, target) - layer := CubemapFaceToLayer(target) - l := GetTextureImage(t, level, layer) - width := l.Width - height := l.Height - unpack := ctx.Other.Unpack - url := SelectNonZero!GLint(unpack.RowLength, as!GLint(width)) - pixel_size := as!GLint(uncompressedPixelSize(format, type)) - row_size := Align!GLint(url * pixel_size, unpack.Alignment) - image_size := SelectNonZero!GLint(unpack.ImageHeight, as!GLint(height)) * row_size - write(pixels[0:image_size]) -} - -// EXT_disjoint_timer_query -// TODO: Always use glGetQueryObjectui64vEXT? - -cmd void glGetQueryObjecti64v(QueryId query, GLenum parameter, s64* value) { - value[0] = ? -} - -cmd void glGetQueryObjectui64v(QueryId query, GLenum parameter, u64* value) { - value[0] = ? -} - -cmd void glTexStorage1D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { -} - -cmd void glBindFragDataLocation(ProgramId program, GLuint color, const char* name) { - _ = as!string(name) -} - -cmd void glTexImage2DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) { - info := GetSizedFormatInfo(internalformat) - TexImage(IsTexImageCmd | HasMultisampleModifier, target, - 0, 0, 0, 0, // Offsets - 1, width, height, 1, 0, samples, fixedsamplelocations, // Dimensions - internalformat, info.UnsizedFormat, info.DataType, 0, null) // Format&data -} diff --git a/gapis/api/gles/api/glbitfield.api b/gapis/api/gles/api/glbitfield.api deleted file mode 100644 index 8cc107bde3..0000000000 --- a/gapis/api/gles/api/glbitfield.api +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@analyze_usage -bitfield GLbitfield { - GL_CURRENT_BIT = 0x00000001, - GL_POINT_BIT = 0x00000002, - GL_LINE_BIT = 0x00000004, - GL_POLYGON_BIT = 0x00000008, - GL_POLYGON_STIPPLE_BIT = 0x00000010, - GL_PIXEL_MODE_BIT = 0x00000020, - GL_LIGHTING_BIT = 0x00000040, - GL_FOG_BIT = 0x00000080, - GL_DEPTH_BUFFER_BIT = 0x00000100, - GL_ACCUM_BUFFER_BIT = 0x00000200, - GL_STENCIL_BUFFER_BIT = 0x00000400, - GL_VIEWPORT_BIT = 0x00000800, - GL_TRANSFORM_BIT = 0x00001000, - GL_ENABLE_BIT = 0x00002000, - GL_COLOR_BUFFER_BIT = 0x00004000, - GL_HINT_BIT = 0x00008000, - GL_EVAL_BIT = 0x00010000, - GL_LIST_BIT = 0x00020000, - GL_TEXTURE_BIT = 0x00040000, - GL_SCISSOR_BIT = 0x00080000, - GL_MULTISAMPLE_BIT = 0x20000000, - GL_MULTISAMPLE_BIT_ARB = 0x20000000, - GL_MULTISAMPLE_BIT_EXT = 0x20000000, - GL_MULTISAMPLE_BIT_3DFX = 0x20000000, - GL_ALL_ATTRIB_BITS = 0xFFFFFFFF, - GL_COVERAGE_BUFFER_BIT_NV = 0x00008000, - GL_CLIENT_PIXEL_STORE_BIT = 0x00000001, - GL_CLIENT_VERTEX_ARRAY_BIT = 0x00000002, - GL_CLIENT_ALL_ATTRIB_BITS = 0xFFFFFFFF, - GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT = 0x00000001, - GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002, - GL_CONTEXT_FLAG_DEBUG_BIT_KHR = 0x00000002, - GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 0x00000004, - GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB = 0x00000004, - GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR = 0x00000008, - GL_CONTEXT_CORE_PROFILE_BIT = 0x00000001, - GL_CONTEXT_COMPATIBILITY_PROFILE_BIT = 0x00000002, - GL_MAP_READ_BIT = 0x00000001, - GL_MAP_READ_BIT_EXT = 0x00000001, - GL_MAP_WRITE_BIT = 0x00000002, - GL_MAP_WRITE_BIT_EXT = 0x00000002, - GL_MAP_INVALIDATE_RANGE_BIT = 0x00000004, - GL_MAP_INVALIDATE_RANGE_BIT_EXT = 0x00000004, - GL_MAP_INVALIDATE_BUFFER_BIT = 0x00000008, - GL_MAP_INVALIDATE_BUFFER_BIT_EXT = 0x00000008, - GL_MAP_FLUSH_EXPLICIT_BIT = 0x00000010, - GL_MAP_FLUSH_EXPLICIT_BIT_EXT = 0x00000010, - GL_MAP_UNSYNCHRONIZED_BIT = 0x00000020, - GL_MAP_UNSYNCHRONIZED_BIT_EXT = 0x00000020, - GL_MAP_PERSISTENT_BIT = 0x00000040, - GL_MAP_PERSISTENT_BIT_EXT = 0x00000040, - GL_MAP_COHERENT_BIT = 0x00000080, - GL_MAP_COHERENT_BIT_EXT = 0x00000080, - GL_DYNAMIC_STORAGE_BIT = 0x00000100, - GL_DYNAMIC_STORAGE_BIT_EXT = 0x00000100, - GL_CLIENT_STORAGE_BIT = 0x00000200, - GL_CLIENT_STORAGE_BIT_EXT = 0x00000200, - GL_SPARSE_STORAGE_BIT_ARB = 0x00000400, - GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 0x00000001, - GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT = 0x00000001, - GL_ELEMENT_ARRAY_BARRIER_BIT = 0x00000002, - GL_ELEMENT_ARRAY_BARRIER_BIT_EXT = 0x00000002, - GL_UNIFORM_BARRIER_BIT = 0x00000004, - GL_UNIFORM_BARRIER_BIT_EXT = 0x00000004, - GL_TEXTURE_FETCH_BARRIER_BIT = 0x00000008, - GL_TEXTURE_FETCH_BARRIER_BIT_EXT = 0x00000008, - GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV = 0x00000010, - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 0x00000020, - GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT = 0x00000020, - GL_COMMAND_BARRIER_BIT = 0x00000040, - GL_COMMAND_BARRIER_BIT_EXT = 0x00000040, - GL_PIXEL_BUFFER_BARRIER_BIT = 0x00000080, - GL_PIXEL_BUFFER_BARRIER_BIT_EXT = 0x00000080, - GL_TEXTURE_UPDATE_BARRIER_BIT = 0x00000100, - GL_TEXTURE_UPDATE_BARRIER_BIT_EXT = 0x00000100, - GL_BUFFER_UPDATE_BARRIER_BIT = 0x00000200, - GL_BUFFER_UPDATE_BARRIER_BIT_EXT = 0x00000200, - GL_FRAMEBUFFER_BARRIER_BIT = 0x00000400, - GL_FRAMEBUFFER_BARRIER_BIT_EXT = 0x00000400, - GL_TRANSFORM_FEEDBACK_BARRIER_BIT = 0x00000800, - GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT = 0x00000800, - GL_ATOMIC_COUNTER_BARRIER_BIT = 0x00001000, - GL_ATOMIC_COUNTER_BARRIER_BIT_EXT = 0x00001000, - GL_SHADER_STORAGE_BARRIER_BIT = 0x00002000, - GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT = 0x00004000, - GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT = 0x00004000, - GL_QUERY_BUFFER_BARRIER_BIT = 0x00008000, - GL_ALL_BARRIER_BITS = 0xFFFFFFFF, - GL_ALL_BARRIER_BITS_EXT = 0xFFFFFFFF, - GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001, - GL_SYNC_FLUSH_COMMANDS_BIT_APPLE = 0x00000001, - GL_VERTEX_SHADER_BIT = 0x00000001, - GL_VERTEX_SHADER_BIT_EXT = 0x00000001, - GL_FRAGMENT_SHADER_BIT = 0x00000002, - GL_FRAGMENT_SHADER_BIT_EXT = 0x00000002, - GL_GEOMETRY_SHADER_BIT = 0x00000004, - GL_GEOMETRY_SHADER_BIT_EXT = 0x00000004, - GL_GEOMETRY_SHADER_BIT_OES = 0x00000004, - GL_TESS_CONTROL_SHADER_BIT = 0x00000008, - GL_TESS_CONTROL_SHADER_BIT_EXT = 0x00000008, - GL_TESS_CONTROL_SHADER_BIT_OES = 0x00000008, - GL_TESS_EVALUATION_SHADER_BIT = 0x00000010, - GL_TESS_EVALUATION_SHADER_BIT_EXT = 0x00000010, - GL_TESS_EVALUATION_SHADER_BIT_OES = 0x00000010, - GL_COMPUTE_SHADER_BIT = 0x00000020, - GL_ALL_SHADER_BITS = 0xFFFFFFFF, - GL_ALL_SHADER_BITS_EXT = 0xFFFFFFFF, - GL_TEXTURE_STORAGE_SPARSE_BIT_AMD = 0x00000001, - GL_RED_BIT_ATI = 0x00000001, - GL_GREEN_BIT_ATI = 0x00000002, - GL_BLUE_BIT_ATI = 0x00000004, - GL_2X_BIT_ATI = 0x00000001, - GL_4X_BIT_ATI = 0x00000002, - GL_8X_BIT_ATI = 0x00000004, - GL_HALF_BIT_ATI = 0x00000008, - GL_QUARTER_BIT_ATI = 0x00000010, - GL_EIGHTH_BIT_ATI = 0x00000020, - GL_SATURATE_BIT_ATI = 0x00000040, - GL_COMP_BIT_ATI = 0x00000002, - GL_NEGATE_BIT_ATI = 0x00000004, - GL_BIAS_BIT_ATI = 0x00000008, - GL_TRACE_OPERATIONS_BIT_MESA = 0x00000001, - GL_TRACE_PRIMITIVES_BIT_MESA = 0x00000002, - GL_TRACE_ARRAYS_BIT_MESA = 0x00000004, - GL_TRACE_TEXTURES_BIT_MESA = 0x00000008, - GL_TRACE_PIXELS_BIT_MESA = 0x00000010, - GL_TRACE_ERRORS_BIT_MESA = 0x00000020, - GL_TRACE_ALL_BITS_MESA = 0x0000FFFF, - GL_BOLD_BIT_NV = 0x00000001, - GL_ITALIC_BIT_NV = 0x00000002, - GL_GLYPH_WIDTH_BIT_NV = 0x00000001, - GL_GLYPH_HEIGHT_BIT_NV = 0x00000002, - GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV = 0x00000004, - GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV = 0x00000008, - GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV = 0x00000010, - GL_GLYPH_VERTICAL_BEARING_X_BIT_NV = 0x00000020, - GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV = 0x00000040, - GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV = 0x00000080, - GL_GLYPH_HAS_KERNING_BIT_NV = 0x00000100, - GL_FONT_X_MIN_BOUNDS_BIT_NV = 0x00010000, - GL_FONT_Y_MIN_BOUNDS_BIT_NV = 0x00020000, - GL_FONT_X_MAX_BOUNDS_BIT_NV = 0x00040000, - GL_FONT_Y_MAX_BOUNDS_BIT_NV = 0x00080000, - GL_FONT_UNITS_PER_EM_BIT_NV = 0x00100000, - GL_FONT_ASCENDER_BIT_NV = 0x00200000, - GL_FONT_DESCENDER_BIT_NV = 0x00400000, - GL_FONT_HEIGHT_BIT_NV = 0x00800000, - GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV = 0x01000000, - GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV = 0x02000000, - GL_FONT_UNDERLINE_POSITION_BIT_NV = 0x04000000, - GL_FONT_UNDERLINE_THICKNESS_BIT_NV = 0x08000000, - GL_FONT_HAS_KERNING_BIT_NV = 0x10000000, - GL_FONT_NUM_GLYPH_INDICES_BIT_NV = 0x20000000, - GL_PERFQUERY_SINGLE_CONTEXT_INTEL = 0x00000000, - GL_PERFQUERY_GLOBAL_CONTEXT_INTEL = 0x00000001, - GL_VERTEX23_BIT_PGI = 0x00000004, - GL_VERTEX4_BIT_PGI = 0x00000008, - GL_COLOR3_BIT_PGI = 0x00010000, - GL_COLOR4_BIT_PGI = 0x00020000, - GL_EDGEFLAG_BIT_PGI = 0x00040000, - GL_INDEX_BIT_PGI = 0x00080000, - GL_MAT_AMBIENT_BIT_PGI = 0x00100000, - GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI = 0x00200000, - GL_MAT_DIFFUSE_BIT_PGI = 0x00400000, - GL_MAT_EMISSION_BIT_PGI = 0x00800000, - GL_MAT_COLOR_INDEXES_BIT_PGI = 0x01000000, - GL_MAT_SHININESS_BIT_PGI = 0x02000000, - GL_MAT_SPECULAR_BIT_PGI = 0x04000000, - GL_NORMAL_BIT_PGI = 0x08000000, - GL_TEXCOORD1_BIT_PGI = 0x10000000, - GL_TEXCOORD2_BIT_PGI = 0x20000000, - GL_TEXCOORD3_BIT_PGI = 0x40000000, - GL_TEXCOORD4_BIT_PGI = 0x80000000, - GL_COLOR_BUFFER_BIT0_QCOM = 0x00000001, - GL_COLOR_BUFFER_BIT1_QCOM = 0x00000002, - GL_COLOR_BUFFER_BIT2_QCOM = 0x00000004, - GL_COLOR_BUFFER_BIT3_QCOM = 0x00000008, - GL_COLOR_BUFFER_BIT4_QCOM = 0x00000010, - GL_COLOR_BUFFER_BIT5_QCOM = 0x00000020, - GL_COLOR_BUFFER_BIT6_QCOM = 0x00000040, - GL_COLOR_BUFFER_BIT7_QCOM = 0x00000080, - GL_DEPTH_BUFFER_BIT0_QCOM = 0x00000100, - GL_DEPTH_BUFFER_BIT1_QCOM = 0x00000200, - GL_DEPTH_BUFFER_BIT2_QCOM = 0x00000400, - GL_DEPTH_BUFFER_BIT3_QCOM = 0x00000800, - GL_DEPTH_BUFFER_BIT4_QCOM = 0x00001000, - GL_DEPTH_BUFFER_BIT5_QCOM = 0x00002000, - GL_DEPTH_BUFFER_BIT6_QCOM = 0x00004000, - GL_DEPTH_BUFFER_BIT7_QCOM = 0x00008000, - GL_STENCIL_BUFFER_BIT0_QCOM = 0x00010000, - GL_STENCIL_BUFFER_BIT1_QCOM = 0x00020000, - GL_STENCIL_BUFFER_BIT2_QCOM = 0x00040000, - GL_STENCIL_BUFFER_BIT3_QCOM = 0x00080000, - GL_STENCIL_BUFFER_BIT4_QCOM = 0x00100000, - GL_STENCIL_BUFFER_BIT5_QCOM = 0x00200000, - GL_STENCIL_BUFFER_BIT6_QCOM = 0x00400000, - GL_STENCIL_BUFFER_BIT7_QCOM = 0x00800000, - GL_MULTISAMPLE_BUFFER_BIT0_QCOM = 0x01000000, - GL_MULTISAMPLE_BUFFER_BIT1_QCOM = 0x02000000, - GL_MULTISAMPLE_BUFFER_BIT2_QCOM = 0x04000000, - GL_MULTISAMPLE_BUFFER_BIT3_QCOM = 0x08000000, - GL_MULTISAMPLE_BUFFER_BIT4_QCOM = 0x10000000, - GL_MULTISAMPLE_BUFFER_BIT5_QCOM = 0x20000000, - GL_MULTISAMPLE_BUFFER_BIT6_QCOM = 0x40000000, - GL_MULTISAMPLE_BUFFER_BIT7_QCOM = 0x80000000, - GL_TEXTURE_DEFORMATION_BIT_SGIX = 0x00000001, - GL_GEOMETRY_DEFORMATION_BIT_SGIX = 0x00000002, - GL_CONTEXT_FLAG_PROTECTED_CONTENT_BIT_EXT = 0x00000010, -} - diff --git a/gapis/api/gles/api/glenum.api b/gapis/api/gles/api/glenum.api deleted file mode 100644 index e7ec6b9954..0000000000 --- a/gapis/api/gles/api/glenum.api +++ /dev/null @@ -1,5470 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@analyze_usage -enum GLenum { - GL_TERMINATE_SEQUENCE_COMMAND_NV = 0x00000000, - GL_NOP_COMMAND_NV = 0x00000001, - GL_DRAW_ELEMENTS_COMMAND_NV = 0x00000002, - GL_DRAW_ARRAYS_COMMAND_NV = 0x00000003, - GL_DRAW_ELEMENTS_STRIP_COMMAND_NV = 0x00000004, - GL_DRAW_ARRAYS_STRIP_COMMAND_NV = 0x00000005, - GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV = 0x00000006, - GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV = 0x00000007, - GL_ELEMENT_ADDRESS_COMMAND_NV = 0x00000008, - GL_ATTRIBUTE_ADDRESS_COMMAND_NV = 0x00000009, - GL_UNIFORM_ADDRESS_COMMAND_NV = 0x0000000A, - GL_BLEND_COLOR_COMMAND_NV = 0x0000000B, - GL_STENCIL_REF_COMMAND_NV = 0x0000000C, - GL_LINE_WIDTH_COMMAND_NV = 0x0000000D, - GL_POLYGON_OFFSET_COMMAND_NV = 0x0000000E, - GL_ALPHA_REF_COMMAND_NV = 0x0000000F, - GL_VIEWPORT_COMMAND_NV = 0x00000010, - GL_SCISSOR_COMMAND_NV = 0x00000011, - GL_FRONT_FACE_COMMAND_NV = 0x00000012, - GL_LAYOUT_DEFAULT_INTEL = 0x00000000, - GL_LAYOUT_LINEAR_INTEL = 0x00000001, - GL_LAYOUT_LINEAR_CPU_CACHED_INTEL = 0x00000002, - GL_CLOSE_PATH_NV = 0x00000000, - GL_MOVE_TO_NV = 0x00000002, - GL_RELATIVE_MOVE_TO_NV = 0x00000003, - GL_LINE_TO_NV = 0x00000004, - GL_RELATIVE_LINE_TO_NV = 0x00000005, - GL_HORIZONTAL_LINE_TO_NV = 0x00000006, - GL_RELATIVE_HORIZONTAL_LINE_TO_NV = 0x00000007, - GL_VERTICAL_LINE_TO_NV = 0x00000008, - GL_RELATIVE_VERTICAL_LINE_TO_NV = 0x00000009, - GL_QUADRATIC_CURVE_TO_NV = 0x0000000A, - GL_RELATIVE_QUADRATIC_CURVE_TO_NV = 0x0000000B, - GL_CUBIC_CURVE_TO_NV = 0x0000000C, - GL_RELATIVE_CUBIC_CURVE_TO_NV = 0x0000000D, - GL_SMOOTH_QUADRATIC_CURVE_TO_NV = 0x0000000E, - GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV = 0x0000000F, - GL_SMOOTH_CUBIC_CURVE_TO_NV = 0x00000010, - GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV = 0x00000011, - GL_SMALL_CCW_ARC_TO_NV = 0x00000012, - GL_RELATIVE_SMALL_CCW_ARC_TO_NV = 0x00000013, - GL_SMALL_CW_ARC_TO_NV = 0x00000014, - GL_RELATIVE_SMALL_CW_ARC_TO_NV = 0x00000015, - GL_LARGE_CCW_ARC_TO_NV = 0x00000016, - GL_RELATIVE_LARGE_CCW_ARC_TO_NV = 0x00000017, - GL_LARGE_CW_ARC_TO_NV = 0x00000018, - GL_RELATIVE_LARGE_CW_ARC_TO_NV = 0x00000019, - GL_CONIC_CURVE_TO_NV = 0x0000001A, - GL_RELATIVE_CONIC_CURVE_TO_NV = 0x0000001B, - GL_SHARED_EDGE_NV = 0x000000C0, - GL_ROUNDED_RECT_NV = 0x000000E8, - GL_RELATIVE_ROUNDED_RECT_NV = 0x000000E9, - GL_ROUNDED_RECT2_NV = 0x000000EA, - GL_RELATIVE_ROUNDED_RECT2_NV = 0x000000EB, - GL_ROUNDED_RECT4_NV = 0x000000EC, - GL_RELATIVE_ROUNDED_RECT4_NV = 0x000000ED, - GL_ROUNDED_RECT8_NV = 0x000000EE, - GL_RELATIVE_ROUNDED_RECT8_NV = 0x000000EF, - GL_RESTART_PATH_NV = 0x000000F0, - GL_DUP_FIRST_CUBIC_CURVE_TO_NV = 0x000000F2, - GL_DUP_LAST_CUBIC_CURVE_TO_NV = 0x000000F4, - GL_RECT_NV = 0x000000F6, - GL_RELATIVE_RECT_NV = 0x000000F7, - GL_CIRCULAR_CCW_ARC_TO_NV = 0x000000F8, - GL_CIRCULAR_CW_ARC_TO_NV = 0x000000FA, - GL_CIRCULAR_TANGENT_ARC_TO_NV = 0x000000FC, - GL_ARC_TO_NV = 0x000000FE, - GL_RELATIVE_ARC_TO_NV = 0x000000FF, - GL_NEXT_BUFFER_NV = 0xFFFFFFFE, - GL_SKIP_COMPONENTS4_NV = 0xFFFFFFFD, - GL_SKIP_COMPONENTS3_NV = 0xFFFFFFFC, - GL_SKIP_COMPONENTS2_NV = 0xFFFFFFFB, - GL_SKIP_COMPONENTS1_NV = 0xFFFFFFFA, - GL_RESTART_SUN = 0x00000001, - GL_REPLACE_MIDDLE_SUN = 0x00000002, - GL_REPLACE_OLDEST_SUN = 0x00000003, - GL_NO_ERROR = 0x00000000, - GL_ZERO = 0x00000000, - GL_NONE = 0x00000000, - GL_NONE_OES = 0x00000000, - GL_ONE = 0x00000001, - GL_INVALID_INDEX = 0xFFFFFFFF, - GL_VERSION_ES_CL_1_0 = 0x00000001, - GL_VERSION_ES_CM_1_1 = 0x00000001, - GL_VERSION_ES_CL_1_1 = 0x00000001, - GL_POINTS = 0x00000000, - GL_LINES = 0x00000001, - GL_LINE_LOOP = 0x00000002, - GL_LINE_STRIP = 0x00000003, - GL_TRIANGLES = 0x00000004, - GL_TRIANGLE_STRIP = 0x00000005, - GL_TRIANGLE_FAN = 0x00000006, - GL_QUADS = 0x00000007, - GL_QUADS_EXT = 0x00000007, - GL_QUADS_OES = 0x00000007, - GL_QUAD_STRIP = 0x00000008, - GL_POLYGON = 0x00000009, - GL_LINES_ADJACENCY = 0x0000000A, - GL_LINES_ADJACENCY_ARB = 0x0000000A, - GL_LINES_ADJACENCY_EXT = 0x0000000A, - GL_LINES_ADJACENCY_OES = 0x0000000A, - GL_LINE_STRIP_ADJACENCY = 0x0000000B, - GL_LINE_STRIP_ADJACENCY_ARB = 0x0000000B, - GL_LINE_STRIP_ADJACENCY_EXT = 0x0000000B, - GL_LINE_STRIP_ADJACENCY_OES = 0x0000000B, - GL_TRIANGLES_ADJACENCY = 0x0000000C, - GL_TRIANGLES_ADJACENCY_ARB = 0x0000000C, - GL_TRIANGLES_ADJACENCY_EXT = 0x0000000C, - GL_TRIANGLES_ADJACENCY_OES = 0x0000000C, - GL_TRIANGLE_STRIP_ADJACENCY = 0x0000000D, - GL_TRIANGLE_STRIP_ADJACENCY_ARB = 0x0000000D, - GL_TRIANGLE_STRIP_ADJACENCY_EXT = 0x0000000D, - GL_TRIANGLE_STRIP_ADJACENCY_OES = 0x0000000D, - GL_PATCHES = 0x0000000E, - GL_PATCHES_EXT = 0x0000000E, - GL_PATCHES_OES = 0x0000000E, - GL_ACCUM = 0x00000100, - GL_LOAD = 0x00000101, - GL_RETURN = 0x00000102, - GL_MULT = 0x00000103, - GL_ADD = 0x00000104, - GL_NEVER = 0x00000200, - GL_LESS = 0x00000201, - GL_EQUAL = 0x00000202, - GL_LEQUAL = 0x00000203, - GL_GREATER = 0x00000204, - GL_NOTEQUAL = 0x00000205, - GL_GEQUAL = 0x00000206, - GL_ALWAYS = 0x00000207, - GL_SRC_COLOR = 0x00000300, - GL_ONE_MINUS_SRC_COLOR = 0x00000301, - GL_SRC_ALPHA = 0x00000302, - GL_ONE_MINUS_SRC_ALPHA = 0x00000303, - GL_DST_ALPHA = 0x00000304, - GL_ONE_MINUS_DST_ALPHA = 0x00000305, - GL_DST_COLOR = 0x00000306, - GL_ONE_MINUS_DST_COLOR = 0x00000307, - GL_SRC_ALPHA_SATURATE = 0x00000308, - GL_SRC_ALPHA_SATURATE_EXT = 0x00000308, - GL_FRONT_LEFT = 0x00000400, - GL_FRONT_RIGHT = 0x00000401, - GL_BACK_LEFT = 0x00000402, - GL_BACK_RIGHT = 0x00000403, - GL_FRONT = 0x00000404, - GL_BACK = 0x00000405, - GL_LEFT = 0x00000406, - GL_RIGHT = 0x00000407, - GL_FRONT_AND_BACK = 0x00000408, - GL_AUX0 = 0x00000409, - GL_AUX1 = 0x0000040A, - GL_AUX2 = 0x0000040B, - GL_AUX3 = 0x0000040C, - GL_INVALID_ENUM = 0x00000500, - GL_INVALID_VALUE = 0x00000501, - GL_INVALID_OPERATION = 0x00000502, - GL_STACK_OVERFLOW = 0x00000503, - GL_STACK_OVERFLOW_KHR = 0x00000503, - GL_STACK_UNDERFLOW = 0x00000504, - GL_STACK_UNDERFLOW_KHR = 0x00000504, - GL_OUT_OF_MEMORY = 0x00000505, - GL_INVALID_FRAMEBUFFER_OPERATION = 0x00000506, - GL_INVALID_FRAMEBUFFER_OPERATION_EXT = 0x00000506, - GL_INVALID_FRAMEBUFFER_OPERATION_OES = 0x00000506, - GL_CONTEXT_LOST = 0x00000507, - GL_CONTEXT_LOST_KHR = 0x00000507, - GL_2D = 0x00000600, - GL_3D = 0x00000601, - GL_3D_COLOR = 0x00000602, - GL_3D_COLOR_TEXTURE = 0x00000603, - GL_4D_COLOR_TEXTURE = 0x00000604, - GL_PASS_THROUGH_TOKEN = 0x00000700, - GL_POINT_TOKEN = 0x00000701, - GL_LINE_TOKEN = 0x00000702, - GL_POLYGON_TOKEN = 0x00000703, - GL_BITMAP_TOKEN = 0x00000704, - GL_DRAW_PIXEL_TOKEN = 0x00000705, - GL_COPY_PIXEL_TOKEN = 0x00000706, - GL_LINE_RESET_TOKEN = 0x00000707, - GL_EXP = 0x00000800, - GL_EXP2 = 0x00000801, - GL_CW = 0x00000900, - GL_CCW = 0x00000901, - GL_COEFF = 0x00000A00, - GL_ORDER = 0x00000A01, - GL_DOMAIN = 0x00000A02, - GL_CURRENT_COLOR = 0x00000B00, - GL_CURRENT_INDEX = 0x00000B01, - GL_CURRENT_NORMAL = 0x00000B02, - GL_CURRENT_TEXTURE_COORDS = 0x00000B03, - GL_CURRENT_RASTER_COLOR = 0x00000B04, - GL_CURRENT_RASTER_INDEX = 0x00000B05, - GL_CURRENT_RASTER_TEXTURE_COORDS = 0x00000B06, - GL_CURRENT_RASTER_POSITION = 0x00000B07, - GL_CURRENT_RASTER_POSITION_VALID = 0x00000B08, - GL_CURRENT_RASTER_DISTANCE = 0x00000B09, - GL_POINT_SMOOTH = 0x00000B10, - GL_POINT_SIZE = 0x00000B11, - GL_POINT_SIZE_RANGE = 0x00000B12, - GL_SMOOTH_POINT_SIZE_RANGE = 0x00000B12, - GL_POINT_SIZE_GRANULARITY = 0x00000B13, - GL_SMOOTH_POINT_SIZE_GRANULARITY = 0x00000B13, - GL_LINE_SMOOTH = 0x00000B20, - GL_LINE_WIDTH = 0x00000B21, - GL_LINE_WIDTH_RANGE = 0x00000B22, - GL_SMOOTH_LINE_WIDTH_RANGE = 0x00000B22, - GL_LINE_WIDTH_GRANULARITY = 0x00000B23, - GL_SMOOTH_LINE_WIDTH_GRANULARITY = 0x00000B23, - GL_LINE_STIPPLE = 0x00000B24, - GL_LINE_STIPPLE_PATTERN = 0x00000B25, - GL_LINE_STIPPLE_REPEAT = 0x00000B26, - GL_LIST_MODE = 0x00000B30, - GL_MAX_LIST_NESTING = 0x00000B31, - GL_LIST_BASE = 0x00000B32, - GL_LIST_INDEX = 0x00000B33, - GL_POLYGON_MODE = 0x00000B40, - GL_POLYGON_MODE_NV = 0x00000B40, - GL_POLYGON_SMOOTH = 0x00000B41, - GL_POLYGON_STIPPLE = 0x00000B42, - GL_EDGE_FLAG = 0x00000B43, - GL_CULL_FACE = 0x00000B44, - GL_CULL_FACE_MODE = 0x00000B45, - GL_FRONT_FACE = 0x00000B46, - GL_LIGHTING = 0x00000B50, - GL_LIGHT_MODEL_LOCAL_VIEWER = 0x00000B51, - GL_LIGHT_MODEL_TWO_SIDE = 0x00000B52, - GL_LIGHT_MODEL_AMBIENT = 0x00000B53, - GL_SHADE_MODEL = 0x00000B54, - GL_COLOR_MATERIAL_FACE = 0x00000B55, - GL_COLOR_MATERIAL_PARAMETER = 0x00000B56, - GL_COLOR_MATERIAL = 0x00000B57, - GL_FOG = 0x00000B60, - GL_FOG_INDEX = 0x00000B61, - GL_FOG_DENSITY = 0x00000B62, - GL_FOG_START = 0x00000B63, - GL_FOG_END = 0x00000B64, - GL_FOG_MODE = 0x00000B65, - GL_FOG_COLOR = 0x00000B66, - GL_DEPTH_RANGE = 0x00000B70, - GL_DEPTH_TEST = 0x00000B71, - GL_DEPTH_WRITEMASK = 0x00000B72, - GL_DEPTH_CLEAR_VALUE = 0x00000B73, - GL_DEPTH_FUNC = 0x00000B74, - GL_ACCUM_CLEAR_VALUE = 0x00000B80, - GL_STENCIL_TEST = 0x00000B90, - GL_STENCIL_CLEAR_VALUE = 0x00000B91, - GL_STENCIL_FUNC = 0x00000B92, - GL_STENCIL_VALUE_MASK = 0x00000B93, - GL_STENCIL_FAIL = 0x00000B94, - GL_STENCIL_PASS_DEPTH_FAIL = 0x00000B95, - GL_STENCIL_PASS_DEPTH_PASS = 0x00000B96, - GL_STENCIL_REF = 0x00000B97, - GL_STENCIL_WRITEMASK = 0x00000B98, - GL_MATRIX_MODE = 0x00000BA0, - GL_NORMALIZE = 0x00000BA1, - GL_VIEWPORT = 0x00000BA2, - GL_MODELVIEW_STACK_DEPTH = 0x00000BA3, - GL_MODELVIEW0_STACK_DEPTH_EXT = 0x00000BA3, - GL_PATH_MODELVIEW_STACK_DEPTH_NV = 0x00000BA3, - GL_PROJECTION_STACK_DEPTH = 0x00000BA4, - GL_PATH_PROJECTION_STACK_DEPTH_NV = 0x00000BA4, - GL_TEXTURE_STACK_DEPTH = 0x00000BA5, - GL_MODELVIEW_MATRIX = 0x00000BA6, - GL_MODELVIEW0_MATRIX_EXT = 0x00000BA6, - GL_PATH_MODELVIEW_MATRIX_NV = 0x00000BA6, - GL_PROJECTION_MATRIX = 0x00000BA7, - GL_PATH_PROJECTION_MATRIX_NV = 0x00000BA7, - GL_TEXTURE_MATRIX = 0x00000BA8, - GL_ATTRIB_STACK_DEPTH = 0x00000BB0, - GL_CLIENT_ATTRIB_STACK_DEPTH = 0x00000BB1, - GL_ALPHA_TEST = 0x00000BC0, - GL_ALPHA_TEST_QCOM = 0x00000BC0, - GL_ALPHA_TEST_FUNC = 0x00000BC1, - GL_ALPHA_TEST_FUNC_QCOM = 0x00000BC1, - GL_ALPHA_TEST_REF = 0x00000BC2, - GL_ALPHA_TEST_REF_QCOM = 0x00000BC2, - GL_DITHER = 0x00000BD0, - GL_BLEND_DST = 0x00000BE0, - GL_BLEND_SRC = 0x00000BE1, - GL_BLEND = 0x00000BE2, - GL_LOGIC_OP_MODE = 0x00000BF0, - GL_INDEX_LOGIC_OP = 0x00000BF1, - GL_LOGIC_OP = 0x00000BF1, - GL_COLOR_LOGIC_OP = 0x00000BF2, - GL_AUX_BUFFERS = 0x00000C00, - GL_DRAW_BUFFER = 0x00000C01, - GL_DRAW_BUFFER_EXT = 0x00000C01, - GL_READ_BUFFER = 0x00000C02, - GL_READ_BUFFER_EXT = 0x00000C02, - GL_READ_BUFFER_NV = 0x00000C02, - GL_SCISSOR_BOX = 0x00000C10, - GL_SCISSOR_TEST = 0x00000C11, - GL_INDEX_CLEAR_VALUE = 0x00000C20, - GL_INDEX_WRITEMASK = 0x00000C21, - GL_COLOR_CLEAR_VALUE = 0x00000C22, - GL_COLOR_WRITEMASK = 0x00000C23, - GL_INDEX_MODE = 0x00000C30, - GL_RGBA_MODE = 0x00000C31, - GL_DOUBLEBUFFER = 0x00000C32, - GL_STEREO = 0x00000C33, - GL_RENDER_MODE = 0x00000C40, - GL_PERSPECTIVE_CORRECTION_HINT = 0x00000C50, - GL_POINT_SMOOTH_HINT = 0x00000C51, - GL_LINE_SMOOTH_HINT = 0x00000C52, - GL_POLYGON_SMOOTH_HINT = 0x00000C53, - GL_FOG_HINT = 0x00000C54, - GL_TEXTURE_GEN_S = 0x00000C60, - GL_TEXTURE_GEN_T = 0x00000C61, - GL_TEXTURE_GEN_R = 0x00000C62, - GL_TEXTURE_GEN_Q = 0x00000C63, - GL_PIXEL_MAP_I_TO_I = 0x00000C70, - GL_PIXEL_MAP_S_TO_S = 0x00000C71, - GL_PIXEL_MAP_I_TO_R = 0x00000C72, - GL_PIXEL_MAP_I_TO_G = 0x00000C73, - GL_PIXEL_MAP_I_TO_B = 0x00000C74, - GL_PIXEL_MAP_I_TO_A = 0x00000C75, - GL_PIXEL_MAP_R_TO_R = 0x00000C76, - GL_PIXEL_MAP_G_TO_G = 0x00000C77, - GL_PIXEL_MAP_B_TO_B = 0x00000C78, - GL_PIXEL_MAP_A_TO_A = 0x00000C79, - GL_PIXEL_MAP_I_TO_I_SIZE = 0x00000CB0, - GL_PIXEL_MAP_S_TO_S_SIZE = 0x00000CB1, - GL_PIXEL_MAP_I_TO_R_SIZE = 0x00000CB2, - GL_PIXEL_MAP_I_TO_G_SIZE = 0x00000CB3, - GL_PIXEL_MAP_I_TO_B_SIZE = 0x00000CB4, - GL_PIXEL_MAP_I_TO_A_SIZE = 0x00000CB5, - GL_PIXEL_MAP_R_TO_R_SIZE = 0x00000CB6, - GL_PIXEL_MAP_G_TO_G_SIZE = 0x00000CB7, - GL_PIXEL_MAP_B_TO_B_SIZE = 0x00000CB8, - GL_PIXEL_MAP_A_TO_A_SIZE = 0x00000CB9, - GL_UNPACK_SWAP_BYTES = 0x00000CF0, - GL_UNPACK_LSB_FIRST = 0x00000CF1, - GL_UNPACK_ROW_LENGTH = 0x00000CF2, - GL_UNPACK_ROW_LENGTH_EXT = 0x00000CF2, - GL_UNPACK_SKIP_ROWS = 0x00000CF3, - GL_UNPACK_SKIP_ROWS_EXT = 0x00000CF3, - GL_UNPACK_SKIP_PIXELS = 0x00000CF4, - GL_UNPACK_SKIP_PIXELS_EXT = 0x00000CF4, - GL_UNPACK_ALIGNMENT = 0x00000CF5, - GL_PACK_SWAP_BYTES = 0x00000D00, - GL_PACK_LSB_FIRST = 0x00000D01, - GL_PACK_ROW_LENGTH = 0x00000D02, - GL_PACK_SKIP_ROWS = 0x00000D03, - GL_PACK_SKIP_PIXELS = 0x00000D04, - GL_PACK_ALIGNMENT = 0x00000D05, - GL_MAP_COLOR = 0x00000D10, - GL_MAP_STENCIL = 0x00000D11, - GL_INDEX_SHIFT = 0x00000D12, - GL_INDEX_OFFSET = 0x00000D13, - GL_RED_SCALE = 0x00000D14, - GL_RED_BIAS = 0x00000D15, - GL_ZOOM_X = 0x00000D16, - GL_ZOOM_Y = 0x00000D17, - GL_GREEN_SCALE = 0x00000D18, - GL_GREEN_BIAS = 0x00000D19, - GL_BLUE_SCALE = 0x00000D1A, - GL_BLUE_BIAS = 0x00000D1B, - GL_ALPHA_SCALE = 0x00000D1C, - GL_ALPHA_BIAS = 0x00000D1D, - GL_DEPTH_SCALE = 0x00000D1E, - GL_DEPTH_BIAS = 0x00000D1F, - GL_MAX_EVAL_ORDER = 0x00000D30, - GL_MAX_LIGHTS = 0x00000D31, - GL_MAX_CLIP_PLANES = 0x00000D32, - GL_MAX_CLIP_PLANES_IMG = 0x00000D32, - GL_MAX_CLIP_DISTANCES = 0x00000D32, - GL_MAX_CLIP_DISTANCES_APPLE = 0x00000D32, - GL_MAX_TEXTURE_SIZE = 0x00000D33, - GL_MAX_PIXEL_MAP_TABLE = 0x00000D34, - GL_MAX_ATTRIB_STACK_DEPTH = 0x00000D35, - GL_MAX_MODELVIEW_STACK_DEPTH = 0x00000D36, - GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV = 0x00000D36, - GL_MAX_NAME_STACK_DEPTH = 0x00000D37, - GL_MAX_PROJECTION_STACK_DEPTH = 0x00000D38, - GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV = 0x00000D38, - GL_MAX_TEXTURE_STACK_DEPTH = 0x00000D39, - GL_MAX_VIEWPORT_DIMS = 0x00000D3A, - GL_MAX_CLIENT_ATTRIB_STACK_DEPTH = 0x00000D3B, - GL_SUBPIXEL_BITS = 0x00000D50, - GL_INDEX_BITS = 0x00000D51, - GL_RED_BITS = 0x00000D52, - GL_GREEN_BITS = 0x00000D53, - GL_BLUE_BITS = 0x00000D54, - GL_ALPHA_BITS = 0x00000D55, - GL_DEPTH_BITS = 0x00000D56, - GL_STENCIL_BITS = 0x00000D57, - GL_ACCUM_RED_BITS = 0x00000D58, - GL_ACCUM_GREEN_BITS = 0x00000D59, - GL_ACCUM_BLUE_BITS = 0x00000D5A, - GL_ACCUM_ALPHA_BITS = 0x00000D5B, - GL_NAME_STACK_DEPTH = 0x00000D70, - GL_AUTO_NORMAL = 0x00000D80, - GL_MAP1_COLOR_4 = 0x00000D90, - GL_MAP1_INDEX = 0x00000D91, - GL_MAP1_NORMAL = 0x00000D92, - GL_MAP1_TEXTURE_COORD_1 = 0x00000D93, - GL_MAP1_TEXTURE_COORD_2 = 0x00000D94, - GL_MAP1_TEXTURE_COORD_3 = 0x00000D95, - GL_MAP1_TEXTURE_COORD_4 = 0x00000D96, - GL_MAP1_VERTEX_3 = 0x00000D97, - GL_MAP1_VERTEX_4 = 0x00000D98, - GL_MAP2_COLOR_4 = 0x00000DB0, - GL_MAP2_INDEX = 0x00000DB1, - GL_MAP2_NORMAL = 0x00000DB2, - GL_MAP2_TEXTURE_COORD_1 = 0x00000DB3, - GL_MAP2_TEXTURE_COORD_2 = 0x00000DB4, - GL_MAP2_TEXTURE_COORD_3 = 0x00000DB5, - GL_MAP2_TEXTURE_COORD_4 = 0x00000DB6, - GL_MAP2_VERTEX_3 = 0x00000DB7, - GL_MAP2_VERTEX_4 = 0x00000DB8, - GL_MAP1_GRID_DOMAIN = 0x00000DD0, - GL_MAP1_GRID_SEGMENTS = 0x00000DD1, - GL_MAP2_GRID_DOMAIN = 0x00000DD2, - GL_MAP2_GRID_SEGMENTS = 0x00000DD3, - GL_TEXTURE_1D = 0x00000DE0, - GL_TEXTURE_2D = 0x00000DE1, - GL_FEEDBACK_BUFFER_POINTER = 0x00000DF0, - GL_FEEDBACK_BUFFER_SIZE = 0x00000DF1, - GL_FEEDBACK_BUFFER_TYPE = 0x00000DF2, - GL_SELECTION_BUFFER_POINTER = 0x00000DF3, - GL_SELECTION_BUFFER_SIZE = 0x00000DF4, - GL_TEXTURE_WIDTH = 0x00001000, - GL_TEXTURE_HEIGHT = 0x00001001, - GL_TEXTURE_INTERNAL_FORMAT = 0x00001003, - GL_TEXTURE_COMPONENTS = 0x00001003, - GL_TEXTURE_BORDER_COLOR = 0x00001004, - GL_TEXTURE_BORDER_COLOR_EXT = 0x00001004, - GL_TEXTURE_BORDER_COLOR_NV = 0x00001004, - GL_TEXTURE_BORDER_COLOR_OES = 0x00001004, - GL_TEXTURE_BORDER = 0x00001005, - GL_TEXTURE_TARGET = 0x00001006, - GL_DONT_CARE = 0x00001100, - GL_FASTEST = 0x00001101, - GL_NICEST = 0x00001102, - GL_AMBIENT = 0x00001200, - GL_DIFFUSE = 0x00001201, - GL_SPECULAR = 0x00001202, - GL_POSITION = 0x00001203, - GL_SPOT_DIRECTION = 0x00001204, - GL_SPOT_EXPONENT = 0x00001205, - GL_SPOT_CUTOFF = 0x00001206, - GL_CONSTANT_ATTENUATION = 0x00001207, - GL_LINEAR_ATTENUATION = 0x00001208, - GL_QUADRATIC_ATTENUATION = 0x00001209, - GL_COMPILE = 0x00001300, - GL_COMPILE_AND_EXECUTE = 0x00001301, - GL_BYTE = 0x00001400, - GL_UNSIGNED_BYTE = 0x00001401, - GL_SHORT = 0x00001402, - GL_UNSIGNED_SHORT = 0x00001403, - GL_INT = 0x00001404, - GL_UNSIGNED_INT = 0x00001405, - GL_FLOAT = 0x00001406, - GL_2_BYTES = 0x00001407, - GL_2_BYTES_NV = 0x00001407, - GL_3_BYTES = 0x00001408, - GL_3_BYTES_NV = 0x00001408, - GL_4_BYTES = 0x00001409, - GL_4_BYTES_NV = 0x00001409, - GL_DOUBLE = 0x0000140A, - GL_DOUBLE_EXT = 0x0000140A, - GL_HALF_FLOAT = 0x0000140B, - GL_HALF_FLOAT_ARB = 0x0000140B, - GL_HALF_FLOAT_NV = 0x0000140B, - GL_HALF_APPLE = 0x0000140B, - GL_FIXED = 0x0000140C, - GL_FIXED_OES = 0x0000140C, - GL_INT64_ARB = 0x0000140E, - GL_INT64_NV = 0x0000140E, - GL_UNSIGNED_INT64_ARB = 0x0000140F, - GL_UNSIGNED_INT64_NV = 0x0000140F, - GL_CLEAR = 0x00001500, - GL_AND = 0x00001501, - GL_AND_REVERSE = 0x00001502, - GL_COPY = 0x00001503, - GL_AND_INVERTED = 0x00001504, - GL_NOOP = 0x00001505, - GL_XOR = 0x00001506, - GL_XOR_NV = 0x00001506, - GL_OR = 0x00001507, - GL_NOR = 0x00001508, - GL_EQUIV = 0x00001509, - GL_INVERT = 0x0000150A, - GL_OR_REVERSE = 0x0000150B, - GL_COPY_INVERTED = 0x0000150C, - GL_OR_INVERTED = 0x0000150D, - GL_NAND = 0x0000150E, - GL_SET = 0x0000150F, - GL_EMISSION = 0x00001600, - GL_SHININESS = 0x00001601, - GL_AMBIENT_AND_DIFFUSE = 0x00001602, - GL_COLOR_INDEXES = 0x00001603, - GL_MODELVIEW = 0x00001700, - GL_MODELVIEW0_ARB = 0x00001700, - GL_MODELVIEW0_EXT = 0x00001700, - GL_PATH_MODELVIEW_NV = 0x00001700, - GL_PROJECTION = 0x00001701, - GL_PATH_PROJECTION_NV = 0x00001701, - GL_TEXTURE = 0x00001702, - GL_COLOR = 0x00001800, - GL_COLOR_EXT = 0x00001800, - GL_DEPTH = 0x00001801, - GL_DEPTH_EXT = 0x00001801, - GL_STENCIL = 0x00001802, - GL_STENCIL_EXT = 0x00001802, - GL_COLOR_INDEX = 0x00001900, - GL_STENCIL_INDEX = 0x00001901, - GL_STENCIL_INDEX_OES = 0x00001901, - GL_DEPTH_COMPONENT = 0x00001902, - GL_RED = 0x00001903, - GL_RED_EXT = 0x00001903, - GL_RED_NV = 0x00001903, - GL_GREEN = 0x00001904, - GL_GREEN_NV = 0x00001904, - GL_BLUE = 0x00001905, - GL_BLUE_NV = 0x00001905, - GL_ALPHA = 0x00001906, - GL_RGB = 0x00001907, - GL_RGBA = 0x00001908, - GL_LUMINANCE = 0x00001909, - GL_LUMINANCE_ALPHA = 0x0000190A, - GL_BITMAP = 0x00001A00, - GL_POINT = 0x00001B00, - GL_POINT_NV = 0x00001B00, - GL_LINE = 0x00001B01, - GL_LINE_NV = 0x00001B01, - GL_FILL = 0x00001B02, - GL_FILL_NV = 0x00001B02, - GL_RENDER = 0x00001C00, - GL_FEEDBACK = 0x00001C01, - GL_SELECT = 0x00001C02, - GL_FLAT = 0x00001D00, - GL_SMOOTH = 0x00001D01, - GL_KEEP = 0x00001E00, - GL_REPLACE = 0x00001E01, - GL_INCR = 0x00001E02, - GL_DECR = 0x00001E03, - GL_VENDOR = 0x00001F00, - GL_RENDERER = 0x00001F01, - GL_VERSION = 0x00001F02, - GL_EXTENSIONS = 0x00001F03, - GL_S = 0x00002000, - GL_T = 0x00002001, - GL_R = 0x00002002, - GL_Q = 0x00002003, - GL_MODULATE = 0x00002100, - GL_DECAL = 0x00002101, - GL_TEXTURE_ENV_MODE = 0x00002200, - GL_TEXTURE_ENV_COLOR = 0x00002201, - GL_TEXTURE_ENV = 0x00002300, - GL_EYE_LINEAR = 0x00002400, - GL_EYE_LINEAR_NV = 0x00002400, - GL_OBJECT_LINEAR = 0x00002401, - GL_OBJECT_LINEAR_NV = 0x00002401, - GL_SPHERE_MAP = 0x00002402, - GL_TEXTURE_GEN_MODE = 0x00002500, - GL_TEXTURE_GEN_MODE_OES = 0x00002500, - GL_OBJECT_PLANE = 0x00002501, - GL_EYE_PLANE = 0x00002502, - GL_NEAREST = 0x00002600, - GL_LINEAR = 0x00002601, - GL_NEAREST_MIPMAP_NEAREST = 0x00002700, - GL_LINEAR_MIPMAP_NEAREST = 0x00002701, - GL_NEAREST_MIPMAP_LINEAR = 0x00002702, - GL_LINEAR_MIPMAP_LINEAR = 0x00002703, - GL_TEXTURE_MAG_FILTER = 0x00002800, - GL_TEXTURE_MIN_FILTER = 0x00002801, - GL_TEXTURE_WRAP_S = 0x00002802, - GL_TEXTURE_WRAP_T = 0x00002803, - GL_CLAMP = 0x00002900, - GL_REPEAT = 0x00002901, - GL_POLYGON_OFFSET_UNITS = 0x00002A00, - GL_POLYGON_OFFSET_POINT = 0x00002A01, - GL_POLYGON_OFFSET_POINT_NV = 0x00002A01, - GL_POLYGON_OFFSET_LINE = 0x00002A02, - GL_POLYGON_OFFSET_LINE_NV = 0x00002A02, - GL_R3_G3_B2 = 0x00002A10, - GL_V2F = 0x00002A20, - GL_V3F = 0x00002A21, - GL_C4UB_V2F = 0x00002A22, - GL_C4UB_V3F = 0x00002A23, - GL_C3F_V3F = 0x00002A24, - GL_N3F_V3F = 0x00002A25, - GL_C4F_N3F_V3F = 0x00002A26, - GL_T2F_V3F = 0x00002A27, - GL_T4F_V4F = 0x00002A28, - GL_T2F_C4UB_V3F = 0x00002A29, - GL_T2F_C3F_V3F = 0x00002A2A, - GL_T2F_N3F_V3F = 0x00002A2B, - GL_T2F_C4F_N3F_V3F = 0x00002A2C, - GL_T4F_C4F_N3F_V4F = 0x00002A2D, - GL_CLIP_PLANE0 = 0x00003000, - GL_CLIP_PLANE0_IMG = 0x00003000, - GL_CLIP_DISTANCE0 = 0x00003000, - GL_CLIP_DISTANCE0_APPLE = 0x00003000, - GL_CLIP_PLANE1 = 0x00003001, - GL_CLIP_PLANE1_IMG = 0x00003001, - GL_CLIP_DISTANCE1 = 0x00003001, - GL_CLIP_DISTANCE1_APPLE = 0x00003001, - GL_CLIP_PLANE2 = 0x00003002, - GL_CLIP_PLANE2_IMG = 0x00003002, - GL_CLIP_DISTANCE2 = 0x00003002, - GL_CLIP_DISTANCE2_APPLE = 0x00003002, - GL_CLIP_PLANE3 = 0x00003003, - GL_CLIP_PLANE3_IMG = 0x00003003, - GL_CLIP_DISTANCE3 = 0x00003003, - GL_CLIP_DISTANCE3_APPLE = 0x00003003, - GL_CLIP_PLANE4 = 0x00003004, - GL_CLIP_PLANE4_IMG = 0x00003004, - GL_CLIP_DISTANCE4 = 0x00003004, - GL_CLIP_DISTANCE4_APPLE = 0x00003004, - GL_CLIP_PLANE5 = 0x00003005, - GL_CLIP_PLANE5_IMG = 0x00003005, - GL_CLIP_DISTANCE5 = 0x00003005, - GL_CLIP_DISTANCE5_APPLE = 0x00003005, - GL_CLIP_DISTANCE6 = 0x00003006, - GL_CLIP_DISTANCE6_APPLE = 0x00003006, - GL_CLIP_DISTANCE7 = 0x00003007, - GL_CLIP_DISTANCE7_APPLE = 0x00003007, - GL_LIGHT0 = 0x00004000, - GL_LIGHT1 = 0x00004001, - GL_LIGHT2 = 0x00004002, - GL_LIGHT3 = 0x00004003, - GL_LIGHT4 = 0x00004004, - GL_LIGHT5 = 0x00004005, - GL_LIGHT6 = 0x00004006, - GL_LIGHT7 = 0x00004007, - GL_ABGR_EXT = 0x00008000, - GL_CONSTANT_COLOR = 0x00008001, - GL_CONSTANT_COLOR_EXT = 0x00008001, - GL_ONE_MINUS_CONSTANT_COLOR = 0x00008002, - GL_ONE_MINUS_CONSTANT_COLOR_EXT = 0x00008002, - GL_CONSTANT_ALPHA = 0x00008003, - GL_CONSTANT_ALPHA_EXT = 0x00008003, - GL_ONE_MINUS_CONSTANT_ALPHA = 0x00008004, - GL_ONE_MINUS_CONSTANT_ALPHA_EXT = 0x00008004, - GL_BLEND_COLOR = 0x00008005, - GL_BLEND_COLOR_EXT = 0x00008005, - GL_FUNC_ADD = 0x00008006, - GL_FUNC_ADD_EXT = 0x00008006, - GL_FUNC_ADD_OES = 0x00008006, - GL_MIN = 0x00008007, - GL_MIN_EXT = 0x00008007, - GL_MAX = 0x00008008, - GL_MAX_EXT = 0x00008008, - GL_BLEND_EQUATION = 0x00008009, - GL_BLEND_EQUATION_EXT = 0x00008009, - GL_BLEND_EQUATION_OES = 0x00008009, - GL_BLEND_EQUATION_RGB = 0x00008009, - GL_BLEND_EQUATION_RGB_EXT = 0x00008009, - GL_BLEND_EQUATION_RGB_OES = 0x00008009, - GL_FUNC_SUBTRACT = 0x0000800A, - GL_FUNC_SUBTRACT_EXT = 0x0000800A, - GL_FUNC_SUBTRACT_OES = 0x0000800A, - GL_FUNC_REVERSE_SUBTRACT = 0x0000800B, - GL_FUNC_REVERSE_SUBTRACT_EXT = 0x0000800B, - GL_FUNC_REVERSE_SUBTRACT_OES = 0x0000800B, - GL_CMYK_EXT = 0x0000800C, - GL_CMYKA_EXT = 0x0000800D, - GL_PACK_CMYK_HINT_EXT = 0x0000800E, - GL_UNPACK_CMYK_HINT_EXT = 0x0000800F, - GL_CONVOLUTION_1D = 0x00008010, - GL_CONVOLUTION_1D_EXT = 0x00008010, - GL_CONVOLUTION_2D = 0x00008011, - GL_CONVOLUTION_2D_EXT = 0x00008011, - GL_SEPARABLE_2D = 0x00008012, - GL_SEPARABLE_2D_EXT = 0x00008012, - GL_CONVOLUTION_BORDER_MODE = 0x00008013, - GL_CONVOLUTION_BORDER_MODE_EXT = 0x00008013, - GL_CONVOLUTION_FILTER_SCALE = 0x00008014, - GL_CONVOLUTION_FILTER_SCALE_EXT = 0x00008014, - GL_CONVOLUTION_FILTER_BIAS = 0x00008015, - GL_CONVOLUTION_FILTER_BIAS_EXT = 0x00008015, - GL_REDUCE = 0x00008016, - GL_REDUCE_EXT = 0x00008016, - GL_CONVOLUTION_FORMAT = 0x00008017, - GL_CONVOLUTION_FORMAT_EXT = 0x00008017, - GL_CONVOLUTION_WIDTH = 0x00008018, - GL_CONVOLUTION_WIDTH_EXT = 0x00008018, - GL_CONVOLUTION_HEIGHT = 0x00008019, - GL_CONVOLUTION_HEIGHT_EXT = 0x00008019, - GL_MAX_CONVOLUTION_WIDTH = 0x0000801A, - GL_MAX_CONVOLUTION_WIDTH_EXT = 0x0000801A, - GL_MAX_CONVOLUTION_HEIGHT = 0x0000801B, - GL_MAX_CONVOLUTION_HEIGHT_EXT = 0x0000801B, - GL_POST_CONVOLUTION_RED_SCALE = 0x0000801C, - GL_POST_CONVOLUTION_RED_SCALE_EXT = 0x0000801C, - GL_POST_CONVOLUTION_GREEN_SCALE = 0x0000801D, - GL_POST_CONVOLUTION_GREEN_SCALE_EXT = 0x0000801D, - GL_POST_CONVOLUTION_BLUE_SCALE = 0x0000801E, - GL_POST_CONVOLUTION_BLUE_SCALE_EXT = 0x0000801E, - GL_POST_CONVOLUTION_ALPHA_SCALE = 0x0000801F, - GL_POST_CONVOLUTION_ALPHA_SCALE_EXT = 0x0000801F, - GL_POST_CONVOLUTION_RED_BIAS = 0x00008020, - GL_POST_CONVOLUTION_RED_BIAS_EXT = 0x00008020, - GL_POST_CONVOLUTION_GREEN_BIAS = 0x00008021, - GL_POST_CONVOLUTION_GREEN_BIAS_EXT = 0x00008021, - GL_POST_CONVOLUTION_BLUE_BIAS = 0x00008022, - GL_POST_CONVOLUTION_BLUE_BIAS_EXT = 0x00008022, - GL_POST_CONVOLUTION_ALPHA_BIAS = 0x00008023, - GL_POST_CONVOLUTION_ALPHA_BIAS_EXT = 0x00008023, - GL_HISTOGRAM = 0x00008024, - GL_HISTOGRAM_EXT = 0x00008024, - GL_PROXY_HISTOGRAM = 0x00008025, - GL_PROXY_HISTOGRAM_EXT = 0x00008025, - GL_HISTOGRAM_WIDTH = 0x00008026, - GL_HISTOGRAM_WIDTH_EXT = 0x00008026, - GL_HISTOGRAM_FORMAT = 0x00008027, - GL_HISTOGRAM_FORMAT_EXT = 0x00008027, - GL_HISTOGRAM_RED_SIZE = 0x00008028, - GL_HISTOGRAM_RED_SIZE_EXT = 0x00008028, - GL_HISTOGRAM_GREEN_SIZE = 0x00008029, - GL_HISTOGRAM_GREEN_SIZE_EXT = 0x00008029, - GL_HISTOGRAM_BLUE_SIZE = 0x0000802A, - GL_HISTOGRAM_BLUE_SIZE_EXT = 0x0000802A, - GL_HISTOGRAM_ALPHA_SIZE = 0x0000802B, - GL_HISTOGRAM_ALPHA_SIZE_EXT = 0x0000802B, - GL_HISTOGRAM_LUMINANCE_SIZE = 0x0000802C, - GL_HISTOGRAM_LUMINANCE_SIZE_EXT = 0x0000802C, - GL_HISTOGRAM_SINK = 0x0000802D, - GL_HISTOGRAM_SINK_EXT = 0x0000802D, - GL_MINMAX = 0x0000802E, - GL_MINMAX_EXT = 0x0000802E, - GL_MINMAX_FORMAT = 0x0000802F, - GL_MINMAX_FORMAT_EXT = 0x0000802F, - GL_MINMAX_SINK = 0x00008030, - GL_MINMAX_SINK_EXT = 0x00008030, - GL_TABLE_TOO_LARGE_EXT = 0x00008031, - GL_TABLE_TOO_LARGE = 0x00008031, - GL_UNSIGNED_BYTE_3_3_2 = 0x00008032, - GL_UNSIGNED_BYTE_3_3_2_EXT = 0x00008032, - GL_UNSIGNED_SHORT_4_4_4_4 = 0x00008033, - GL_UNSIGNED_SHORT_4_4_4_4_EXT = 0x00008033, - GL_UNSIGNED_SHORT_5_5_5_1 = 0x00008034, - GL_UNSIGNED_SHORT_5_5_5_1_EXT = 0x00008034, - GL_UNSIGNED_INT_8_8_8_8 = 0x00008035, - GL_UNSIGNED_INT_8_8_8_8_EXT = 0x00008035, - GL_UNSIGNED_INT_10_10_10_2 = 0x00008036, - GL_UNSIGNED_INT_10_10_10_2_EXT = 0x00008036, - GL_POLYGON_OFFSET_EXT = 0x00008037, - GL_POLYGON_OFFSET_FILL = 0x00008037, - GL_POLYGON_OFFSET_FACTOR = 0x00008038, - GL_POLYGON_OFFSET_FACTOR_EXT = 0x00008038, - GL_POLYGON_OFFSET_BIAS_EXT = 0x00008039, - GL_RESCALE_NORMAL = 0x0000803A, - GL_RESCALE_NORMAL_EXT = 0x0000803A, - GL_ALPHA4 = 0x0000803B, - GL_ALPHA4_EXT = 0x0000803B, - GL_ALPHA8 = 0x0000803C, - GL_ALPHA8_EXT = 0x0000803C, - GL_ALPHA8_OES = 0x0000803C, - GL_ALPHA12 = 0x0000803D, - GL_ALPHA12_EXT = 0x0000803D, - GL_ALPHA16 = 0x0000803E, - GL_ALPHA16_EXT = 0x0000803E, - GL_LUMINANCE4 = 0x0000803F, - GL_LUMINANCE4_EXT = 0x0000803F, - GL_LUMINANCE8 = 0x00008040, - GL_LUMINANCE8_EXT = 0x00008040, - GL_LUMINANCE8_OES = 0x00008040, - GL_LUMINANCE12 = 0x00008041, - GL_LUMINANCE12_EXT = 0x00008041, - GL_LUMINANCE16 = 0x00008042, - GL_LUMINANCE16_EXT = 0x00008042, - GL_LUMINANCE4_ALPHA4 = 0x00008043, - GL_LUMINANCE4_ALPHA4_EXT = 0x00008043, - GL_LUMINANCE4_ALPHA4_OES = 0x00008043, - GL_LUMINANCE6_ALPHA2 = 0x00008044, - GL_LUMINANCE6_ALPHA2_EXT = 0x00008044, - GL_LUMINANCE8_ALPHA8 = 0x00008045, - GL_LUMINANCE8_ALPHA8_EXT = 0x00008045, - GL_LUMINANCE8_ALPHA8_OES = 0x00008045, - GL_LUMINANCE12_ALPHA4 = 0x00008046, - GL_LUMINANCE12_ALPHA4_EXT = 0x00008046, - GL_LUMINANCE12_ALPHA12 = 0x00008047, - GL_LUMINANCE12_ALPHA12_EXT = 0x00008047, - GL_LUMINANCE16_ALPHA16 = 0x00008048, - GL_LUMINANCE16_ALPHA16_EXT = 0x00008048, - GL_INTENSITY = 0x00008049, - GL_INTENSITY_EXT = 0x00008049, - GL_INTENSITY4 = 0x0000804A, - GL_INTENSITY4_EXT = 0x0000804A, - GL_INTENSITY8 = 0x0000804B, - GL_INTENSITY8_EXT = 0x0000804B, - GL_INTENSITY12 = 0x0000804C, - GL_INTENSITY12_EXT = 0x0000804C, - GL_INTENSITY16 = 0x0000804D, - GL_INTENSITY16_EXT = 0x0000804D, - GL_RGB2_EXT = 0x0000804E, - GL_RGB4 = 0x0000804F, - GL_RGB4_EXT = 0x0000804F, - GL_RGB5 = 0x00008050, - GL_RGB5_EXT = 0x00008050, - GL_RGB8 = 0x00008051, - GL_RGB8_EXT = 0x00008051, - GL_RGB8_OES = 0x00008051, - GL_RGB10 = 0x00008052, - GL_RGB10_EXT = 0x00008052, - GL_RGB12 = 0x00008053, - GL_RGB12_EXT = 0x00008053, - GL_RGB16 = 0x00008054, - GL_RGB16_EXT = 0x00008054, - GL_RGBA2 = 0x00008055, - GL_RGBA2_EXT = 0x00008055, - GL_RGBA4 = 0x00008056, - GL_RGBA4_EXT = 0x00008056, - GL_RGBA4_OES = 0x00008056, - GL_RGB5_A1 = 0x00008057, - GL_RGB5_A1_EXT = 0x00008057, - GL_RGB5_A1_OES = 0x00008057, - GL_RGBA8 = 0x00008058, - GL_RGBA8_EXT = 0x00008058, - GL_RGBA8_OES = 0x00008058, - GL_RGB10_A2 = 0x00008059, - GL_RGB10_A2_EXT = 0x00008059, - GL_RGBA12 = 0x0000805A, - GL_RGBA12_EXT = 0x0000805A, - GL_RGBA16 = 0x0000805B, - GL_RGBA16_EXT = 0x0000805B, - GL_TEXTURE_RED_SIZE = 0x0000805C, - GL_TEXTURE_RED_SIZE_EXT = 0x0000805C, - GL_TEXTURE_GREEN_SIZE = 0x0000805D, - GL_TEXTURE_GREEN_SIZE_EXT = 0x0000805D, - GL_TEXTURE_BLUE_SIZE = 0x0000805E, - GL_TEXTURE_BLUE_SIZE_EXT = 0x0000805E, - GL_TEXTURE_ALPHA_SIZE = 0x0000805F, - GL_TEXTURE_ALPHA_SIZE_EXT = 0x0000805F, - GL_TEXTURE_LUMINANCE_SIZE = 0x00008060, - GL_TEXTURE_LUMINANCE_SIZE_EXT = 0x00008060, - GL_TEXTURE_INTENSITY_SIZE = 0x00008061, - GL_TEXTURE_INTENSITY_SIZE_EXT = 0x00008061, - GL_REPLACE_EXT = 0x00008062, - GL_PROXY_TEXTURE_1D = 0x00008063, - GL_PROXY_TEXTURE_1D_EXT = 0x00008063, - GL_PROXY_TEXTURE_2D = 0x00008064, - GL_PROXY_TEXTURE_2D_EXT = 0x00008064, - GL_TEXTURE_TOO_LARGE_EXT = 0x00008065, - GL_TEXTURE_PRIORITY = 0x00008066, - GL_TEXTURE_PRIORITY_EXT = 0x00008066, - GL_TEXTURE_RESIDENT = 0x00008067, - GL_TEXTURE_RESIDENT_EXT = 0x00008067, - GL_TEXTURE_1D_BINDING_EXT = 0x00008068, - GL_TEXTURE_BINDING_1D = 0x00008068, - GL_TEXTURE_2D_BINDING_EXT = 0x00008069, - GL_TEXTURE_BINDING_2D = 0x00008069, - GL_TEXTURE_3D_BINDING_EXT = 0x0000806A, - GL_TEXTURE_3D_BINDING_OES = 0x0000806A, - GL_TEXTURE_BINDING_3D = 0x0000806A, - GL_TEXTURE_BINDING_3D_OES = 0x0000806A, - GL_PACK_SKIP_IMAGES = 0x0000806B, - GL_PACK_SKIP_IMAGES_EXT = 0x0000806B, - GL_PACK_IMAGE_HEIGHT = 0x0000806C, - GL_PACK_IMAGE_HEIGHT_EXT = 0x0000806C, - GL_UNPACK_SKIP_IMAGES = 0x0000806D, - GL_UNPACK_SKIP_IMAGES_EXT = 0x0000806D, - GL_UNPACK_IMAGE_HEIGHT = 0x0000806E, - GL_UNPACK_IMAGE_HEIGHT_EXT = 0x0000806E, - GL_TEXTURE_3D = 0x0000806F, - GL_TEXTURE_3D_EXT = 0x0000806F, - GL_TEXTURE_3D_OES = 0x0000806F, - GL_PROXY_TEXTURE_3D = 0x00008070, - GL_PROXY_TEXTURE_3D_EXT = 0x00008070, - GL_TEXTURE_DEPTH = 0x00008071, - GL_TEXTURE_DEPTH_EXT = 0x00008071, - GL_TEXTURE_WRAP_R = 0x00008072, - GL_TEXTURE_WRAP_R_EXT = 0x00008072, - GL_TEXTURE_WRAP_R_OES = 0x00008072, - GL_MAX_3D_TEXTURE_SIZE = 0x00008073, - GL_MAX_3D_TEXTURE_SIZE_EXT = 0x00008073, - GL_MAX_3D_TEXTURE_SIZE_OES = 0x00008073, - GL_VERTEX_ARRAY = 0x00008074, - GL_VERTEX_ARRAY_EXT = 0x00008074, - GL_VERTEX_ARRAY_KHR = 0x00008074, - GL_NORMAL_ARRAY = 0x00008075, - GL_NORMAL_ARRAY_EXT = 0x00008075, - GL_COLOR_ARRAY = 0x00008076, - GL_COLOR_ARRAY_EXT = 0x00008076, - GL_INDEX_ARRAY = 0x00008077, - GL_INDEX_ARRAY_EXT = 0x00008077, - GL_TEXTURE_COORD_ARRAY = 0x00008078, - GL_TEXTURE_COORD_ARRAY_EXT = 0x00008078, - GL_EDGE_FLAG_ARRAY = 0x00008079, - GL_EDGE_FLAG_ARRAY_EXT = 0x00008079, - GL_VERTEX_ARRAY_SIZE = 0x0000807A, - GL_VERTEX_ARRAY_SIZE_EXT = 0x0000807A, - GL_VERTEX_ARRAY_TYPE = 0x0000807B, - GL_VERTEX_ARRAY_TYPE_EXT = 0x0000807B, - GL_VERTEX_ARRAY_STRIDE = 0x0000807C, - GL_VERTEX_ARRAY_STRIDE_EXT = 0x0000807C, - GL_VERTEX_ARRAY_COUNT_EXT = 0x0000807D, - GL_NORMAL_ARRAY_TYPE = 0x0000807E, - GL_NORMAL_ARRAY_TYPE_EXT = 0x0000807E, - GL_NORMAL_ARRAY_STRIDE = 0x0000807F, - GL_NORMAL_ARRAY_STRIDE_EXT = 0x0000807F, - GL_NORMAL_ARRAY_COUNT_EXT = 0x00008080, - GL_COLOR_ARRAY_SIZE = 0x00008081, - GL_COLOR_ARRAY_SIZE_EXT = 0x00008081, - GL_COLOR_ARRAY_TYPE = 0x00008082, - GL_COLOR_ARRAY_TYPE_EXT = 0x00008082, - GL_COLOR_ARRAY_STRIDE = 0x00008083, - GL_COLOR_ARRAY_STRIDE_EXT = 0x00008083, - GL_COLOR_ARRAY_COUNT_EXT = 0x00008084, - GL_INDEX_ARRAY_TYPE = 0x00008085, - GL_INDEX_ARRAY_TYPE_EXT = 0x00008085, - GL_INDEX_ARRAY_STRIDE = 0x00008086, - GL_INDEX_ARRAY_STRIDE_EXT = 0x00008086, - GL_INDEX_ARRAY_COUNT_EXT = 0x00008087, - GL_TEXTURE_COORD_ARRAY_SIZE = 0x00008088, - GL_TEXTURE_COORD_ARRAY_SIZE_EXT = 0x00008088, - GL_TEXTURE_COORD_ARRAY_TYPE = 0x00008089, - GL_TEXTURE_COORD_ARRAY_TYPE_EXT = 0x00008089, - GL_TEXTURE_COORD_ARRAY_STRIDE = 0x0000808A, - GL_TEXTURE_COORD_ARRAY_STRIDE_EXT = 0x0000808A, - GL_TEXTURE_COORD_ARRAY_COUNT_EXT = 0x0000808B, - GL_EDGE_FLAG_ARRAY_STRIDE = 0x0000808C, - GL_EDGE_FLAG_ARRAY_STRIDE_EXT = 0x0000808C, - GL_EDGE_FLAG_ARRAY_COUNT_EXT = 0x0000808D, - GL_VERTEX_ARRAY_POINTER = 0x0000808E, - GL_VERTEX_ARRAY_POINTER_EXT = 0x0000808E, - GL_NORMAL_ARRAY_POINTER = 0x0000808F, - GL_NORMAL_ARRAY_POINTER_EXT = 0x0000808F, - GL_COLOR_ARRAY_POINTER = 0x00008090, - GL_COLOR_ARRAY_POINTER_EXT = 0x00008090, - GL_INDEX_ARRAY_POINTER = 0x00008091, - GL_INDEX_ARRAY_POINTER_EXT = 0x00008091, - GL_TEXTURE_COORD_ARRAY_POINTER = 0x00008092, - GL_TEXTURE_COORD_ARRAY_POINTER_EXT = 0x00008092, - GL_EDGE_FLAG_ARRAY_POINTER = 0x00008093, - GL_EDGE_FLAG_ARRAY_POINTER_EXT = 0x00008093, - GL_INTERLACE_SGIX = 0x00008094, - GL_DETAIL_TEXTURE_2D_SGIS = 0x00008095, - GL_DETAIL_TEXTURE_2D_BINDING_SGIS = 0x00008096, - GL_LINEAR_DETAIL_SGIS = 0x00008097, - GL_LINEAR_DETAIL_ALPHA_SGIS = 0x00008098, - GL_LINEAR_DETAIL_COLOR_SGIS = 0x00008099, - GL_DETAIL_TEXTURE_LEVEL_SGIS = 0x0000809A, - GL_DETAIL_TEXTURE_MODE_SGIS = 0x0000809B, - GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS = 0x0000809C, - GL_MULTISAMPLE = 0x0000809D, - GL_MULTISAMPLE_ARB = 0x0000809D, - GL_MULTISAMPLE_EXT = 0x0000809D, - GL_MULTISAMPLE_SGIS = 0x0000809D, - GL_SAMPLE_ALPHA_TO_COVERAGE = 0x0000809E, - GL_SAMPLE_ALPHA_TO_COVERAGE_ARB = 0x0000809E, - GL_SAMPLE_ALPHA_TO_MASK_EXT = 0x0000809E, - GL_SAMPLE_ALPHA_TO_MASK_SGIS = 0x0000809E, - GL_SAMPLE_ALPHA_TO_ONE = 0x0000809F, - GL_SAMPLE_ALPHA_TO_ONE_ARB = 0x0000809F, - GL_SAMPLE_ALPHA_TO_ONE_EXT = 0x0000809F, - GL_SAMPLE_ALPHA_TO_ONE_SGIS = 0x0000809F, - GL_SAMPLE_COVERAGE = 0x000080A0, - GL_SAMPLE_COVERAGE_ARB = 0x000080A0, - GL_SAMPLE_MASK_EXT = 0x000080A0, - GL_SAMPLE_MASK_SGIS = 0x000080A0, - GL_1PASS_EXT = 0x000080A1, - GL_1PASS_SGIS = 0x000080A1, - GL_2PASS_0_EXT = 0x000080A2, - GL_2PASS_0_SGIS = 0x000080A2, - GL_2PASS_1_EXT = 0x000080A3, - GL_2PASS_1_SGIS = 0x000080A3, - GL_4PASS_0_EXT = 0x000080A4, - GL_4PASS_0_SGIS = 0x000080A4, - GL_4PASS_1_EXT = 0x000080A5, - GL_4PASS_1_SGIS = 0x000080A5, - GL_4PASS_2_EXT = 0x000080A6, - GL_4PASS_2_SGIS = 0x000080A6, - GL_4PASS_3_EXT = 0x000080A7, - GL_4PASS_3_SGIS = 0x000080A7, - GL_SAMPLE_BUFFERS = 0x000080A8, - GL_SAMPLE_BUFFERS_ARB = 0x000080A8, - GL_SAMPLE_BUFFERS_EXT = 0x000080A8, - GL_SAMPLE_BUFFERS_SGIS = 0x000080A8, - GL_SAMPLES = 0x000080A9, - GL_SAMPLES_ARB = 0x000080A9, - GL_SAMPLES_EXT = 0x000080A9, - GL_SAMPLES_SGIS = 0x000080A9, - GL_SAMPLE_COVERAGE_VALUE = 0x000080AA, - GL_SAMPLE_COVERAGE_VALUE_ARB = 0x000080AA, - GL_SAMPLE_MASK_VALUE_EXT = 0x000080AA, - GL_SAMPLE_MASK_VALUE_SGIS = 0x000080AA, - GL_SAMPLE_COVERAGE_INVERT = 0x000080AB, - GL_SAMPLE_COVERAGE_INVERT_ARB = 0x000080AB, - GL_SAMPLE_MASK_INVERT_EXT = 0x000080AB, - GL_SAMPLE_MASK_INVERT_SGIS = 0x000080AB, - GL_SAMPLE_PATTERN_EXT = 0x000080AC, - GL_SAMPLE_PATTERN_SGIS = 0x000080AC, - GL_LINEAR_SHARPEN_SGIS = 0x000080AD, - GL_LINEAR_SHARPEN_ALPHA_SGIS = 0x000080AE, - GL_LINEAR_SHARPEN_COLOR_SGIS = 0x000080AF, - GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS = 0x000080B0, - GL_COLOR_MATRIX = 0x000080B1, - GL_COLOR_MATRIX_SGI = 0x000080B1, - GL_COLOR_MATRIX_STACK_DEPTH = 0x000080B2, - GL_COLOR_MATRIX_STACK_DEPTH_SGI = 0x000080B2, - GL_MAX_COLOR_MATRIX_STACK_DEPTH = 0x000080B3, - GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI = 0x000080B3, - GL_POST_COLOR_MATRIX_RED_SCALE = 0x000080B4, - GL_POST_COLOR_MATRIX_RED_SCALE_SGI = 0x000080B4, - GL_POST_COLOR_MATRIX_GREEN_SCALE = 0x000080B5, - GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI = 0x000080B5, - GL_POST_COLOR_MATRIX_BLUE_SCALE = 0x000080B6, - GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI = 0x000080B6, - GL_POST_COLOR_MATRIX_ALPHA_SCALE = 0x000080B7, - GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI = 0x000080B7, - GL_POST_COLOR_MATRIX_RED_BIAS = 0x000080B8, - GL_POST_COLOR_MATRIX_RED_BIAS_SGI = 0x000080B8, - GL_POST_COLOR_MATRIX_GREEN_BIAS = 0x000080B9, - GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI = 0x000080B9, - GL_POST_COLOR_MATRIX_BLUE_BIAS = 0x000080BA, - GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI = 0x000080BA, - GL_POST_COLOR_MATRIX_ALPHA_BIAS = 0x000080BB, - GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI = 0x000080BB, - GL_TEXTURE_COLOR_TABLE_SGI = 0x000080BC, - GL_PROXY_TEXTURE_COLOR_TABLE_SGI = 0x000080BD, - GL_TEXTURE_ENV_BIAS_SGIX = 0x000080BE, - GL_SHADOW_AMBIENT_SGIX = 0x000080BF, - GL_TEXTURE_COMPARE_FAIL_VALUE_ARB = 0x000080BF, - GL_BLEND_DST_RGB = 0x000080C8, - GL_BLEND_DST_RGB_EXT = 0x000080C8, - GL_BLEND_DST_RGB_OES = 0x000080C8, - GL_BLEND_SRC_RGB = 0x000080C9, - GL_BLEND_SRC_RGB_EXT = 0x000080C9, - GL_BLEND_SRC_RGB_OES = 0x000080C9, - GL_BLEND_DST_ALPHA = 0x000080CA, - GL_BLEND_DST_ALPHA_EXT = 0x000080CA, - GL_BLEND_DST_ALPHA_OES = 0x000080CA, - GL_BLEND_SRC_ALPHA = 0x000080CB, - GL_BLEND_SRC_ALPHA_EXT = 0x000080CB, - GL_BLEND_SRC_ALPHA_OES = 0x000080CB, - GL_422_EXT = 0x000080CC, - GL_422_REV_EXT = 0x000080CD, - GL_422_AVERAGE_EXT = 0x000080CE, - GL_422_REV_AVERAGE_EXT = 0x000080CF, - GL_COLOR_TABLE = 0x000080D0, - GL_COLOR_TABLE_SGI = 0x000080D0, - GL_POST_CONVOLUTION_COLOR_TABLE = 0x000080D1, - GL_POST_CONVOLUTION_COLOR_TABLE_SGI = 0x000080D1, - GL_POST_COLOR_MATRIX_COLOR_TABLE = 0x000080D2, - GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI = 0x000080D2, - GL_PROXY_COLOR_TABLE = 0x000080D3, - GL_PROXY_COLOR_TABLE_SGI = 0x000080D3, - GL_PROXY_POST_CONVOLUTION_COLOR_TABLE = 0x000080D4, - GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI = 0x000080D4, - GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE = 0x000080D5, - GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI = 0x000080D5, - GL_COLOR_TABLE_SCALE = 0x000080D6, - GL_COLOR_TABLE_SCALE_SGI = 0x000080D6, - GL_COLOR_TABLE_BIAS = 0x000080D7, - GL_COLOR_TABLE_BIAS_SGI = 0x000080D7, - GL_COLOR_TABLE_FORMAT = 0x000080D8, - GL_COLOR_TABLE_FORMAT_SGI = 0x000080D8, - GL_COLOR_TABLE_WIDTH = 0x000080D9, - GL_COLOR_TABLE_WIDTH_SGI = 0x000080D9, - GL_COLOR_TABLE_RED_SIZE = 0x000080DA, - GL_COLOR_TABLE_RED_SIZE_SGI = 0x000080DA, - GL_COLOR_TABLE_GREEN_SIZE = 0x000080DB, - GL_COLOR_TABLE_GREEN_SIZE_SGI = 0x000080DB, - GL_COLOR_TABLE_BLUE_SIZE = 0x000080DC, - GL_COLOR_TABLE_BLUE_SIZE_SGI = 0x000080DC, - GL_COLOR_TABLE_ALPHA_SIZE = 0x000080DD, - GL_COLOR_TABLE_ALPHA_SIZE_SGI = 0x000080DD, - GL_COLOR_TABLE_LUMINANCE_SIZE = 0x000080DE, - GL_COLOR_TABLE_LUMINANCE_SIZE_SGI = 0x000080DE, - GL_COLOR_TABLE_INTENSITY_SIZE = 0x000080DF, - GL_COLOR_TABLE_INTENSITY_SIZE_SGI = 0x000080DF, - GL_BGR = 0x000080E0, - GL_BGR_EXT = 0x000080E0, - GL_BGRA = 0x000080E1, - GL_BGRA_EXT = 0x000080E1, - GL_BGRA_IMG = 0x000080E1, - GL_COLOR_INDEX1_EXT = 0x000080E2, - GL_COLOR_INDEX2_EXT = 0x000080E3, - GL_COLOR_INDEX4_EXT = 0x000080E4, - GL_COLOR_INDEX8_EXT = 0x000080E5, - GL_COLOR_INDEX12_EXT = 0x000080E6, - GL_COLOR_INDEX16_EXT = 0x000080E7, - GL_MAX_ELEMENTS_VERTICES = 0x000080E8, - GL_MAX_ELEMENTS_VERTICES_EXT = 0x000080E8, - GL_MAX_ELEMENTS_INDICES = 0x000080E9, - GL_MAX_ELEMENTS_INDICES_EXT = 0x000080E9, - GL_PHONG_WIN = 0x000080EA, - GL_PHONG_HINT_WIN = 0x000080EB, - GL_FOG_SPECULAR_TEXTURE_WIN = 0x000080EC, - GL_TEXTURE_INDEX_SIZE_EXT = 0x000080ED, - GL_PARAMETER_BUFFER_ARB = 0x000080EE, - GL_PARAMETER_BUFFER_BINDING_ARB = 0x000080EF, - GL_CLIP_VOLUME_CLIPPING_HINT_EXT = 0x000080F0, - GL_DUAL_ALPHA4_SGIS = 0x00008110, - GL_DUAL_ALPHA8_SGIS = 0x00008111, - GL_DUAL_ALPHA12_SGIS = 0x00008112, - GL_DUAL_ALPHA16_SGIS = 0x00008113, - GL_DUAL_LUMINANCE4_SGIS = 0x00008114, - GL_DUAL_LUMINANCE8_SGIS = 0x00008115, - GL_DUAL_LUMINANCE12_SGIS = 0x00008116, - GL_DUAL_LUMINANCE16_SGIS = 0x00008117, - GL_DUAL_INTENSITY4_SGIS = 0x00008118, - GL_DUAL_INTENSITY8_SGIS = 0x00008119, - GL_DUAL_INTENSITY12_SGIS = 0x0000811A, - GL_DUAL_INTENSITY16_SGIS = 0x0000811B, - GL_DUAL_LUMINANCE_ALPHA4_SGIS = 0x0000811C, - GL_DUAL_LUMINANCE_ALPHA8_SGIS = 0x0000811D, - GL_QUAD_ALPHA4_SGIS = 0x0000811E, - GL_QUAD_ALPHA8_SGIS = 0x0000811F, - GL_QUAD_LUMINANCE4_SGIS = 0x00008120, - GL_QUAD_LUMINANCE8_SGIS = 0x00008121, - GL_QUAD_INTENSITY4_SGIS = 0x00008122, - GL_QUAD_INTENSITY8_SGIS = 0x00008123, - GL_DUAL_TEXTURE_SELECT_SGIS = 0x00008124, - GL_QUAD_TEXTURE_SELECT_SGIS = 0x00008125, - GL_POINT_SIZE_MIN = 0x00008126, - GL_POINT_SIZE_MIN_ARB = 0x00008126, - GL_POINT_SIZE_MIN_EXT = 0x00008126, - GL_POINT_SIZE_MIN_SGIS = 0x00008126, - GL_POINT_SIZE_MAX = 0x00008127, - GL_POINT_SIZE_MAX_ARB = 0x00008127, - GL_POINT_SIZE_MAX_EXT = 0x00008127, - GL_POINT_SIZE_MAX_SGIS = 0x00008127, - GL_POINT_FADE_THRESHOLD_SIZE = 0x00008128, - GL_POINT_FADE_THRESHOLD_SIZE_ARB = 0x00008128, - GL_POINT_FADE_THRESHOLD_SIZE_EXT = 0x00008128, - GL_POINT_FADE_THRESHOLD_SIZE_SGIS = 0x00008128, - GL_DISTANCE_ATTENUATION_EXT = 0x00008129, - GL_DISTANCE_ATTENUATION_SGIS = 0x00008129, - GL_POINT_DISTANCE_ATTENUATION = 0x00008129, - GL_POINT_DISTANCE_ATTENUATION_ARB = 0x00008129, - GL_FOG_FUNC_SGIS = 0x0000812A, - GL_FOG_FUNC_POINTS_SGIS = 0x0000812B, - GL_MAX_FOG_FUNC_POINTS_SGIS = 0x0000812C, - GL_CLAMP_TO_BORDER = 0x0000812D, - GL_CLAMP_TO_BORDER_ARB = 0x0000812D, - GL_CLAMP_TO_BORDER_EXT = 0x0000812D, - GL_CLAMP_TO_BORDER_NV = 0x0000812D, - GL_CLAMP_TO_BORDER_SGIS = 0x0000812D, - GL_CLAMP_TO_BORDER_OES = 0x0000812D, - GL_TEXTURE_MULTI_BUFFER_HINT_SGIX = 0x0000812E, - GL_CLAMP_TO_EDGE = 0x0000812F, - GL_CLAMP_TO_EDGE_SGIS = 0x0000812F, - GL_PACK_SKIP_VOLUMES_SGIS = 0x00008130, - GL_PACK_IMAGE_DEPTH_SGIS = 0x00008131, - GL_UNPACK_SKIP_VOLUMES_SGIS = 0x00008132, - GL_UNPACK_IMAGE_DEPTH_SGIS = 0x00008133, - GL_TEXTURE_4D_SGIS = 0x00008134, - GL_PROXY_TEXTURE_4D_SGIS = 0x00008135, - GL_TEXTURE_4DSIZE_SGIS = 0x00008136, - GL_TEXTURE_WRAP_Q_SGIS = 0x00008137, - GL_MAX_4D_TEXTURE_SIZE_SGIS = 0x00008138, - GL_PIXEL_TEX_GEN_SGIX = 0x00008139, - GL_TEXTURE_MIN_LOD = 0x0000813A, - GL_TEXTURE_MIN_LOD_SGIS = 0x0000813A, - GL_TEXTURE_MAX_LOD = 0x0000813B, - GL_TEXTURE_MAX_LOD_SGIS = 0x0000813B, - GL_TEXTURE_BASE_LEVEL = 0x0000813C, - GL_TEXTURE_BASE_LEVEL_SGIS = 0x0000813C, - GL_TEXTURE_MAX_LEVEL = 0x0000813D, - GL_TEXTURE_MAX_LEVEL_APPLE = 0x0000813D, - GL_TEXTURE_MAX_LEVEL_SGIS = 0x0000813D, - GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX = 0x0000813E, - GL_PIXEL_TILE_CACHE_INCREMENT_SGIX = 0x0000813F, - GL_PIXEL_TILE_WIDTH_SGIX = 0x00008140, - GL_PIXEL_TILE_HEIGHT_SGIX = 0x00008141, - GL_PIXEL_TILE_GRID_WIDTH_SGIX = 0x00008142, - GL_PIXEL_TILE_GRID_HEIGHT_SGIX = 0x00008143, - GL_PIXEL_TILE_GRID_DEPTH_SGIX = 0x00008144, - GL_PIXEL_TILE_CACHE_SIZE_SGIX = 0x00008145, - GL_FILTER4_SGIS = 0x00008146, - GL_TEXTURE_FILTER4_SIZE_SGIS = 0x00008147, - GL_SPRITE_SGIX = 0x00008148, - GL_SPRITE_MODE_SGIX = 0x00008149, - GL_SPRITE_AXIS_SGIX = 0x0000814A, - GL_SPRITE_TRANSLATION_SGIX = 0x0000814B, - GL_SPRITE_AXIAL_SGIX = 0x0000814C, - GL_SPRITE_OBJECT_ALIGNED_SGIX = 0x0000814D, - GL_SPRITE_EYE_ALIGNED_SGIX = 0x0000814E, - GL_TEXTURE_4D_BINDING_SGIS = 0x0000814F, - GL_IGNORE_BORDER_HP = 0x00008150, - GL_CONSTANT_BORDER = 0x00008151, - GL_CONSTANT_BORDER_HP = 0x00008151, - GL_REPLICATE_BORDER = 0x00008153, - GL_REPLICATE_BORDER_HP = 0x00008153, - GL_CONVOLUTION_BORDER_COLOR = 0x00008154, - GL_CONVOLUTION_BORDER_COLOR_HP = 0x00008154, - GL_IMAGE_SCALE_X_HP = 0x00008155, - GL_IMAGE_SCALE_Y_HP = 0x00008156, - GL_IMAGE_TRANSLATE_X_HP = 0x00008157, - GL_IMAGE_TRANSLATE_Y_HP = 0x00008158, - GL_IMAGE_ROTATE_ANGLE_HP = 0x00008159, - GL_IMAGE_ROTATE_ORIGIN_X_HP = 0x0000815A, - GL_IMAGE_ROTATE_ORIGIN_Y_HP = 0x0000815B, - GL_IMAGE_MAG_FILTER_HP = 0x0000815C, - GL_IMAGE_MIN_FILTER_HP = 0x0000815D, - GL_IMAGE_CUBIC_WEIGHT_HP = 0x0000815E, - GL_CUBIC_HP = 0x0000815F, - GL_AVERAGE_HP = 0x00008160, - GL_IMAGE_TRANSFORM_2D_HP = 0x00008161, - GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = 0x00008162, - GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP = 0x00008163, - GL_OCCLUSION_TEST_HP = 0x00008165, - GL_OCCLUSION_TEST_RESULT_HP = 0x00008166, - GL_TEXTURE_LIGHTING_MODE_HP = 0x00008167, - GL_TEXTURE_POST_SPECULAR_HP = 0x00008168, - GL_TEXTURE_PRE_SPECULAR_HP = 0x00008169, - GL_LINEAR_CLIPMAP_LINEAR_SGIX = 0x00008170, - GL_TEXTURE_CLIPMAP_CENTER_SGIX = 0x00008171, - GL_TEXTURE_CLIPMAP_FRAME_SGIX = 0x00008172, - GL_TEXTURE_CLIPMAP_OFFSET_SGIX = 0x00008173, - GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX = 0x00008174, - GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX = 0x00008175, - GL_TEXTURE_CLIPMAP_DEPTH_SGIX = 0x00008176, - GL_MAX_CLIPMAP_DEPTH_SGIX = 0x00008177, - GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX = 0x00008178, - GL_POST_TEXTURE_FILTER_BIAS_SGIX = 0x00008179, - GL_POST_TEXTURE_FILTER_SCALE_SGIX = 0x0000817A, - GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX = 0x0000817B, - GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX = 0x0000817C, - GL_REFERENCE_PLANE_SGIX = 0x0000817D, - GL_REFERENCE_PLANE_EQUATION_SGIX = 0x0000817E, - GL_IR_INSTRUMENT1_SGIX = 0x0000817F, - GL_INSTRUMENT_BUFFER_POINTER_SGIX = 0x00008180, - GL_INSTRUMENT_MEASUREMENTS_SGIX = 0x00008181, - GL_LIST_PRIORITY_SGIX = 0x00008182, - GL_CALLIGRAPHIC_FRAGMENT_SGIX = 0x00008183, - GL_PIXEL_TEX_GEN_Q_CEILING_SGIX = 0x00008184, - GL_PIXEL_TEX_GEN_Q_ROUND_SGIX = 0x00008185, - GL_PIXEL_TEX_GEN_Q_FLOOR_SGIX = 0x00008186, - GL_PIXEL_TEX_GEN_ALPHA_REPLACE_SGIX = 0x00008187, - GL_PIXEL_TEX_GEN_ALPHA_NO_REPLACE_SGIX = 0x00008188, - GL_PIXEL_TEX_GEN_ALPHA_LS_SGIX = 0x00008189, - GL_PIXEL_TEX_GEN_ALPHA_MS_SGIX = 0x0000818A, - GL_FRAMEZOOM_SGIX = 0x0000818B, - GL_FRAMEZOOM_FACTOR_SGIX = 0x0000818C, - GL_MAX_FRAMEZOOM_FACTOR_SGIX = 0x0000818D, - GL_TEXTURE_LOD_BIAS_S_SGIX = 0x0000818E, - GL_TEXTURE_LOD_BIAS_T_SGIX = 0x0000818F, - GL_TEXTURE_LOD_BIAS_R_SGIX = 0x00008190, - GL_GENERATE_MIPMAP = 0x00008191, - GL_GENERATE_MIPMAP_SGIS = 0x00008191, - GL_GENERATE_MIPMAP_HINT = 0x00008192, - GL_GENERATE_MIPMAP_HINT_SGIS = 0x00008192, - GL_GEOMETRY_DEFORMATION_SGIX = 0x00008194, - GL_TEXTURE_DEFORMATION_SGIX = 0x00008195, - GL_DEFORMATIONS_MASK_SGIX = 0x00008196, - GL_MAX_DEFORMATION_ORDER_SGIX = 0x00008197, - GL_FOG_OFFSET_SGIX = 0x00008198, - GL_FOG_OFFSET_VALUE_SGIX = 0x00008199, - GL_TEXTURE_COMPARE_SGIX = 0x0000819A, - GL_TEXTURE_COMPARE_OPERATOR_SGIX = 0x0000819B, - GL_TEXTURE_LEQUAL_R_SGIX = 0x0000819C, - GL_TEXTURE_GEQUAL_R_SGIX = 0x0000819D, - GL_DEPTH_COMPONENT16 = 0x000081A5, - GL_DEPTH_COMPONENT16_ARB = 0x000081A5, - GL_DEPTH_COMPONENT16_OES = 0x000081A5, - GL_DEPTH_COMPONENT16_SGIX = 0x000081A5, - GL_DEPTH_COMPONENT24 = 0x000081A6, - GL_DEPTH_COMPONENT24_ARB = 0x000081A6, - GL_DEPTH_COMPONENT24_OES = 0x000081A6, - GL_DEPTH_COMPONENT24_SGIX = 0x000081A6, - GL_DEPTH_COMPONENT32 = 0x000081A7, - GL_DEPTH_COMPONENT32_ARB = 0x000081A7, - GL_DEPTH_COMPONENT32_OES = 0x000081A7, - GL_DEPTH_COMPONENT32_SGIX = 0x000081A7, - GL_ARRAY_ELEMENT_LOCK_FIRST_EXT = 0x000081A8, - GL_ARRAY_ELEMENT_LOCK_COUNT_EXT = 0x000081A9, - GL_CULL_VERTEX_EXT = 0x000081AA, - GL_CULL_VERTEX_EYE_POSITION_EXT = 0x000081AB, - GL_CULL_VERTEX_OBJECT_POSITION_EXT = 0x000081AC, - GL_IUI_V2F_EXT = 0x000081AD, - GL_IUI_V3F_EXT = 0x000081AE, - GL_IUI_N3F_V2F_EXT = 0x000081AF, - GL_IUI_N3F_V3F_EXT = 0x000081B0, - GL_T2F_IUI_V2F_EXT = 0x000081B1, - GL_T2F_IUI_V3F_EXT = 0x000081B2, - GL_T2F_IUI_N3F_V2F_EXT = 0x000081B3, - GL_T2F_IUI_N3F_V3F_EXT = 0x000081B4, - GL_INDEX_TEST_EXT = 0x000081B5, - GL_INDEX_TEST_FUNC_EXT = 0x000081B6, - GL_INDEX_TEST_REF_EXT = 0x000081B7, - GL_INDEX_MATERIAL_EXT = 0x000081B8, - GL_INDEX_MATERIAL_PARAMETER_EXT = 0x000081B9, - GL_INDEX_MATERIAL_FACE_EXT = 0x000081BA, - GL_YCRCB_422_SGIX = 0x000081BB, - GL_YCRCB_444_SGIX = 0x000081BC, - GL_WRAP_BORDER_SUN = 0x000081D4, - GL_UNPACK_CONSTANT_DATA_SUNX = 0x000081D5, - GL_TEXTURE_CONSTANT_DATA_SUNX = 0x000081D6, - GL_TRIANGLE_LIST_SUN = 0x000081D7, - GL_REPLACEMENT_CODE_SUN = 0x000081D8, - GL_GLOBAL_ALPHA_SUN = 0x000081D9, - GL_GLOBAL_ALPHA_FACTOR_SUN = 0x000081DA, - GL_TEXTURE_COLOR_WRITEMASK_SGIS = 0x000081EF, - GL_EYE_DISTANCE_TO_POINT_SGIS = 0x000081F0, - GL_OBJECT_DISTANCE_TO_POINT_SGIS = 0x000081F1, - GL_EYE_DISTANCE_TO_LINE_SGIS = 0x000081F2, - GL_OBJECT_DISTANCE_TO_LINE_SGIS = 0x000081F3, - GL_EYE_POINT_SGIS = 0x000081F4, - GL_OBJECT_POINT_SGIS = 0x000081F5, - GL_EYE_LINE_SGIS = 0x000081F6, - GL_OBJECT_LINE_SGIS = 0x000081F7, - GL_LIGHT_MODEL_COLOR_CONTROL = 0x000081F8, - GL_LIGHT_MODEL_COLOR_CONTROL_EXT = 0x000081F8, - GL_SINGLE_COLOR = 0x000081F9, - GL_SINGLE_COLOR_EXT = 0x000081F9, - GL_SEPARATE_SPECULAR_COLOR = 0x000081FA, - GL_SEPARATE_SPECULAR_COLOR_EXT = 0x000081FA, - GL_SHARED_TEXTURE_PALETTE_EXT = 0x000081FB, - GL_TEXT_FRAGMENT_SHADER_ATI = 0x00008200, - GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x00008210, - GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT = 0x00008210, - GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE = 0x00008211, - GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT = 0x00008211, - GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE = 0x00008212, - GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE = 0x00008213, - GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE = 0x00008214, - GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE = 0x00008215, - GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE = 0x00008216, - GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE = 0x00008217, - GL_FRAMEBUFFER_DEFAULT = 0x00008218, - GL_FRAMEBUFFER_UNDEFINED = 0x00008219, - GL_FRAMEBUFFER_UNDEFINED_OES = 0x00008219, - GL_DEPTH_STENCIL_ATTACHMENT = 0x0000821A, - GL_MAJOR_VERSION = 0x0000821B, - GL_MINOR_VERSION = 0x0000821C, - GL_NUM_EXTENSIONS = 0x0000821D, - GL_CONTEXT_FLAGS = 0x0000821E, - GL_BUFFER_IMMUTABLE_STORAGE = 0x0000821F, - GL_BUFFER_IMMUTABLE_STORAGE_EXT = 0x0000821F, - GL_BUFFER_STORAGE_FLAGS = 0x00008220, - GL_BUFFER_STORAGE_FLAGS_EXT = 0x00008220, - GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 0x00008221, - GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED_OES = 0x00008221, - GL_INDEX = 0x00008222, - GL_COMPRESSED_RED = 0x00008225, - GL_COMPRESSED_RG = 0x00008226, - GL_RG = 0x00008227, - GL_RG_EXT = 0x00008227, - GL_RG_INTEGER = 0x00008228, - GL_R8 = 0x00008229, - GL_R8_EXT = 0x00008229, - GL_R16 = 0x0000822A, - GL_R16_EXT = 0x0000822A, - GL_RG8 = 0x0000822B, - GL_RG8_EXT = 0x0000822B, - GL_RG16 = 0x0000822C, - GL_RG16_EXT = 0x0000822C, - GL_R16F = 0x0000822D, - GL_R16F_EXT = 0x0000822D, - GL_R32F = 0x0000822E, - GL_R32F_EXT = 0x0000822E, - GL_RG16F = 0x0000822F, - GL_RG16F_EXT = 0x0000822F, - GL_RG32F = 0x00008230, - GL_RG32F_EXT = 0x00008230, - GL_R8I = 0x00008231, - GL_R8UI = 0x00008232, - GL_R16I = 0x00008233, - GL_R16UI = 0x00008234, - GL_R32I = 0x00008235, - GL_R32UI = 0x00008236, - GL_RG8I = 0x00008237, - GL_RG8UI = 0x00008238, - GL_RG16I = 0x00008239, - GL_RG16UI = 0x0000823A, - GL_RG32I = 0x0000823B, - GL_RG32UI = 0x0000823C, - GL_SYNC_CL_EVENT_ARB = 0x00008240, - GL_SYNC_CL_EVENT_COMPLETE_ARB = 0x00008241, - GL_DEBUG_OUTPUT_SYNCHRONOUS = 0x00008242, - GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB = 0x00008242, - GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR = 0x00008242, - GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 0x00008243, - GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB = 0x00008243, - GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_KHR = 0x00008243, - GL_DEBUG_CALLBACK_FUNCTION = 0x00008244, - GL_DEBUG_CALLBACK_FUNCTION_ARB = 0x00008244, - GL_DEBUG_CALLBACK_FUNCTION_KHR = 0x00008244, - GL_DEBUG_CALLBACK_USER_PARAM = 0x00008245, - GL_DEBUG_CALLBACK_USER_PARAM_ARB = 0x00008245, - GL_DEBUG_CALLBACK_USER_PARAM_KHR = 0x00008245, - GL_DEBUG_SOURCE_API = 0x00008246, - GL_DEBUG_SOURCE_API_ARB = 0x00008246, - GL_DEBUG_SOURCE_API_KHR = 0x00008246, - GL_DEBUG_SOURCE_WINDOW_SYSTEM = 0x00008247, - GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB = 0x00008247, - GL_DEBUG_SOURCE_WINDOW_SYSTEM_KHR = 0x00008247, - GL_DEBUG_SOURCE_SHADER_COMPILER = 0x00008248, - GL_DEBUG_SOURCE_SHADER_COMPILER_ARB = 0x00008248, - GL_DEBUG_SOURCE_SHADER_COMPILER_KHR = 0x00008248, - GL_DEBUG_SOURCE_THIRD_PARTY = 0x00008249, - GL_DEBUG_SOURCE_THIRD_PARTY_ARB = 0x00008249, - GL_DEBUG_SOURCE_THIRD_PARTY_KHR = 0x00008249, - GL_DEBUG_SOURCE_APPLICATION = 0x0000824A, - GL_DEBUG_SOURCE_APPLICATION_ARB = 0x0000824A, - GL_DEBUG_SOURCE_APPLICATION_KHR = 0x0000824A, - GL_DEBUG_SOURCE_OTHER = 0x0000824B, - GL_DEBUG_SOURCE_OTHER_ARB = 0x0000824B, - GL_DEBUG_SOURCE_OTHER_KHR = 0x0000824B, - GL_DEBUG_TYPE_ERROR = 0x0000824C, - GL_DEBUG_TYPE_ERROR_ARB = 0x0000824C, - GL_DEBUG_TYPE_ERROR_KHR = 0x0000824C, - GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 0x0000824D, - GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB = 0x0000824D, - GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_KHR = 0x0000824D, - GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 0x0000824E, - GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB = 0x0000824E, - GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_KHR = 0x0000824E, - GL_DEBUG_TYPE_PORTABILITY = 0x0000824F, - GL_DEBUG_TYPE_PORTABILITY_ARB = 0x0000824F, - GL_DEBUG_TYPE_PORTABILITY_KHR = 0x0000824F, - GL_DEBUG_TYPE_PERFORMANCE = 0x00008250, - GL_DEBUG_TYPE_PERFORMANCE_ARB = 0x00008250, - GL_DEBUG_TYPE_PERFORMANCE_KHR = 0x00008250, - GL_DEBUG_TYPE_OTHER = 0x00008251, - GL_DEBUG_TYPE_OTHER_ARB = 0x00008251, - GL_DEBUG_TYPE_OTHER_KHR = 0x00008251, - GL_LOSE_CONTEXT_ON_RESET = 0x00008252, - GL_LOSE_CONTEXT_ON_RESET_ARB = 0x00008252, - GL_LOSE_CONTEXT_ON_RESET_EXT = 0x00008252, - GL_LOSE_CONTEXT_ON_RESET_KHR = 0x00008252, - GL_GUILTY_CONTEXT_RESET = 0x00008253, - GL_GUILTY_CONTEXT_RESET_ARB = 0x00008253, - GL_GUILTY_CONTEXT_RESET_EXT = 0x00008253, - GL_GUILTY_CONTEXT_RESET_KHR = 0x00008253, - GL_INNOCENT_CONTEXT_RESET = 0x00008254, - GL_INNOCENT_CONTEXT_RESET_ARB = 0x00008254, - GL_INNOCENT_CONTEXT_RESET_EXT = 0x00008254, - GL_INNOCENT_CONTEXT_RESET_KHR = 0x00008254, - GL_UNKNOWN_CONTEXT_RESET = 0x00008255, - GL_UNKNOWN_CONTEXT_RESET_ARB = 0x00008255, - GL_UNKNOWN_CONTEXT_RESET_EXT = 0x00008255, - GL_UNKNOWN_CONTEXT_RESET_KHR = 0x00008255, - GL_RESET_NOTIFICATION_STRATEGY = 0x00008256, - GL_RESET_NOTIFICATION_STRATEGY_ARB = 0x00008256, - GL_RESET_NOTIFICATION_STRATEGY_EXT = 0x00008256, - GL_RESET_NOTIFICATION_STRATEGY_KHR = 0x00008256, - GL_PROGRAM_BINARY_RETRIEVABLE_HINT = 0x00008257, - GL_PROGRAM_SEPARABLE = 0x00008258, - GL_PROGRAM_SEPARABLE_EXT = 0x00008258, - GL_ACTIVE_PROGRAM = 0x00008259, - GL_ACTIVE_PROGRAM_EXT = 0x00008259, - GL_PROGRAM_PIPELINE_BINDING = 0x0000825A, - GL_PROGRAM_PIPELINE_BINDING_EXT = 0x0000825A, - GL_MAX_VIEWPORTS = 0x0000825B, - GL_MAX_VIEWPORTS_NV = 0x0000825B, - GL_VIEWPORT_SUBPIXEL_BITS = 0x0000825C, - GL_VIEWPORT_SUBPIXEL_BITS_EXT = 0x0000825C, - GL_VIEWPORT_SUBPIXEL_BITS_NV = 0x0000825C, - GL_VIEWPORT_BOUNDS_RANGE = 0x0000825D, - GL_VIEWPORT_BOUNDS_RANGE_EXT = 0x0000825D, - GL_VIEWPORT_BOUNDS_RANGE_NV = 0x0000825D, - GL_LAYER_PROVOKING_VERTEX = 0x0000825E, - GL_LAYER_PROVOKING_VERTEX_EXT = 0x0000825E, - GL_LAYER_PROVOKING_VERTEX_OES = 0x0000825E, - GL_VIEWPORT_INDEX_PROVOKING_VERTEX = 0x0000825F, - GL_VIEWPORT_INDEX_PROVOKING_VERTEX_EXT = 0x0000825F, - GL_VIEWPORT_INDEX_PROVOKING_VERTEX_NV = 0x0000825F, - GL_UNDEFINED_VERTEX = 0x00008260, - GL_UNDEFINED_VERTEX_EXT = 0x00008260, - GL_UNDEFINED_VERTEX_OES = 0x00008260, - GL_NO_RESET_NOTIFICATION = 0x00008261, - GL_NO_RESET_NOTIFICATION_ARB = 0x00008261, - GL_NO_RESET_NOTIFICATION_EXT = 0x00008261, - GL_NO_RESET_NOTIFICATION_KHR = 0x00008261, - GL_MAX_COMPUTE_SHARED_MEMORY_SIZE = 0x00008262, - GL_MAX_COMPUTE_UNIFORM_COMPONENTS = 0x00008263, - GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS = 0x00008264, - GL_MAX_COMPUTE_ATOMIC_COUNTERS = 0x00008265, - GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS = 0x00008266, - GL_COMPUTE_WORK_GROUP_SIZE = 0x00008267, - GL_DEBUG_TYPE_MARKER = 0x00008268, - GL_DEBUG_TYPE_MARKER_KHR = 0x00008268, - GL_DEBUG_TYPE_PUSH_GROUP = 0x00008269, - GL_DEBUG_TYPE_PUSH_GROUP_KHR = 0x00008269, - GL_DEBUG_TYPE_POP_GROUP = 0x0000826A, - GL_DEBUG_TYPE_POP_GROUP_KHR = 0x0000826A, - GL_DEBUG_SEVERITY_NOTIFICATION = 0x0000826B, - GL_DEBUG_SEVERITY_NOTIFICATION_KHR = 0x0000826B, - GL_MAX_DEBUG_GROUP_STACK_DEPTH = 0x0000826C, - GL_MAX_DEBUG_GROUP_STACK_DEPTH_KHR = 0x0000826C, - GL_DEBUG_GROUP_STACK_DEPTH = 0x0000826D, - GL_DEBUG_GROUP_STACK_DEPTH_KHR = 0x0000826D, - GL_MAX_UNIFORM_LOCATIONS = 0x0000826E, - GL_INTERNALFORMAT_SUPPORTED = 0x0000826F, - GL_INTERNALFORMAT_PREFERRED = 0x00008270, - GL_INTERNALFORMAT_RED_SIZE = 0x00008271, - GL_INTERNALFORMAT_GREEN_SIZE = 0x00008272, - GL_INTERNALFORMAT_BLUE_SIZE = 0x00008273, - GL_INTERNALFORMAT_ALPHA_SIZE = 0x00008274, - GL_INTERNALFORMAT_DEPTH_SIZE = 0x00008275, - GL_INTERNALFORMAT_STENCIL_SIZE = 0x00008276, - GL_INTERNALFORMAT_SHARED_SIZE = 0x00008277, - GL_INTERNALFORMAT_RED_TYPE = 0x00008278, - GL_INTERNALFORMAT_GREEN_TYPE = 0x00008279, - GL_INTERNALFORMAT_BLUE_TYPE = 0x0000827A, - GL_INTERNALFORMAT_ALPHA_TYPE = 0x0000827B, - GL_INTERNALFORMAT_DEPTH_TYPE = 0x0000827C, - GL_INTERNALFORMAT_STENCIL_TYPE = 0x0000827D, - GL_MAX_WIDTH = 0x0000827E, - GL_MAX_HEIGHT = 0x0000827F, - GL_MAX_DEPTH = 0x00008280, - GL_MAX_LAYERS = 0x00008281, - GL_MAX_COMBINED_DIMENSIONS = 0x00008282, - GL_COLOR_COMPONENTS = 0x00008283, - GL_DEPTH_COMPONENTS = 0x00008284, - GL_STENCIL_COMPONENTS = 0x00008285, - GL_COLOR_RENDERABLE = 0x00008286, - GL_DEPTH_RENDERABLE = 0x00008287, - GL_STENCIL_RENDERABLE = 0x00008288, - GL_FRAMEBUFFER_RENDERABLE = 0x00008289, - GL_FRAMEBUFFER_RENDERABLE_LAYERED = 0x0000828A, - GL_FRAMEBUFFER_BLEND = 0x0000828B, - GL_READ_PIXELS = 0x0000828C, - GL_READ_PIXELS_FORMAT = 0x0000828D, - GL_READ_PIXELS_TYPE = 0x0000828E, - GL_TEXTURE_IMAGE_FORMAT = 0x0000828F, - GL_TEXTURE_IMAGE_TYPE = 0x00008290, - GL_GET_TEXTURE_IMAGE_FORMAT = 0x00008291, - GL_GET_TEXTURE_IMAGE_TYPE = 0x00008292, - GL_MIPMAP = 0x00008293, - GL_MANUAL_GENERATE_MIPMAP = 0x00008294, - GL_AUTO_GENERATE_MIPMAP = 0x00008295, - GL_COLOR_ENCODING = 0x00008296, - GL_SRGB_READ = 0x00008297, - GL_SRGB_WRITE = 0x00008298, - GL_SRGB_DECODE_ARB = 0x00008299, - GL_FILTER = 0x0000829A, - GL_VERTEX_TEXTURE = 0x0000829B, - GL_TESS_CONTROL_TEXTURE = 0x0000829C, - GL_TESS_EVALUATION_TEXTURE = 0x0000829D, - GL_GEOMETRY_TEXTURE = 0x0000829E, - GL_FRAGMENT_TEXTURE = 0x0000829F, - GL_COMPUTE_TEXTURE = 0x000082A0, - GL_TEXTURE_SHADOW = 0x000082A1, - GL_TEXTURE_GATHER = 0x000082A2, - GL_TEXTURE_GATHER_SHADOW = 0x000082A3, - GL_SHADER_IMAGE_LOAD = 0x000082A4, - GL_SHADER_IMAGE_STORE = 0x000082A5, - GL_SHADER_IMAGE_ATOMIC = 0x000082A6, - GL_IMAGE_TEXEL_SIZE = 0x000082A7, - GL_IMAGE_COMPATIBILITY_CLASS = 0x000082A8, - GL_IMAGE_PIXEL_FORMAT = 0x000082A9, - GL_IMAGE_PIXEL_TYPE = 0x000082AA, - GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST = 0x000082AC, - GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST = 0x000082AD, - GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE = 0x000082AE, - GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE = 0x000082AF, - GL_TEXTURE_COMPRESSED_BLOCK_WIDTH = 0x000082B1, - GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT = 0x000082B2, - GL_TEXTURE_COMPRESSED_BLOCK_SIZE = 0x000082B3, - GL_CLEAR_BUFFER = 0x000082B4, - GL_TEXTURE_VIEW = 0x000082B5, - GL_VIEW_COMPATIBILITY_CLASS = 0x000082B6, - GL_FULL_SUPPORT = 0x000082B7, - GL_CAVEAT_SUPPORT = 0x000082B8, - GL_IMAGE_CLASS_4_X_32 = 0x000082B9, - GL_IMAGE_CLASS_2_X_32 = 0x000082BA, - GL_IMAGE_CLASS_1_X_32 = 0x000082BB, - GL_IMAGE_CLASS_4_X_16 = 0x000082BC, - GL_IMAGE_CLASS_2_X_16 = 0x000082BD, - GL_IMAGE_CLASS_1_X_16 = 0x000082BE, - GL_IMAGE_CLASS_4_X_8 = 0x000082BF, - GL_IMAGE_CLASS_2_X_8 = 0x000082C0, - GL_IMAGE_CLASS_1_X_8 = 0x000082C1, - GL_IMAGE_CLASS_11_11_10 = 0x000082C2, - GL_IMAGE_CLASS_10_10_10_2 = 0x000082C3, - GL_VIEW_CLASS_128_BITS = 0x000082C4, - GL_VIEW_CLASS_96_BITS = 0x000082C5, - GL_VIEW_CLASS_64_BITS = 0x000082C6, - GL_VIEW_CLASS_48_BITS = 0x000082C7, - GL_VIEW_CLASS_32_BITS = 0x000082C8, - GL_VIEW_CLASS_24_BITS = 0x000082C9, - GL_VIEW_CLASS_16_BITS = 0x000082CA, - GL_VIEW_CLASS_8_BITS = 0x000082CB, - GL_VIEW_CLASS_S3TC_DXT1_RGB = 0x000082CC, - GL_VIEW_CLASS_S3TC_DXT1_RGBA = 0x000082CD, - GL_VIEW_CLASS_S3TC_DXT3_RGBA = 0x000082CE, - GL_VIEW_CLASS_S3TC_DXT5_RGBA = 0x000082CF, - GL_VIEW_CLASS_RGTC1_RED = 0x000082D0, - GL_VIEW_CLASS_RGTC2_RG = 0x000082D1, - GL_VIEW_CLASS_BPTC_UNORM = 0x000082D2, - GL_VIEW_CLASS_BPTC_FLOAT = 0x000082D3, - GL_VERTEX_ATTRIB_BINDING = 0x000082D4, - GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x000082D5, - GL_VERTEX_BINDING_DIVISOR = 0x000082D6, - GL_VERTEX_BINDING_OFFSET = 0x000082D7, - GL_VERTEX_BINDING_STRIDE = 0x000082D8, - GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET = 0x000082D9, - GL_MAX_VERTEX_ATTRIB_BINDINGS = 0x000082DA, - GL_TEXTURE_VIEW_MIN_LEVEL = 0x000082DB, - GL_TEXTURE_VIEW_MIN_LEVEL_EXT = 0x000082DB, - GL_TEXTURE_VIEW_MIN_LEVEL_OES = 0x000082DB, - GL_TEXTURE_VIEW_NUM_LEVELS = 0x000082DC, - GL_TEXTURE_VIEW_NUM_LEVELS_EXT = 0x000082DC, - GL_TEXTURE_VIEW_NUM_LEVELS_OES = 0x000082DC, - GL_TEXTURE_VIEW_MIN_LAYER = 0x000082DD, - GL_TEXTURE_VIEW_MIN_LAYER_EXT = 0x000082DD, - GL_TEXTURE_VIEW_MIN_LAYER_OES = 0x000082DD, - GL_TEXTURE_VIEW_NUM_LAYERS = 0x000082DE, - GL_TEXTURE_VIEW_NUM_LAYERS_EXT = 0x000082DE, - GL_TEXTURE_VIEW_NUM_LAYERS_OES = 0x000082DE, - GL_TEXTURE_IMMUTABLE_LEVELS = 0x000082DF, - GL_BUFFER = 0x000082E0, - GL_BUFFER_KHR = 0x000082E0, - GL_SHADER = 0x000082E1, - GL_SHADER_KHR = 0x000082E1, - GL_PROGRAM = 0x000082E2, - GL_PROGRAM_KHR = 0x000082E2, - GL_QUERY = 0x000082E3, - GL_QUERY_KHR = 0x000082E3, - GL_PROGRAM_PIPELINE = 0x000082E4, - GL_PROGRAM_PIPELINE_KHR = 0x000082E4, - GL_MAX_VERTEX_ATTRIB_STRIDE = 0x000082E5, - GL_SAMPLER = 0x000082E6, - GL_SAMPLER_KHR = 0x000082E6, - GL_DISPLAY_LIST = 0x000082E7, - GL_MAX_LABEL_LENGTH = 0x000082E8, - GL_MAX_LABEL_LENGTH_KHR = 0x000082E8, - GL_NUM_SHADING_LANGUAGE_VERSIONS = 0x000082E9, - GL_QUERY_TARGET = 0x000082EA, - GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB = 0x000082EC, - GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB = 0x000082ED, - GL_VERTICES_SUBMITTED_ARB = 0x000082EE, - GL_PRIMITIVES_SUBMITTED_ARB = 0x000082EF, - GL_VERTEX_SHADER_INVOCATIONS_ARB = 0x000082F0, - GL_TESS_CONTROL_SHADER_PATCHES_ARB = 0x000082F1, - GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB = 0x000082F2, - GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB = 0x000082F3, - GL_FRAGMENT_SHADER_INVOCATIONS_ARB = 0x000082F4, - GL_COMPUTE_SHADER_INVOCATIONS_ARB = 0x000082F5, - GL_CLIPPING_INPUT_PRIMITIVES_ARB = 0x000082F6, - GL_CLIPPING_OUTPUT_PRIMITIVES_ARB = 0x000082F7, - GL_SPARSE_BUFFER_PAGE_SIZE_ARB = 0x000082F8, - GL_MAX_CULL_DISTANCES = 0x000082F9, - GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES = 0x000082FA, - GL_CONTEXT_RELEASE_BEHAVIOR = 0x000082FB, - GL_CONTEXT_RELEASE_BEHAVIOR_KHR = 0x000082FB, - GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x000082FC, - GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR = 0x000082FC, - GL_DEPTH_PASS_INSTRUMENT_SGIX = 0x00008310, - GL_DEPTH_PASS_INSTRUMENT_COUNTERS_SGIX = 0x00008311, - GL_DEPTH_PASS_INSTRUMENT_MAX_SGIX = 0x00008312, - GL_FRAGMENTS_INSTRUMENT_SGIX = 0x00008313, - GL_FRAGMENTS_INSTRUMENT_COUNTERS_SGIX = 0x00008314, - GL_FRAGMENTS_INSTRUMENT_MAX_SGIX = 0x00008315, - GL_CONVOLUTION_HINT_SGIX = 0x00008316, - GL_YCRCB_SGIX = 0x00008318, - GL_YCRCBA_SGIX = 0x00008319, - GL_UNPACK_COMPRESSED_SIZE_SGIX = 0x0000831A, - GL_PACK_MAX_COMPRESSED_SIZE_SGIX = 0x0000831B, - GL_PACK_COMPRESSED_SIZE_SGIX = 0x0000831C, - GL_SLIM8U_SGIX = 0x0000831D, - GL_SLIM10U_SGIX = 0x0000831E, - GL_SLIM12S_SGIX = 0x0000831F, - GL_ALPHA_MIN_SGIX = 0x00008320, - GL_ALPHA_MAX_SGIX = 0x00008321, - GL_SCALEBIAS_HINT_SGIX = 0x00008322, - GL_ASYNC_MARKER_SGIX = 0x00008329, - GL_PIXEL_TEX_GEN_MODE_SGIX = 0x0000832B, - GL_ASYNC_HISTOGRAM_SGIX = 0x0000832C, - GL_MAX_ASYNC_HISTOGRAM_SGIX = 0x0000832D, - GL_PIXEL_TRANSFORM_2D_EXT = 0x00008330, - GL_PIXEL_MAG_FILTER_EXT = 0x00008331, - GL_PIXEL_MIN_FILTER_EXT = 0x00008332, - GL_PIXEL_CUBIC_WEIGHT_EXT = 0x00008333, - GL_CUBIC_EXT = 0x00008334, - GL_AVERAGE_EXT = 0x00008335, - GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = 0x00008336, - GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT = 0x00008337, - GL_PIXEL_TRANSFORM_2D_MATRIX_EXT = 0x00008338, - GL_FRAGMENT_MATERIAL_EXT = 0x00008349, - GL_FRAGMENT_NORMAL_EXT = 0x0000834A, - GL_FRAGMENT_COLOR_EXT = 0x0000834C, - GL_ATTENUATION_EXT = 0x0000834D, - GL_SHADOW_ATTENUATION_EXT = 0x0000834E, - GL_TEXTURE_APPLICATION_MODE_EXT = 0x0000834F, - GL_TEXTURE_LIGHT_EXT = 0x00008350, - GL_TEXTURE_MATERIAL_FACE_EXT = 0x00008351, - GL_TEXTURE_MATERIAL_PARAMETER_EXT = 0x00008352, - GL_PIXEL_TEXTURE_SGIS = 0x00008353, - GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS = 0x00008354, - GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS = 0x00008355, - GL_PIXEL_GROUP_COLOR_SGIS = 0x00008356, - GL_LINE_QUALITY_HINT_SGIX = 0x0000835B, - GL_ASYNC_TEX_IMAGE_SGIX = 0x0000835C, - GL_ASYNC_DRAW_PIXELS_SGIX = 0x0000835D, - GL_ASYNC_READ_PIXELS_SGIX = 0x0000835E, - GL_MAX_ASYNC_TEX_IMAGE_SGIX = 0x0000835F, - GL_MAX_ASYNC_DRAW_PIXELS_SGIX = 0x00008360, - GL_MAX_ASYNC_READ_PIXELS_SGIX = 0x00008361, - GL_UNSIGNED_BYTE_2_3_3_REV = 0x00008362, - GL_UNSIGNED_BYTE_2_3_3_REV_EXT = 0x00008362, - GL_UNSIGNED_SHORT_5_6_5 = 0x00008363, - GL_UNSIGNED_SHORT_5_6_5_EXT = 0x00008363, - GL_UNSIGNED_SHORT_5_6_5_REV = 0x00008364, - GL_UNSIGNED_SHORT_5_6_5_REV_EXT = 0x00008364, - GL_UNSIGNED_SHORT_4_4_4_4_REV = 0x00008365, - GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT = 0x00008365, - GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG = 0x00008365, - GL_UNSIGNED_SHORT_1_5_5_5_REV = 0x00008366, - GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT = 0x00008366, - GL_UNSIGNED_INT_8_8_8_8_REV = 0x00008367, - GL_UNSIGNED_INT_8_8_8_8_REV_EXT = 0x00008367, - GL_UNSIGNED_INT_2_10_10_10_REV = 0x00008368, - GL_UNSIGNED_INT_2_10_10_10_REV_EXT = 0x00008368, - GL_TEXTURE_MAX_CLAMP_S_SGIX = 0x00008369, - GL_TEXTURE_MAX_CLAMP_T_SGIX = 0x0000836A, - GL_TEXTURE_MAX_CLAMP_R_SGIX = 0x0000836B, - GL_MIRRORED_REPEAT = 0x00008370, - GL_MIRRORED_REPEAT_ARB = 0x00008370, - GL_MIRRORED_REPEAT_IBM = 0x00008370, - GL_MIRRORED_REPEAT_OES = 0x00008370, - GL_RGB_S3TC = 0x000083A0, - GL_RGB4_S3TC = 0x000083A1, - GL_RGBA_S3TC = 0x000083A2, - GL_RGBA4_S3TC = 0x000083A3, - GL_RGBA_DXT5_S3TC = 0x000083A4, - GL_RGBA4_DXT5_S3TC = 0x000083A5, - GL_VERTEX_PRECLIP_SGIX = 0x000083EE, - GL_VERTEX_PRECLIP_HINT_SGIX = 0x000083EF, - GL_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x000083F0, - GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x000083F1, - GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE = 0x000083F2, - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x000083F2, - GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE = 0x000083F3, - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x000083F3, - GL_PARALLEL_ARRAYS_INTEL = 0x000083F4, - GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL = 0x000083F5, - GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL = 0x000083F6, - GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL = 0x000083F7, - GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL = 0x000083F8, - GL_PERFQUERY_DONOT_FLUSH_INTEL = 0x000083F9, - GL_PERFQUERY_FLUSH_INTEL = 0x000083FA, - GL_PERFQUERY_WAIT_INTEL = 0x000083FB, - GL_TEXTURE_MEMORY_LAYOUT_INTEL = 0x000083FF, - GL_FRAGMENT_LIGHTING_SGIX = 0x00008400, - GL_FRAGMENT_COLOR_MATERIAL_SGIX = 0x00008401, - GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX = 0x00008402, - GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX = 0x00008403, - GL_MAX_FRAGMENT_LIGHTS_SGIX = 0x00008404, - GL_MAX_ACTIVE_LIGHTS_SGIX = 0x00008405, - GL_CURRENT_RASTER_NORMAL_SGIX = 0x00008406, - GL_LIGHT_ENV_MODE_SGIX = 0x00008407, - GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX = 0x00008408, - GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX = 0x00008409, - GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX = 0x0000840A, - GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX = 0x0000840B, - GL_FRAGMENT_LIGHT0_SGIX = 0x0000840C, - GL_FRAGMENT_LIGHT1_SGIX = 0x0000840D, - GL_FRAGMENT_LIGHT2_SGIX = 0x0000840E, - GL_FRAGMENT_LIGHT3_SGIX = 0x0000840F, - GL_FRAGMENT_LIGHT4_SGIX = 0x00008410, - GL_FRAGMENT_LIGHT5_SGIX = 0x00008411, - GL_FRAGMENT_LIGHT6_SGIX = 0x00008412, - GL_FRAGMENT_LIGHT7_SGIX = 0x00008413, - GL_PACK_RESAMPLE_SGIX = 0x0000842E, - GL_UNPACK_RESAMPLE_SGIX = 0x0000842F, - GL_RESAMPLE_DECIMATE_SGIX = 0x00008430, - GL_RESAMPLE_REPLICATE_SGIX = 0x00008433, - GL_RESAMPLE_ZERO_FILL_SGIX = 0x00008434, - GL_TANGENT_ARRAY_EXT = 0x00008439, - GL_BINORMAL_ARRAY_EXT = 0x0000843A, - GL_CURRENT_TANGENT_EXT = 0x0000843B, - GL_CURRENT_BINORMAL_EXT = 0x0000843C, - GL_TANGENT_ARRAY_TYPE_EXT = 0x0000843E, - GL_TANGENT_ARRAY_STRIDE_EXT = 0x0000843F, - GL_BINORMAL_ARRAY_TYPE_EXT = 0x00008440, - GL_BINORMAL_ARRAY_STRIDE_EXT = 0x00008441, - GL_TANGENT_ARRAY_POINTER_EXT = 0x00008442, - GL_BINORMAL_ARRAY_POINTER_EXT = 0x00008443, - GL_MAP1_TANGENT_EXT = 0x00008444, - GL_MAP2_TANGENT_EXT = 0x00008445, - GL_MAP1_BINORMAL_EXT = 0x00008446, - GL_MAP2_BINORMAL_EXT = 0x00008447, - GL_NEAREST_CLIPMAP_NEAREST_SGIX = 0x0000844D, - GL_NEAREST_CLIPMAP_LINEAR_SGIX = 0x0000844E, - GL_LINEAR_CLIPMAP_NEAREST_SGIX = 0x0000844F, - GL_FOG_COORDINATE_SOURCE = 0x00008450, - GL_FOG_COORDINATE_SOURCE_EXT = 0x00008450, - GL_FOG_COORD_SRC = 0x00008450, - GL_FOG_COORDINATE = 0x00008451, - GL_FOG_COORD = 0x00008451, - GL_FOG_COORDINATE_EXT = 0x00008451, - GL_FRAGMENT_DEPTH = 0x00008452, - GL_FRAGMENT_DEPTH_EXT = 0x00008452, - GL_CURRENT_FOG_COORDINATE = 0x00008453, - GL_CURRENT_FOG_COORD = 0x00008453, - GL_CURRENT_FOG_COORDINATE_EXT = 0x00008453, - GL_FOG_COORDINATE_ARRAY_TYPE = 0x00008454, - GL_FOG_COORDINATE_ARRAY_TYPE_EXT = 0x00008454, - GL_FOG_COORD_ARRAY_TYPE = 0x00008454, - GL_FOG_COORDINATE_ARRAY_STRIDE = 0x00008455, - GL_FOG_COORDINATE_ARRAY_STRIDE_EXT = 0x00008455, - GL_FOG_COORD_ARRAY_STRIDE = 0x00008455, - GL_FOG_COORDINATE_ARRAY_POINTER = 0x00008456, - GL_FOG_COORDINATE_ARRAY_POINTER_EXT = 0x00008456, - GL_FOG_COORD_ARRAY_POINTER = 0x00008456, - GL_FOG_COORDINATE_ARRAY = 0x00008457, - GL_FOG_COORDINATE_ARRAY_EXT = 0x00008457, - GL_FOG_COORD_ARRAY = 0x00008457, - GL_COLOR_SUM = 0x00008458, - GL_COLOR_SUM_ARB = 0x00008458, - GL_COLOR_SUM_EXT = 0x00008458, - GL_CURRENT_SECONDARY_COLOR = 0x00008459, - GL_CURRENT_SECONDARY_COLOR_EXT = 0x00008459, - GL_SECONDARY_COLOR_ARRAY_SIZE = 0x0000845A, - GL_SECONDARY_COLOR_ARRAY_SIZE_EXT = 0x0000845A, - GL_SECONDARY_COLOR_ARRAY_TYPE = 0x0000845B, - GL_SECONDARY_COLOR_ARRAY_TYPE_EXT = 0x0000845B, - GL_SECONDARY_COLOR_ARRAY_STRIDE = 0x0000845C, - GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT = 0x0000845C, - GL_SECONDARY_COLOR_ARRAY_POINTER = 0x0000845D, - GL_SECONDARY_COLOR_ARRAY_POINTER_EXT = 0x0000845D, - GL_SECONDARY_COLOR_ARRAY = 0x0000845E, - GL_SECONDARY_COLOR_ARRAY_EXT = 0x0000845E, - GL_CURRENT_RASTER_SECONDARY_COLOR = 0x0000845F, - GL_ALIASED_POINT_SIZE_RANGE = 0x0000846D, - GL_ALIASED_LINE_WIDTH_RANGE = 0x0000846E, - GL_SCREEN_COORDINATES_REND = 0x00008490, - GL_INVERTED_SCREEN_W_REND = 0x00008491, - GL_TEXTURE0 = 0x000084C0, - GL_TEXTURE0_ARB = 0x000084C0, - GL_TEXTURE1 = 0x000084C1, - GL_TEXTURE1_ARB = 0x000084C1, - GL_TEXTURE2 = 0x000084C2, - GL_TEXTURE2_ARB = 0x000084C2, - GL_TEXTURE3 = 0x000084C3, - GL_TEXTURE3_ARB = 0x000084C3, - GL_TEXTURE4 = 0x000084C4, - GL_TEXTURE4_ARB = 0x000084C4, - GL_TEXTURE5 = 0x000084C5, - GL_TEXTURE5_ARB = 0x000084C5, - GL_TEXTURE6 = 0x000084C6, - GL_TEXTURE6_ARB = 0x000084C6, - GL_TEXTURE7 = 0x000084C7, - GL_TEXTURE7_ARB = 0x000084C7, - GL_TEXTURE8 = 0x000084C8, - GL_TEXTURE8_ARB = 0x000084C8, - GL_TEXTURE9 = 0x000084C9, - GL_TEXTURE9_ARB = 0x000084C9, - GL_TEXTURE10 = 0x000084CA, - GL_TEXTURE10_ARB = 0x000084CA, - GL_TEXTURE11 = 0x000084CB, - GL_TEXTURE11_ARB = 0x000084CB, - GL_TEXTURE12 = 0x000084CC, - GL_TEXTURE12_ARB = 0x000084CC, - GL_TEXTURE13 = 0x000084CD, - GL_TEXTURE13_ARB = 0x000084CD, - GL_TEXTURE14 = 0x000084CE, - GL_TEXTURE14_ARB = 0x000084CE, - GL_TEXTURE15 = 0x000084CF, - GL_TEXTURE15_ARB = 0x000084CF, - GL_TEXTURE16 = 0x000084D0, - GL_TEXTURE16_ARB = 0x000084D0, - GL_TEXTURE17 = 0x000084D1, - GL_TEXTURE17_ARB = 0x000084D1, - GL_TEXTURE18 = 0x000084D2, - GL_TEXTURE18_ARB = 0x000084D2, - GL_TEXTURE19 = 0x000084D3, - GL_TEXTURE19_ARB = 0x000084D3, - GL_TEXTURE20 = 0x000084D4, - GL_TEXTURE20_ARB = 0x000084D4, - GL_TEXTURE21 = 0x000084D5, - GL_TEXTURE21_ARB = 0x000084D5, - GL_TEXTURE22 = 0x000084D6, - GL_TEXTURE22_ARB = 0x000084D6, - GL_TEXTURE23 = 0x000084D7, - GL_TEXTURE23_ARB = 0x000084D7, - GL_TEXTURE24 = 0x000084D8, - GL_TEXTURE24_ARB = 0x000084D8, - GL_TEXTURE25 = 0x000084D9, - GL_TEXTURE25_ARB = 0x000084D9, - GL_TEXTURE26 = 0x000084DA, - GL_TEXTURE26_ARB = 0x000084DA, - GL_TEXTURE27 = 0x000084DB, - GL_TEXTURE27_ARB = 0x000084DB, - GL_TEXTURE28 = 0x000084DC, - GL_TEXTURE28_ARB = 0x000084DC, - GL_TEXTURE29 = 0x000084DD, - GL_TEXTURE29_ARB = 0x000084DD, - GL_TEXTURE30 = 0x000084DE, - GL_TEXTURE30_ARB = 0x000084DE, - GL_TEXTURE31 = 0x000084DF, - GL_TEXTURE31_ARB = 0x000084DF, - GL_ACTIVE_TEXTURE = 0x000084E0, - GL_ACTIVE_TEXTURE_ARB = 0x000084E0, - GL_CLIENT_ACTIVE_TEXTURE = 0x000084E1, - GL_CLIENT_ACTIVE_TEXTURE_ARB = 0x000084E1, - GL_MAX_TEXTURE_UNITS = 0x000084E2, - GL_MAX_TEXTURE_UNITS_ARB = 0x000084E2, - GL_TRANSPOSE_MODELVIEW_MATRIX = 0x000084E3, - GL_TRANSPOSE_MODELVIEW_MATRIX_ARB = 0x000084E3, - GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV = 0x000084E3, - GL_TRANSPOSE_PROJECTION_MATRIX = 0x000084E4, - GL_TRANSPOSE_PROJECTION_MATRIX_ARB = 0x000084E4, - GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV = 0x000084E4, - GL_TRANSPOSE_TEXTURE_MATRIX = 0x000084E5, - GL_TRANSPOSE_TEXTURE_MATRIX_ARB = 0x000084E5, - GL_TRANSPOSE_COLOR_MATRIX = 0x000084E6, - GL_TRANSPOSE_COLOR_MATRIX_ARB = 0x000084E6, - GL_SUBTRACT = 0x000084E7, - GL_SUBTRACT_ARB = 0x000084E7, - GL_MAX_RENDERBUFFER_SIZE = 0x000084E8, - GL_MAX_RENDERBUFFER_SIZE_EXT = 0x000084E8, - GL_MAX_RENDERBUFFER_SIZE_OES = 0x000084E8, - GL_COMPRESSED_ALPHA = 0x000084E9, - GL_COMPRESSED_ALPHA_ARB = 0x000084E9, - GL_COMPRESSED_LUMINANCE = 0x000084EA, - GL_COMPRESSED_LUMINANCE_ARB = 0x000084EA, - GL_COMPRESSED_LUMINANCE_ALPHA = 0x000084EB, - GL_COMPRESSED_LUMINANCE_ALPHA_ARB = 0x000084EB, - GL_COMPRESSED_INTENSITY = 0x000084EC, - GL_COMPRESSED_INTENSITY_ARB = 0x000084EC, - GL_COMPRESSED_RGB = 0x000084ED, - GL_COMPRESSED_RGB_ARB = 0x000084ED, - GL_COMPRESSED_RGBA = 0x000084EE, - GL_COMPRESSED_RGBA_ARB = 0x000084EE, - GL_TEXTURE_COMPRESSION_HINT = 0x000084EF, - GL_TEXTURE_COMPRESSION_HINT_ARB = 0x000084EF, - GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER = 0x000084F0, - GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x000084F1, - GL_ALL_COMPLETED_NV = 0x000084F2, - GL_FENCE_STATUS_NV = 0x000084F3, - GL_FENCE_CONDITION_NV = 0x000084F4, - GL_TEXTURE_RECTANGLE = 0x000084F5, - GL_TEXTURE_RECTANGLE_ARB = 0x000084F5, - GL_TEXTURE_RECTANGLE_NV = 0x000084F5, - GL_TEXTURE_BINDING_RECTANGLE = 0x000084F6, - GL_TEXTURE_BINDING_RECTANGLE_ARB = 0x000084F6, - GL_TEXTURE_BINDING_RECTANGLE_NV = 0x000084F6, - GL_PROXY_TEXTURE_RECTANGLE = 0x000084F7, - GL_PROXY_TEXTURE_RECTANGLE_ARB = 0x000084F7, - GL_PROXY_TEXTURE_RECTANGLE_NV = 0x000084F7, - GL_MAX_RECTANGLE_TEXTURE_SIZE = 0x000084F8, - GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB = 0x000084F8, - GL_MAX_RECTANGLE_TEXTURE_SIZE_NV = 0x000084F8, - GL_DEPTH_STENCIL = 0x000084F9, - GL_DEPTH_STENCIL_EXT = 0x000084F9, - GL_DEPTH_STENCIL_NV = 0x000084F9, - GL_DEPTH_STENCIL_OES = 0x000084F9, - GL_UNSIGNED_INT_24_8 = 0x000084FA, - GL_UNSIGNED_INT_24_8_EXT = 0x000084FA, - GL_UNSIGNED_INT_24_8_NV = 0x000084FA, - GL_UNSIGNED_INT_24_8_OES = 0x000084FA, - GL_MAX_TEXTURE_LOD_BIAS = 0x000084FD, - GL_MAX_TEXTURE_LOD_BIAS_EXT = 0x000084FD, - GL_TEXTURE_MAX_ANISOTROPY_EXT = 0x000084FE, - GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x000084FF, - GL_TEXTURE_FILTER_CONTROL = 0x00008500, - GL_TEXTURE_FILTER_CONTROL_EXT = 0x00008500, - GL_TEXTURE_LOD_BIAS = 0x00008501, - GL_TEXTURE_LOD_BIAS_EXT = 0x00008501, - GL_MODELVIEW1_STACK_DEPTH_EXT = 0x00008502, - GL_COMBINE4_NV = 0x00008503, - GL_MAX_SHININESS_NV = 0x00008504, - GL_MAX_SPOT_EXPONENT_NV = 0x00008505, - GL_MODELVIEW1_MATRIX_EXT = 0x00008506, - GL_INCR_WRAP = 0x00008507, - GL_INCR_WRAP_EXT = 0x00008507, - GL_INCR_WRAP_OES = 0x00008507, - GL_DECR_WRAP = 0x00008508, - GL_DECR_WRAP_EXT = 0x00008508, - GL_DECR_WRAP_OES = 0x00008508, - GL_VERTEX_WEIGHTING_EXT = 0x00008509, - GL_MODELVIEW1_ARB = 0x0000850A, - GL_MODELVIEW1_EXT = 0x0000850A, - GL_CURRENT_VERTEX_WEIGHT_EXT = 0x0000850B, - GL_VERTEX_WEIGHT_ARRAY_EXT = 0x0000850C, - GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT = 0x0000850D, - GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT = 0x0000850E, - GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT = 0x0000850F, - GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT = 0x00008510, - GL_NORMAL_MAP = 0x00008511, - GL_NORMAL_MAP_ARB = 0x00008511, - GL_NORMAL_MAP_EXT = 0x00008511, - GL_NORMAL_MAP_NV = 0x00008511, - GL_NORMAL_MAP_OES = 0x00008511, - GL_REFLECTION_MAP = 0x00008512, - GL_REFLECTION_MAP_ARB = 0x00008512, - GL_REFLECTION_MAP_EXT = 0x00008512, - GL_REFLECTION_MAP_NV = 0x00008512, - GL_REFLECTION_MAP_OES = 0x00008512, - GL_TEXTURE_CUBE_MAP = 0x00008513, - GL_TEXTURE_CUBE_MAP_ARB = 0x00008513, - GL_TEXTURE_CUBE_MAP_EXT = 0x00008513, - GL_TEXTURE_CUBE_MAP_OES = 0x00008513, - GL_TEXTURE_BINDING_CUBE_MAP = 0x00008514, - GL_TEXTURE_BINDING_CUBE_MAP_ARB = 0x00008514, - GL_TEXTURE_BINDING_CUBE_MAP_EXT = 0x00008514, - GL_TEXTURE_BINDING_CUBE_MAP_OES = 0x00008514, - GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x00008515, - GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB = 0x00008515, - GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT = 0x00008515, - GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES = 0x00008515, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x00008516, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB = 0x00008516, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT = 0x00008516, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES = 0x00008516, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x00008517, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB = 0x00008517, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT = 0x00008517, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES = 0x00008517, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x00008518, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB = 0x00008518, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT = 0x00008518, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES = 0x00008518, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x00008519, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB = 0x00008519, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT = 0x00008519, - GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES = 0x00008519, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x0000851A, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB = 0x0000851A, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT = 0x0000851A, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES = 0x0000851A, - GL_PROXY_TEXTURE_CUBE_MAP = 0x0000851B, - GL_PROXY_TEXTURE_CUBE_MAP_ARB = 0x0000851B, - GL_PROXY_TEXTURE_CUBE_MAP_EXT = 0x0000851B, - GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x0000851C, - GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB = 0x0000851C, - GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT = 0x0000851C, - GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES = 0x0000851C, - GL_VERTEX_ARRAY_RANGE_APPLE = 0x0000851D, - GL_VERTEX_ARRAY_RANGE_NV = 0x0000851D, - GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE = 0x0000851E, - GL_VERTEX_ARRAY_RANGE_LENGTH_NV = 0x0000851E, - GL_VERTEX_ARRAY_RANGE_VALID_NV = 0x0000851F, - GL_VERTEX_ARRAY_STORAGE_HINT_APPLE = 0x0000851F, - GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV = 0x00008520, - GL_VERTEX_ARRAY_RANGE_POINTER_APPLE = 0x00008521, - GL_VERTEX_ARRAY_RANGE_POINTER_NV = 0x00008521, - GL_REGISTER_COMBINERS_NV = 0x00008522, - GL_VARIABLE_A_NV = 0x00008523, - GL_VARIABLE_B_NV = 0x00008524, - GL_VARIABLE_C_NV = 0x00008525, - GL_VARIABLE_D_NV = 0x00008526, - GL_VARIABLE_E_NV = 0x00008527, - GL_VARIABLE_F_NV = 0x00008528, - GL_VARIABLE_G_NV = 0x00008529, - GL_CONSTANT_COLOR0_NV = 0x0000852A, - GL_CONSTANT_COLOR1_NV = 0x0000852B, - GL_PRIMARY_COLOR_NV = 0x0000852C, - GL_SECONDARY_COLOR_NV = 0x0000852D, - GL_SPARE0_NV = 0x0000852E, - GL_SPARE1_NV = 0x0000852F, - GL_DISCARD_NV = 0x00008530, - GL_E_TIMES_F_NV = 0x00008531, - GL_SPARE0_PLUS_SECONDARY_COLOR_NV = 0x00008532, - GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV = 0x00008533, - GL_MULTISAMPLE_FILTER_HINT_NV = 0x00008534, - GL_PER_STAGE_CONSTANTS_NV = 0x00008535, - GL_UNSIGNED_IDENTITY_NV = 0x00008536, - GL_UNSIGNED_INVERT_NV = 0x00008537, - GL_EXPAND_NORMAL_NV = 0x00008538, - GL_EXPAND_NEGATE_NV = 0x00008539, - GL_HALF_BIAS_NORMAL_NV = 0x0000853A, - GL_HALF_BIAS_NEGATE_NV = 0x0000853B, - GL_SIGNED_IDENTITY_NV = 0x0000853C, - GL_SIGNED_NEGATE_NV = 0x0000853D, - GL_SCALE_BY_TWO_NV = 0x0000853E, - GL_SCALE_BY_FOUR_NV = 0x0000853F, - GL_SCALE_BY_ONE_HALF_NV = 0x00008540, - GL_BIAS_BY_NEGATIVE_ONE_HALF_NV = 0x00008541, - GL_COMBINER_INPUT_NV = 0x00008542, - GL_COMBINER_MAPPING_NV = 0x00008543, - GL_COMBINER_COMPONENT_USAGE_NV = 0x00008544, - GL_COMBINER_AB_DOT_PRODUCT_NV = 0x00008545, - GL_COMBINER_CD_DOT_PRODUCT_NV = 0x00008546, - GL_COMBINER_MUX_SUM_NV = 0x00008547, - GL_COMBINER_SCALE_NV = 0x00008548, - GL_COMBINER_BIAS_NV = 0x00008549, - GL_COMBINER_AB_OUTPUT_NV = 0x0000854A, - GL_COMBINER_CD_OUTPUT_NV = 0x0000854B, - GL_COMBINER_SUM_OUTPUT_NV = 0x0000854C, - GL_MAX_GENERAL_COMBINERS_NV = 0x0000854D, - GL_NUM_GENERAL_COMBINERS_NV = 0x0000854E, - GL_COLOR_SUM_CLAMP_NV = 0x0000854F, - GL_COMBINER0_NV = 0x00008550, - GL_COMBINER1_NV = 0x00008551, - GL_COMBINER2_NV = 0x00008552, - GL_COMBINER3_NV = 0x00008553, - GL_COMBINER4_NV = 0x00008554, - GL_COMBINER5_NV = 0x00008555, - GL_COMBINER6_NV = 0x00008556, - GL_COMBINER7_NV = 0x00008557, - GL_PRIMITIVE_RESTART_NV = 0x00008558, - GL_PRIMITIVE_RESTART_INDEX_NV = 0x00008559, - GL_FOG_DISTANCE_MODE_NV = 0x0000855A, - GL_EYE_RADIAL_NV = 0x0000855B, - GL_EYE_PLANE_ABSOLUTE_NV = 0x0000855C, - GL_EMBOSS_LIGHT_NV = 0x0000855D, - GL_EMBOSS_CONSTANT_NV = 0x0000855E, - GL_EMBOSS_MAP_NV = 0x0000855F, - GL_RED_MIN_CLAMP_INGR = 0x00008560, - GL_GREEN_MIN_CLAMP_INGR = 0x00008561, - GL_BLUE_MIN_CLAMP_INGR = 0x00008562, - GL_ALPHA_MIN_CLAMP_INGR = 0x00008563, - GL_RED_MAX_CLAMP_INGR = 0x00008564, - GL_GREEN_MAX_CLAMP_INGR = 0x00008565, - GL_BLUE_MAX_CLAMP_INGR = 0x00008566, - GL_ALPHA_MAX_CLAMP_INGR = 0x00008567, - GL_INTERLACE_READ_INGR = 0x00008568, - GL_COMBINE = 0x00008570, - GL_COMBINE_ARB = 0x00008570, - GL_COMBINE_EXT = 0x00008570, - GL_COMBINE_RGB = 0x00008571, - GL_COMBINE_RGB_ARB = 0x00008571, - GL_COMBINE_RGB_EXT = 0x00008571, - GL_COMBINE_ALPHA = 0x00008572, - GL_COMBINE_ALPHA_ARB = 0x00008572, - GL_COMBINE_ALPHA_EXT = 0x00008572, - GL_RGB_SCALE = 0x00008573, - GL_RGB_SCALE_ARB = 0x00008573, - GL_RGB_SCALE_EXT = 0x00008573, - GL_ADD_SIGNED = 0x00008574, - GL_ADD_SIGNED_ARB = 0x00008574, - GL_ADD_SIGNED_EXT = 0x00008574, - GL_INTERPOLATE = 0x00008575, - GL_INTERPOLATE_ARB = 0x00008575, - GL_INTERPOLATE_EXT = 0x00008575, - GL_CONSTANT = 0x00008576, - GL_CONSTANT_ARB = 0x00008576, - GL_CONSTANT_EXT = 0x00008576, - GL_CONSTANT_NV = 0x00008576, - GL_PRIMARY_COLOR = 0x00008577, - GL_PRIMARY_COLOR_ARB = 0x00008577, - GL_PRIMARY_COLOR_EXT = 0x00008577, - GL_PREVIOUS = 0x00008578, - GL_PREVIOUS_ARB = 0x00008578, - GL_PREVIOUS_EXT = 0x00008578, - GL_SOURCE0_RGB = 0x00008580, - GL_SOURCE0_RGB_ARB = 0x00008580, - GL_SOURCE0_RGB_EXT = 0x00008580, - GL_SRC0_RGB = 0x00008580, - GL_SOURCE1_RGB = 0x00008581, - GL_SOURCE1_RGB_ARB = 0x00008581, - GL_SOURCE1_RGB_EXT = 0x00008581, - GL_SRC1_RGB = 0x00008581, - GL_SOURCE2_RGB = 0x00008582, - GL_SOURCE2_RGB_ARB = 0x00008582, - GL_SOURCE2_RGB_EXT = 0x00008582, - GL_SRC2_RGB = 0x00008582, - GL_SOURCE3_RGB_NV = 0x00008583, - GL_SOURCE0_ALPHA = 0x00008588, - GL_SOURCE0_ALPHA_ARB = 0x00008588, - GL_SOURCE0_ALPHA_EXT = 0x00008588, - GL_SRC0_ALPHA = 0x00008588, - GL_SOURCE1_ALPHA = 0x00008589, - GL_SOURCE1_ALPHA_ARB = 0x00008589, - GL_SOURCE1_ALPHA_EXT = 0x00008589, - GL_SRC1_ALPHA = 0x00008589, - GL_SRC1_ALPHA_EXT = 0x00008589, - GL_SOURCE2_ALPHA = 0x0000858A, - GL_SOURCE2_ALPHA_ARB = 0x0000858A, - GL_SOURCE2_ALPHA_EXT = 0x0000858A, - GL_SRC2_ALPHA = 0x0000858A, - GL_SOURCE3_ALPHA_NV = 0x0000858B, - GL_OPERAND0_RGB = 0x00008590, - GL_OPERAND0_RGB_ARB = 0x00008590, - GL_OPERAND0_RGB_EXT = 0x00008590, - GL_OPERAND1_RGB = 0x00008591, - GL_OPERAND1_RGB_ARB = 0x00008591, - GL_OPERAND1_RGB_EXT = 0x00008591, - GL_OPERAND2_RGB = 0x00008592, - GL_OPERAND2_RGB_ARB = 0x00008592, - GL_OPERAND2_RGB_EXT = 0x00008592, - GL_OPERAND3_RGB_NV = 0x00008593, - GL_OPERAND0_ALPHA = 0x00008598, - GL_OPERAND0_ALPHA_ARB = 0x00008598, - GL_OPERAND0_ALPHA_EXT = 0x00008598, - GL_OPERAND1_ALPHA = 0x00008599, - GL_OPERAND1_ALPHA_ARB = 0x00008599, - GL_OPERAND1_ALPHA_EXT = 0x00008599, - GL_OPERAND2_ALPHA = 0x0000859A, - GL_OPERAND2_ALPHA_ARB = 0x0000859A, - GL_OPERAND2_ALPHA_EXT = 0x0000859A, - GL_OPERAND3_ALPHA_NV = 0x0000859B, - GL_PACK_SUBSAMPLE_RATE_SGIX = 0x000085A0, - GL_UNPACK_SUBSAMPLE_RATE_SGIX = 0x000085A1, - GL_PIXEL_SUBSAMPLE_4444_SGIX = 0x000085A2, - GL_PIXEL_SUBSAMPLE_2424_SGIX = 0x000085A3, - GL_PIXEL_SUBSAMPLE_4242_SGIX = 0x000085A4, - GL_PERTURB_EXT = 0x000085AE, - GL_TEXTURE_NORMAL_EXT = 0x000085AF, - GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE = 0x000085B0, - GL_TRANSFORM_HINT_APPLE = 0x000085B1, - GL_UNPACK_CLIENT_STORAGE_APPLE = 0x000085B2, - GL_BUFFER_OBJECT_APPLE = 0x000085B3, - GL_STORAGE_CLIENT_APPLE = 0x000085B4, - GL_VERTEX_ARRAY_BINDING = 0x000085B5, - GL_VERTEX_ARRAY_BINDING_APPLE = 0x000085B5, - GL_VERTEX_ARRAY_BINDING_OES = 0x000085B5, - GL_TEXTURE_RANGE_LENGTH_APPLE = 0x000085B7, - GL_TEXTURE_RANGE_POINTER_APPLE = 0x000085B8, - GL_YCBCR_422_APPLE = 0x000085B9, - GL_UNSIGNED_SHORT_8_8_APPLE = 0x000085BA, - GL_UNSIGNED_SHORT_8_8_MESA = 0x000085BA, - GL_UNSIGNED_SHORT_8_8_REV_APPLE = 0x000085BB, - GL_UNSIGNED_SHORT_8_8_REV_MESA = 0x000085BB, - GL_TEXTURE_STORAGE_HINT_APPLE = 0x000085BC, - GL_STORAGE_PRIVATE_APPLE = 0x000085BD, - GL_STORAGE_CACHED_APPLE = 0x000085BE, - GL_STORAGE_SHARED_APPLE = 0x000085BF, - GL_REPLACEMENT_CODE_ARRAY_SUN = 0x000085C0, - GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN = 0x000085C1, - GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN = 0x000085C2, - GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN = 0x000085C3, - GL_R1UI_V3F_SUN = 0x000085C4, - GL_R1UI_C4UB_V3F_SUN = 0x000085C5, - GL_R1UI_C3F_V3F_SUN = 0x000085C6, - GL_R1UI_N3F_V3F_SUN = 0x000085C7, - GL_R1UI_C4F_N3F_V3F_SUN = 0x000085C8, - GL_R1UI_T2F_V3F_SUN = 0x000085C9, - GL_R1UI_T2F_N3F_V3F_SUN = 0x000085CA, - GL_R1UI_T2F_C4F_N3F_V3F_SUN = 0x000085CB, - GL_SLICE_ACCUM_SUN = 0x000085CC, - GL_QUAD_MESH_SUN = 0x00008614, - GL_TRIANGLE_MESH_SUN = 0x00008615, - GL_VERTEX_PROGRAM_ARB = 0x00008620, - GL_VERTEX_PROGRAM_NV = 0x00008620, - GL_VERTEX_STATE_PROGRAM_NV = 0x00008621, - GL_VERTEX_ATTRIB_ARRAY_ENABLED = 0x00008622, - GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB = 0x00008622, - GL_ATTRIB_ARRAY_SIZE_NV = 0x00008623, - GL_VERTEX_ATTRIB_ARRAY_SIZE = 0x00008623, - GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB = 0x00008623, - GL_ATTRIB_ARRAY_STRIDE_NV = 0x00008624, - GL_VERTEX_ATTRIB_ARRAY_STRIDE = 0x00008624, - GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB = 0x00008624, - GL_ATTRIB_ARRAY_TYPE_NV = 0x00008625, - GL_VERTEX_ATTRIB_ARRAY_TYPE = 0x00008625, - GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB = 0x00008625, - GL_CURRENT_ATTRIB_NV = 0x00008626, - GL_CURRENT_VERTEX_ATTRIB = 0x00008626, - GL_CURRENT_VERTEX_ATTRIB_ARB = 0x00008626, - GL_PROGRAM_LENGTH_ARB = 0x00008627, - GL_PROGRAM_LENGTH_NV = 0x00008627, - GL_PROGRAM_STRING_ARB = 0x00008628, - GL_PROGRAM_STRING_NV = 0x00008628, - GL_MODELVIEW_PROJECTION_NV = 0x00008629, - GL_IDENTITY_NV = 0x0000862A, - GL_INVERSE_NV = 0x0000862B, - GL_TRANSPOSE_NV = 0x0000862C, - GL_INVERSE_TRANSPOSE_NV = 0x0000862D, - GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB = 0x0000862E, - GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV = 0x0000862E, - GL_MAX_PROGRAM_MATRICES_ARB = 0x0000862F, - GL_MAX_TRACK_MATRICES_NV = 0x0000862F, - GL_MATRIX0_NV = 0x00008630, - GL_MATRIX1_NV = 0x00008631, - GL_MATRIX2_NV = 0x00008632, - GL_MATRIX3_NV = 0x00008633, - GL_MATRIX4_NV = 0x00008634, - GL_MATRIX5_NV = 0x00008635, - GL_MATRIX6_NV = 0x00008636, - GL_MATRIX7_NV = 0x00008637, - GL_CURRENT_MATRIX_STACK_DEPTH_ARB = 0x00008640, - GL_CURRENT_MATRIX_STACK_DEPTH_NV = 0x00008640, - GL_CURRENT_MATRIX_ARB = 0x00008641, - GL_CURRENT_MATRIX_NV = 0x00008641, - GL_VERTEX_PROGRAM_POINT_SIZE = 0x00008642, - GL_VERTEX_PROGRAM_POINT_SIZE_ARB = 0x00008642, - GL_VERTEX_PROGRAM_POINT_SIZE_NV = 0x00008642, - GL_PROGRAM_POINT_SIZE = 0x00008642, - GL_PROGRAM_POINT_SIZE_ARB = 0x00008642, - GL_PROGRAM_POINT_SIZE_EXT = 0x00008642, - GL_VERTEX_PROGRAM_TWO_SIDE = 0x00008643, - GL_VERTEX_PROGRAM_TWO_SIDE_ARB = 0x00008643, - GL_VERTEX_PROGRAM_TWO_SIDE_NV = 0x00008643, - GL_PROGRAM_PARAMETER_NV = 0x00008644, - GL_ATTRIB_ARRAY_POINTER_NV = 0x00008645, - GL_VERTEX_ATTRIB_ARRAY_POINTER = 0x00008645, - GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB = 0x00008645, - GL_PROGRAM_TARGET_NV = 0x00008646, - GL_PROGRAM_RESIDENT_NV = 0x00008647, - GL_TRACK_MATRIX_NV = 0x00008648, - GL_TRACK_MATRIX_TRANSFORM_NV = 0x00008649, - GL_VERTEX_PROGRAM_BINDING_NV = 0x0000864A, - GL_PROGRAM_ERROR_POSITION_ARB = 0x0000864B, - GL_PROGRAM_ERROR_POSITION_NV = 0x0000864B, - GL_OFFSET_TEXTURE_RECTANGLE_NV = 0x0000864C, - GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV = 0x0000864D, - GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV = 0x0000864E, - GL_DEPTH_CLAMP = 0x0000864F, - GL_DEPTH_CLAMP_NV = 0x0000864F, - GL_VERTEX_ATTRIB_ARRAY0_NV = 0x00008650, - GL_VERTEX_ATTRIB_ARRAY1_NV = 0x00008651, - GL_VERTEX_ATTRIB_ARRAY2_NV = 0x00008652, - GL_VERTEX_ATTRIB_ARRAY3_NV = 0x00008653, - GL_VERTEX_ATTRIB_ARRAY4_NV = 0x00008654, - GL_VERTEX_ATTRIB_ARRAY5_NV = 0x00008655, - GL_VERTEX_ATTRIB_ARRAY6_NV = 0x00008656, - GL_VERTEX_ATTRIB_ARRAY7_NV = 0x00008657, - GL_VERTEX_ATTRIB_ARRAY8_NV = 0x00008658, - GL_VERTEX_ATTRIB_ARRAY9_NV = 0x00008659, - GL_VERTEX_ATTRIB_ARRAY10_NV = 0x0000865A, - GL_VERTEX_ATTRIB_ARRAY11_NV = 0x0000865B, - GL_VERTEX_ATTRIB_ARRAY12_NV = 0x0000865C, - GL_VERTEX_ATTRIB_ARRAY13_NV = 0x0000865D, - GL_VERTEX_ATTRIB_ARRAY14_NV = 0x0000865E, - GL_VERTEX_ATTRIB_ARRAY15_NV = 0x0000865F, - GL_MAP1_VERTEX_ATTRIB0_4_NV = 0x00008660, - GL_MAP1_VERTEX_ATTRIB1_4_NV = 0x00008661, - GL_MAP1_VERTEX_ATTRIB2_4_NV = 0x00008662, - GL_MAP1_VERTEX_ATTRIB3_4_NV = 0x00008663, - GL_MAP1_VERTEX_ATTRIB4_4_NV = 0x00008664, - GL_MAP1_VERTEX_ATTRIB5_4_NV = 0x00008665, - GL_MAP1_VERTEX_ATTRIB6_4_NV = 0x00008666, - GL_MAP1_VERTEX_ATTRIB7_4_NV = 0x00008667, - GL_MAP1_VERTEX_ATTRIB8_4_NV = 0x00008668, - GL_MAP1_VERTEX_ATTRIB9_4_NV = 0x00008669, - GL_MAP1_VERTEX_ATTRIB10_4_NV = 0x0000866A, - GL_MAP1_VERTEX_ATTRIB11_4_NV = 0x0000866B, - GL_MAP1_VERTEX_ATTRIB12_4_NV = 0x0000866C, - GL_MAP1_VERTEX_ATTRIB13_4_NV = 0x0000866D, - GL_MAP1_VERTEX_ATTRIB14_4_NV = 0x0000866E, - GL_MAP1_VERTEX_ATTRIB15_4_NV = 0x0000866F, - GL_MAP2_VERTEX_ATTRIB0_4_NV = 0x00008670, - GL_MAP2_VERTEX_ATTRIB1_4_NV = 0x00008671, - GL_MAP2_VERTEX_ATTRIB2_4_NV = 0x00008672, - GL_MAP2_VERTEX_ATTRIB3_4_NV = 0x00008673, - GL_MAP2_VERTEX_ATTRIB4_4_NV = 0x00008674, - GL_MAP2_VERTEX_ATTRIB5_4_NV = 0x00008675, - GL_MAP2_VERTEX_ATTRIB6_4_NV = 0x00008676, - GL_MAP2_VERTEX_ATTRIB7_4_NV = 0x00008677, - GL_PROGRAM_BINDING_ARB = 0x00008677, - GL_MAP2_VERTEX_ATTRIB8_4_NV = 0x00008678, - GL_MAP2_VERTEX_ATTRIB9_4_NV = 0x00008679, - GL_MAP2_VERTEX_ATTRIB10_4_NV = 0x0000867A, - GL_MAP2_VERTEX_ATTRIB11_4_NV = 0x0000867B, - GL_MAP2_VERTEX_ATTRIB12_4_NV = 0x0000867C, - GL_MAP2_VERTEX_ATTRIB13_4_NV = 0x0000867D, - GL_MAP2_VERTEX_ATTRIB14_4_NV = 0x0000867E, - GL_MAP2_VERTEX_ATTRIB15_4_NV = 0x0000867F, - GL_TEXTURE_COMPRESSED_IMAGE_SIZE = 0x000086A0, - GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB = 0x000086A0, - GL_TEXTURE_COMPRESSED = 0x000086A1, - GL_TEXTURE_COMPRESSED_ARB = 0x000086A1, - GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x000086A2, - GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB = 0x000086A2, - GL_COMPRESSED_TEXTURE_FORMATS = 0x000086A3, - GL_COMPRESSED_TEXTURE_FORMATS_ARB = 0x000086A3, - GL_MAX_VERTEX_UNITS_ARB = 0x000086A4, - GL_MAX_VERTEX_UNITS_OES = 0x000086A4, - GL_ACTIVE_VERTEX_UNITS_ARB = 0x000086A5, - GL_WEIGHT_SUM_UNITY_ARB = 0x000086A6, - GL_VERTEX_BLEND_ARB = 0x000086A7, - GL_CURRENT_WEIGHT_ARB = 0x000086A8, - GL_WEIGHT_ARRAY_TYPE_ARB = 0x000086A9, - GL_WEIGHT_ARRAY_TYPE_OES = 0x000086A9, - GL_WEIGHT_ARRAY_STRIDE_ARB = 0x000086AA, - GL_WEIGHT_ARRAY_STRIDE_OES = 0x000086AA, - GL_WEIGHT_ARRAY_SIZE_ARB = 0x000086AB, - GL_WEIGHT_ARRAY_SIZE_OES = 0x000086AB, - GL_WEIGHT_ARRAY_POINTER_ARB = 0x000086AC, - GL_WEIGHT_ARRAY_POINTER_OES = 0x000086AC, - GL_WEIGHT_ARRAY_ARB = 0x000086AD, - GL_WEIGHT_ARRAY_OES = 0x000086AD, - GL_DOT3_RGB = 0x000086AE, - GL_DOT3_RGB_ARB = 0x000086AE, - GL_DOT3_RGBA = 0x000086AF, - GL_DOT3_RGBA_ARB = 0x000086AF, - GL_DOT3_RGBA_IMG = 0x000086AF, - GL_COMPRESSED_RGB_FXT1_3DFX = 0x000086B0, - GL_COMPRESSED_RGBA_FXT1_3DFX = 0x000086B1, - GL_MULTISAMPLE_3DFX = 0x000086B2, - GL_SAMPLE_BUFFERS_3DFX = 0x000086B3, - GL_SAMPLES_3DFX = 0x000086B4, - GL_EVAL_2D_NV = 0x000086C0, - GL_EVAL_TRIANGULAR_2D_NV = 0x000086C1, - GL_MAP_TESSELLATION_NV = 0x000086C2, - GL_MAP_ATTRIB_U_ORDER_NV = 0x000086C3, - GL_MAP_ATTRIB_V_ORDER_NV = 0x000086C4, - GL_EVAL_FRACTIONAL_TESSELLATION_NV = 0x000086C5, - GL_EVAL_VERTEX_ATTRIB0_NV = 0x000086C6, - GL_EVAL_VERTEX_ATTRIB1_NV = 0x000086C7, - GL_EVAL_VERTEX_ATTRIB2_NV = 0x000086C8, - GL_EVAL_VERTEX_ATTRIB3_NV = 0x000086C9, - GL_EVAL_VERTEX_ATTRIB4_NV = 0x000086CA, - GL_EVAL_VERTEX_ATTRIB5_NV = 0x000086CB, - GL_EVAL_VERTEX_ATTRIB6_NV = 0x000086CC, - GL_EVAL_VERTEX_ATTRIB7_NV = 0x000086CD, - GL_EVAL_VERTEX_ATTRIB8_NV = 0x000086CE, - GL_EVAL_VERTEX_ATTRIB9_NV = 0x000086CF, - GL_EVAL_VERTEX_ATTRIB10_NV = 0x000086D0, - GL_EVAL_VERTEX_ATTRIB11_NV = 0x000086D1, - GL_EVAL_VERTEX_ATTRIB12_NV = 0x000086D2, - GL_EVAL_VERTEX_ATTRIB13_NV = 0x000086D3, - GL_EVAL_VERTEX_ATTRIB14_NV = 0x000086D4, - GL_EVAL_VERTEX_ATTRIB15_NV = 0x000086D5, - GL_MAX_MAP_TESSELLATION_NV = 0x000086D6, - GL_MAX_RATIONAL_EVAL_ORDER_NV = 0x000086D7, - GL_MAX_PROGRAM_PATCH_ATTRIBS_NV = 0x000086D8, - GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV = 0x000086D9, - GL_UNSIGNED_INT_S8_S8_8_8_NV = 0x000086DA, - GL_UNSIGNED_INT_8_8_S8_S8_REV_NV = 0x000086DB, - GL_DSDT_MAG_INTENSITY_NV = 0x000086DC, - GL_SHADER_CONSISTENT_NV = 0x000086DD, - GL_TEXTURE_SHADER_NV = 0x000086DE, - GL_SHADER_OPERATION_NV = 0x000086DF, - GL_CULL_MODES_NV = 0x000086E0, - GL_OFFSET_TEXTURE_MATRIX_NV = 0x000086E1, - GL_OFFSET_TEXTURE_2D_MATRIX_NV = 0x000086E1, - GL_OFFSET_TEXTURE_SCALE_NV = 0x000086E2, - GL_OFFSET_TEXTURE_2D_SCALE_NV = 0x000086E2, - GL_OFFSET_TEXTURE_BIAS_NV = 0x000086E3, - GL_OFFSET_TEXTURE_2D_BIAS_NV = 0x000086E3, - GL_PREVIOUS_TEXTURE_INPUT_NV = 0x000086E4, - GL_CONST_EYE_NV = 0x000086E5, - GL_PASS_THROUGH_NV = 0x000086E6, - GL_CULL_FRAGMENT_NV = 0x000086E7, - GL_OFFSET_TEXTURE_2D_NV = 0x000086E8, - GL_DEPENDENT_AR_TEXTURE_2D_NV = 0x000086E9, - GL_DEPENDENT_GB_TEXTURE_2D_NV = 0x000086EA, - GL_SURFACE_STATE_NV = 0x000086EB, - GL_DOT_PRODUCT_NV = 0x000086EC, - GL_DOT_PRODUCT_DEPTH_REPLACE_NV = 0x000086ED, - GL_DOT_PRODUCT_TEXTURE_2D_NV = 0x000086EE, - GL_DOT_PRODUCT_TEXTURE_3D_NV = 0x000086EF, - GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV = 0x000086F0, - GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV = 0x000086F1, - GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV = 0x000086F2, - GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV = 0x000086F3, - GL_HILO_NV = 0x000086F4, - GL_DSDT_NV = 0x000086F5, - GL_DSDT_MAG_NV = 0x000086F6, - GL_DSDT_MAG_VIB_NV = 0x000086F7, - GL_HILO16_NV = 0x000086F8, - GL_SIGNED_HILO_NV = 0x000086F9, - GL_SIGNED_HILO16_NV = 0x000086FA, - GL_SIGNED_RGBA_NV = 0x000086FB, - GL_SIGNED_RGBA8_NV = 0x000086FC, - GL_SURFACE_REGISTERED_NV = 0x000086FD, - GL_SIGNED_RGB_NV = 0x000086FE, - GL_SIGNED_RGB8_NV = 0x000086FF, - GL_SURFACE_MAPPED_NV = 0x00008700, - GL_SIGNED_LUMINANCE_NV = 0x00008701, - GL_SIGNED_LUMINANCE8_NV = 0x00008702, - GL_SIGNED_LUMINANCE_ALPHA_NV = 0x00008703, - GL_SIGNED_LUMINANCE8_ALPHA8_NV = 0x00008704, - GL_SIGNED_ALPHA_NV = 0x00008705, - GL_SIGNED_ALPHA8_NV = 0x00008706, - GL_SIGNED_INTENSITY_NV = 0x00008707, - GL_SIGNED_INTENSITY8_NV = 0x00008708, - GL_DSDT8_NV = 0x00008709, - GL_DSDT8_MAG8_NV = 0x0000870A, - GL_DSDT8_MAG8_INTENSITY8_NV = 0x0000870B, - GL_SIGNED_RGB_UNSIGNED_ALPHA_NV = 0x0000870C, - GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV = 0x0000870D, - GL_HI_SCALE_NV = 0x0000870E, - GL_LO_SCALE_NV = 0x0000870F, - GL_DS_SCALE_NV = 0x00008710, - GL_DT_SCALE_NV = 0x00008711, - GL_MAGNITUDE_SCALE_NV = 0x00008712, - GL_VIBRANCE_SCALE_NV = 0x00008713, - GL_HI_BIAS_NV = 0x00008714, - GL_LO_BIAS_NV = 0x00008715, - GL_DS_BIAS_NV = 0x00008716, - GL_DT_BIAS_NV = 0x00008717, - GL_MAGNITUDE_BIAS_NV = 0x00008718, - GL_VIBRANCE_BIAS_NV = 0x00008719, - GL_TEXTURE_BORDER_VALUES_NV = 0x0000871A, - GL_TEXTURE_HI_SIZE_NV = 0x0000871B, - GL_TEXTURE_LO_SIZE_NV = 0x0000871C, - GL_TEXTURE_DS_SIZE_NV = 0x0000871D, - GL_TEXTURE_DT_SIZE_NV = 0x0000871E, - GL_TEXTURE_MAG_SIZE_NV = 0x0000871F, - GL_MODELVIEW2_ARB = 0x00008722, - GL_MODELVIEW3_ARB = 0x00008723, - GL_MODELVIEW4_ARB = 0x00008724, - GL_MODELVIEW5_ARB = 0x00008725, - GL_MODELVIEW6_ARB = 0x00008726, - GL_MODELVIEW7_ARB = 0x00008727, - GL_MODELVIEW8_ARB = 0x00008728, - GL_MODELVIEW9_ARB = 0x00008729, - GL_MODELVIEW10_ARB = 0x0000872A, - GL_MODELVIEW11_ARB = 0x0000872B, - GL_MODELVIEW12_ARB = 0x0000872C, - GL_MODELVIEW13_ARB = 0x0000872D, - GL_MODELVIEW14_ARB = 0x0000872E, - GL_MODELVIEW15_ARB = 0x0000872F, - GL_MODELVIEW16_ARB = 0x00008730, - GL_MODELVIEW17_ARB = 0x00008731, - GL_MODELVIEW18_ARB = 0x00008732, - GL_MODELVIEW19_ARB = 0x00008733, - GL_MODELVIEW20_ARB = 0x00008734, - GL_MODELVIEW21_ARB = 0x00008735, - GL_MODELVIEW22_ARB = 0x00008736, - GL_MODELVIEW23_ARB = 0x00008737, - GL_MODELVIEW24_ARB = 0x00008738, - GL_MODELVIEW25_ARB = 0x00008739, - GL_MODELVIEW26_ARB = 0x0000873A, - GL_MODELVIEW27_ARB = 0x0000873B, - GL_MODELVIEW28_ARB = 0x0000873C, - GL_MODELVIEW29_ARB = 0x0000873D, - GL_MODELVIEW30_ARB = 0x0000873E, - GL_MODELVIEW31_ARB = 0x0000873F, - GL_DOT3_RGB_EXT = 0x00008740, - GL_Z400_BINARY_AMD = 0x00008740, - GL_DOT3_RGBA_EXT = 0x00008741, - GL_PROGRAM_BINARY_LENGTH_OES = 0x00008741, - GL_PROGRAM_BINARY_LENGTH = 0x00008741, - GL_MIRROR_CLAMP_ATI = 0x00008742, - GL_MIRROR_CLAMP_EXT = 0x00008742, - GL_MIRROR_CLAMP_TO_EDGE = 0x00008743, - GL_MIRROR_CLAMP_TO_EDGE_ATI = 0x00008743, - GL_MIRROR_CLAMP_TO_EDGE_EXT = 0x00008743, - GL_MODULATE_ADD_ATI = 0x00008744, - GL_MODULATE_SIGNED_ADD_ATI = 0x00008745, - GL_MODULATE_SUBTRACT_ATI = 0x00008746, - GL_SET_AMD = 0x0000874A, - GL_REPLACE_VALUE_AMD = 0x0000874B, - GL_STENCIL_OP_VALUE_AMD = 0x0000874C, - GL_STENCIL_BACK_OP_VALUE_AMD = 0x0000874D, - GL_VERTEX_ATTRIB_ARRAY_LONG = 0x0000874E, - GL_OCCLUSION_QUERY_EVENT_MASK_AMD = 0x0000874F, - GL_DEPTH_STENCIL_MESA = 0x00008750, - GL_UNSIGNED_INT_24_8_MESA = 0x00008751, - GL_UNSIGNED_INT_8_24_REV_MESA = 0x00008752, - GL_UNSIGNED_SHORT_15_1_MESA = 0x00008753, - GL_UNSIGNED_SHORT_1_15_REV_MESA = 0x00008754, - GL_TRACE_MASK_MESA = 0x00008755, - GL_TRACE_NAME_MESA = 0x00008756, - GL_YCBCR_MESA = 0x00008757, - GL_PACK_INVERT_MESA = 0x00008758, - GL_DEBUG_OBJECT_MESA = 0x00008759, - GL_TEXTURE_1D_STACK_MESAX = 0x00008759, - GL_DEBUG_PRINT_MESA = 0x0000875A, - GL_TEXTURE_2D_STACK_MESAX = 0x0000875A, - GL_DEBUG_ASSERT_MESA = 0x0000875B, - GL_PROXY_TEXTURE_1D_STACK_MESAX = 0x0000875B, - GL_PROXY_TEXTURE_2D_STACK_MESAX = 0x0000875C, - GL_TEXTURE_1D_STACK_BINDING_MESAX = 0x0000875D, - GL_TEXTURE_2D_STACK_BINDING_MESAX = 0x0000875E, - GL_STATIC_ATI = 0x00008760, - GL_DYNAMIC_ATI = 0x00008761, - GL_PRESERVE_ATI = 0x00008762, - GL_DISCARD_ATI = 0x00008763, - GL_BUFFER_SIZE = 0x00008764, - GL_BUFFER_SIZE_ARB = 0x00008764, - GL_OBJECT_BUFFER_SIZE_ATI = 0x00008764, - GL_BUFFER_USAGE = 0x00008765, - GL_BUFFER_USAGE_ARB = 0x00008765, - GL_OBJECT_BUFFER_USAGE_ATI = 0x00008765, - GL_ARRAY_OBJECT_BUFFER_ATI = 0x00008766, - GL_ARRAY_OBJECT_OFFSET_ATI = 0x00008767, - GL_ELEMENT_ARRAY_ATI = 0x00008768, - GL_ELEMENT_ARRAY_TYPE_ATI = 0x00008769, - GL_ELEMENT_ARRAY_POINTER_ATI = 0x0000876A, - GL_MAX_VERTEX_STREAMS_ATI = 0x0000876B, - GL_VERTEX_STREAM0_ATI = 0x0000876C, - GL_VERTEX_STREAM1_ATI = 0x0000876D, - GL_VERTEX_STREAM2_ATI = 0x0000876E, - GL_VERTEX_STREAM3_ATI = 0x0000876F, - GL_VERTEX_STREAM4_ATI = 0x00008770, - GL_VERTEX_STREAM5_ATI = 0x00008771, - GL_VERTEX_STREAM6_ATI = 0x00008772, - GL_VERTEX_STREAM7_ATI = 0x00008773, - GL_VERTEX_SOURCE_ATI = 0x00008774, - GL_BUMP_ROT_MATRIX_ATI = 0x00008775, - GL_BUMP_ROT_MATRIX_SIZE_ATI = 0x00008776, - GL_BUMP_NUM_TEX_UNITS_ATI = 0x00008777, - GL_BUMP_TEX_UNITS_ATI = 0x00008778, - GL_DUDV_ATI = 0x00008779, - GL_DU8DV8_ATI = 0x0000877A, - GL_BUMP_ENVMAP_ATI = 0x0000877B, - GL_BUMP_TARGET_ATI = 0x0000877C, - GL_VERTEX_SHADER_EXT = 0x00008780, - GL_VERTEX_SHADER_BINDING_EXT = 0x00008781, - GL_OP_INDEX_EXT = 0x00008782, - GL_OP_NEGATE_EXT = 0x00008783, - GL_OP_DOT3_EXT = 0x00008784, - GL_OP_DOT4_EXT = 0x00008785, - GL_OP_MUL_EXT = 0x00008786, - GL_OP_ADD_EXT = 0x00008787, - GL_OP_MADD_EXT = 0x00008788, - GL_OP_FRAC_EXT = 0x00008789, - GL_OP_MAX_EXT = 0x0000878A, - GL_OP_MIN_EXT = 0x0000878B, - GL_OP_SET_GE_EXT = 0x0000878C, - GL_OP_SET_LT_EXT = 0x0000878D, - GL_OP_CLAMP_EXT = 0x0000878E, - GL_OP_FLOOR_EXT = 0x0000878F, - GL_OP_ROUND_EXT = 0x00008790, - GL_OP_EXP_BASE_2_EXT = 0x00008791, - GL_OP_LOG_BASE_2_EXT = 0x00008792, - GL_OP_POWER_EXT = 0x00008793, - GL_OP_RECIP_EXT = 0x00008794, - GL_OP_RECIP_SQRT_EXT = 0x00008795, - GL_OP_SUB_EXT = 0x00008796, - GL_OP_CROSS_PRODUCT_EXT = 0x00008797, - GL_OP_MULTIPLY_MATRIX_EXT = 0x00008798, - GL_OP_MOV_EXT = 0x00008799, - GL_OUTPUT_VERTEX_EXT = 0x0000879A, - GL_OUTPUT_COLOR0_EXT = 0x0000879B, - GL_OUTPUT_COLOR1_EXT = 0x0000879C, - GL_OUTPUT_TEXTURE_COORD0_EXT = 0x0000879D, - GL_OUTPUT_TEXTURE_COORD1_EXT = 0x0000879E, - GL_OUTPUT_TEXTURE_COORD2_EXT = 0x0000879F, - GL_OUTPUT_TEXTURE_COORD3_EXT = 0x000087A0, - GL_OUTPUT_TEXTURE_COORD4_EXT = 0x000087A1, - GL_OUTPUT_TEXTURE_COORD5_EXT = 0x000087A2, - GL_OUTPUT_TEXTURE_COORD6_EXT = 0x000087A3, - GL_OUTPUT_TEXTURE_COORD7_EXT = 0x000087A4, - GL_OUTPUT_TEXTURE_COORD8_EXT = 0x000087A5, - GL_OUTPUT_TEXTURE_COORD9_EXT = 0x000087A6, - GL_OUTPUT_TEXTURE_COORD10_EXT = 0x000087A7, - GL_OUTPUT_TEXTURE_COORD11_EXT = 0x000087A8, - GL_OUTPUT_TEXTURE_COORD12_EXT = 0x000087A9, - GL_OUTPUT_TEXTURE_COORD13_EXT = 0x000087AA, - GL_OUTPUT_TEXTURE_COORD14_EXT = 0x000087AB, - GL_OUTPUT_TEXTURE_COORD15_EXT = 0x000087AC, - GL_OUTPUT_TEXTURE_COORD16_EXT = 0x000087AD, - GL_OUTPUT_TEXTURE_COORD17_EXT = 0x000087AE, - GL_OUTPUT_TEXTURE_COORD18_EXT = 0x000087AF, - GL_OUTPUT_TEXTURE_COORD19_EXT = 0x000087B0, - GL_OUTPUT_TEXTURE_COORD20_EXT = 0x000087B1, - GL_OUTPUT_TEXTURE_COORD21_EXT = 0x000087B2, - GL_OUTPUT_TEXTURE_COORD22_EXT = 0x000087B3, - GL_OUTPUT_TEXTURE_COORD23_EXT = 0x000087B4, - GL_OUTPUT_TEXTURE_COORD24_EXT = 0x000087B5, - GL_OUTPUT_TEXTURE_COORD25_EXT = 0x000087B6, - GL_OUTPUT_TEXTURE_COORD26_EXT = 0x000087B7, - GL_OUTPUT_TEXTURE_COORD27_EXT = 0x000087B8, - GL_OUTPUT_TEXTURE_COORD28_EXT = 0x000087B9, - GL_OUTPUT_TEXTURE_COORD29_EXT = 0x000087BA, - GL_OUTPUT_TEXTURE_COORD30_EXT = 0x000087BB, - GL_OUTPUT_TEXTURE_COORD31_EXT = 0x000087BC, - GL_OUTPUT_FOG_EXT = 0x000087BD, - GL_SCALAR_EXT = 0x000087BE, - GL_VECTOR_EXT = 0x000087BF, - GL_MATRIX_EXT = 0x000087C0, - GL_VARIANT_EXT = 0x000087C1, - GL_INVARIANT_EXT = 0x000087C2, - GL_LOCAL_CONSTANT_EXT = 0x000087C3, - GL_LOCAL_EXT = 0x000087C4, - GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x000087C5, - GL_MAX_VERTEX_SHADER_VARIANTS_EXT = 0x000087C6, - GL_MAX_VERTEX_SHADER_INVARIANTS_EXT = 0x000087C7, - GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x000087C8, - GL_MAX_VERTEX_SHADER_LOCALS_EXT = 0x000087C9, - GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x000087CA, - GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT = 0x000087CB, - GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x000087CC, - GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT = 0x000087CD, - GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT = 0x000087CE, - GL_VERTEX_SHADER_INSTRUCTIONS_EXT = 0x000087CF, - GL_VERTEX_SHADER_VARIANTS_EXT = 0x000087D0, - GL_VERTEX_SHADER_INVARIANTS_EXT = 0x000087D1, - GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT = 0x000087D2, - GL_VERTEX_SHADER_LOCALS_EXT = 0x000087D3, - GL_VERTEX_SHADER_OPTIMIZED_EXT = 0x000087D4, - GL_X_EXT = 0x000087D5, - GL_Y_EXT = 0x000087D6, - GL_Z_EXT = 0x000087D7, - GL_W_EXT = 0x000087D8, - GL_NEGATIVE_X_EXT = 0x000087D9, - GL_NEGATIVE_Y_EXT = 0x000087DA, - GL_NEGATIVE_Z_EXT = 0x000087DB, - GL_NEGATIVE_W_EXT = 0x000087DC, - GL_ZERO_EXT = 0x000087DD, - GL_ONE_EXT = 0x000087DE, - GL_NEGATIVE_ONE_EXT = 0x000087DF, - GL_NORMALIZED_RANGE_EXT = 0x000087E0, - GL_FULL_RANGE_EXT = 0x000087E1, - GL_CURRENT_VERTEX_EXT = 0x000087E2, - GL_MVP_MATRIX_EXT = 0x000087E3, - GL_VARIANT_VALUE_EXT = 0x000087E4, - GL_VARIANT_DATATYPE_EXT = 0x000087E5, - GL_VARIANT_ARRAY_STRIDE_EXT = 0x000087E6, - GL_VARIANT_ARRAY_TYPE_EXT = 0x000087E7, - GL_VARIANT_ARRAY_EXT = 0x000087E8, - GL_VARIANT_ARRAY_POINTER_EXT = 0x000087E9, - GL_INVARIANT_VALUE_EXT = 0x000087EA, - GL_INVARIANT_DATATYPE_EXT = 0x000087EB, - GL_LOCAL_CONSTANT_VALUE_EXT = 0x000087EC, - GL_LOCAL_CONSTANT_DATATYPE_EXT = 0x000087ED, - GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = 0x000087EE, - GL_PN_TRIANGLES_ATI = 0x000087F0, - GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI = 0x000087F1, - GL_PN_TRIANGLES_POINT_MODE_ATI = 0x000087F2, - GL_PN_TRIANGLES_NORMAL_MODE_ATI = 0x000087F3, - GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI = 0x000087F4, - GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI = 0x000087F5, - GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI = 0x000087F6, - GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI = 0x000087F7, - GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI = 0x000087F8, - GL_3DC_X_AMD = 0x000087F9, - GL_3DC_XY_AMD = 0x000087FA, - GL_VBO_FREE_MEMORY_ATI = 0x000087FB, - GL_TEXTURE_FREE_MEMORY_ATI = 0x000087FC, - GL_RENDERBUFFER_FREE_MEMORY_ATI = 0x000087FD, - GL_NUM_PROGRAM_BINARY_FORMATS = 0x000087FE, - GL_NUM_PROGRAM_BINARY_FORMATS_OES = 0x000087FE, - GL_PROGRAM_BINARY_FORMATS = 0x000087FF, - GL_PROGRAM_BINARY_FORMATS_OES = 0x000087FF, - GL_STENCIL_BACK_FUNC = 0x00008800, - GL_STENCIL_BACK_FUNC_ATI = 0x00008800, - GL_STENCIL_BACK_FAIL = 0x00008801, - GL_STENCIL_BACK_FAIL_ATI = 0x00008801, - GL_STENCIL_BACK_PASS_DEPTH_FAIL = 0x00008802, - GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI = 0x00008802, - GL_STENCIL_BACK_PASS_DEPTH_PASS = 0x00008803, - GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI = 0x00008803, - GL_FRAGMENT_PROGRAM_ARB = 0x00008804, - GL_PROGRAM_ALU_INSTRUCTIONS_ARB = 0x00008805, - GL_PROGRAM_TEX_INSTRUCTIONS_ARB = 0x00008806, - GL_PROGRAM_TEX_INDIRECTIONS_ARB = 0x00008807, - GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = 0x00008808, - GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = 0x00008809, - GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = 0x0000880A, - GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB = 0x0000880B, - GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB = 0x0000880C, - GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB = 0x0000880D, - GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB = 0x0000880E, - GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB = 0x0000880F, - GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB = 0x00008810, - GL_RGBA32F = 0x00008814, - GL_RGBA32F_ARB = 0x00008814, - GL_RGBA32F_EXT = 0x00008814, - GL_RGBA_FLOAT32_APPLE = 0x00008814, - GL_RGBA_FLOAT32_ATI = 0x00008814, - GL_RGB32F = 0x00008815, - GL_RGB32F_ARB = 0x00008815, - GL_RGB32F_EXT = 0x00008815, - GL_RGB_FLOAT32_APPLE = 0x00008815, - GL_RGB_FLOAT32_ATI = 0x00008815, - GL_ALPHA32F_ARB = 0x00008816, - GL_ALPHA32F_EXT = 0x00008816, - GL_ALPHA_FLOAT32_APPLE = 0x00008816, - GL_ALPHA_FLOAT32_ATI = 0x00008816, - GL_INTENSITY32F_ARB = 0x00008817, - GL_INTENSITY_FLOAT32_APPLE = 0x00008817, - GL_INTENSITY_FLOAT32_ATI = 0x00008817, - GL_LUMINANCE32F_ARB = 0x00008818, - GL_LUMINANCE32F_EXT = 0x00008818, - GL_LUMINANCE_FLOAT32_APPLE = 0x00008818, - GL_LUMINANCE_FLOAT32_ATI = 0x00008818, - GL_LUMINANCE_ALPHA32F_ARB = 0x00008819, - GL_LUMINANCE_ALPHA32F_EXT = 0x00008819, - GL_LUMINANCE_ALPHA_FLOAT32_APPLE = 0x00008819, - GL_LUMINANCE_ALPHA_FLOAT32_ATI = 0x00008819, - GL_RGBA16F = 0x0000881A, - GL_RGBA16F_ARB = 0x0000881A, - GL_RGBA16F_EXT = 0x0000881A, - GL_RGBA_FLOAT16_APPLE = 0x0000881A, - GL_RGBA_FLOAT16_ATI = 0x0000881A, - GL_RGB16F = 0x0000881B, - GL_RGB16F_ARB = 0x0000881B, - GL_RGB16F_EXT = 0x0000881B, - GL_RGB_FLOAT16_APPLE = 0x0000881B, - GL_RGB_FLOAT16_ATI = 0x0000881B, - GL_ALPHA16F_ARB = 0x0000881C, - GL_ALPHA16F_EXT = 0x0000881C, - GL_ALPHA_FLOAT16_APPLE = 0x0000881C, - GL_ALPHA_FLOAT16_ATI = 0x0000881C, - GL_INTENSITY16F_ARB = 0x0000881D, - GL_INTENSITY_FLOAT16_APPLE = 0x0000881D, - GL_INTENSITY_FLOAT16_ATI = 0x0000881D, - GL_LUMINANCE16F_ARB = 0x0000881E, - GL_LUMINANCE16F_EXT = 0x0000881E, - GL_LUMINANCE_FLOAT16_APPLE = 0x0000881E, - GL_LUMINANCE_FLOAT16_ATI = 0x0000881E, - GL_LUMINANCE_ALPHA16F_ARB = 0x0000881F, - GL_LUMINANCE_ALPHA16F_EXT = 0x0000881F, - GL_LUMINANCE_ALPHA_FLOAT16_APPLE = 0x0000881F, - GL_LUMINANCE_ALPHA_FLOAT16_ATI = 0x0000881F, - GL_RGBA_FLOAT_MODE_ARB = 0x00008820, - GL_RGBA_FLOAT_MODE_ATI = 0x00008820, - GL_WRITEONLY_RENDERING_QCOM = 0x00008823, - GL_MAX_DRAW_BUFFERS = 0x00008824, - GL_MAX_DRAW_BUFFERS_ARB = 0x00008824, - GL_MAX_DRAW_BUFFERS_ATI = 0x00008824, - GL_MAX_DRAW_BUFFERS_EXT = 0x00008824, - GL_MAX_DRAW_BUFFERS_NV = 0x00008824, - GL_DRAW_BUFFER0 = 0x00008825, - GL_DRAW_BUFFER0_ARB = 0x00008825, - GL_DRAW_BUFFER0_ATI = 0x00008825, - GL_DRAW_BUFFER0_EXT = 0x00008825, - GL_DRAW_BUFFER0_NV = 0x00008825, - GL_DRAW_BUFFER1 = 0x00008826, - GL_DRAW_BUFFER1_ARB = 0x00008826, - GL_DRAW_BUFFER1_ATI = 0x00008826, - GL_DRAW_BUFFER1_EXT = 0x00008826, - GL_DRAW_BUFFER1_NV = 0x00008826, - GL_DRAW_BUFFER2 = 0x00008827, - GL_DRAW_BUFFER2_ARB = 0x00008827, - GL_DRAW_BUFFER2_ATI = 0x00008827, - GL_DRAW_BUFFER2_EXT = 0x00008827, - GL_DRAW_BUFFER2_NV = 0x00008827, - GL_DRAW_BUFFER3 = 0x00008828, - GL_DRAW_BUFFER3_ARB = 0x00008828, - GL_DRAW_BUFFER3_ATI = 0x00008828, - GL_DRAW_BUFFER3_EXT = 0x00008828, - GL_DRAW_BUFFER3_NV = 0x00008828, - GL_DRAW_BUFFER4 = 0x00008829, - GL_DRAW_BUFFER4_ARB = 0x00008829, - GL_DRAW_BUFFER4_ATI = 0x00008829, - GL_DRAW_BUFFER4_EXT = 0x00008829, - GL_DRAW_BUFFER4_NV = 0x00008829, - GL_DRAW_BUFFER5 = 0x0000882A, - GL_DRAW_BUFFER5_ARB = 0x0000882A, - GL_DRAW_BUFFER5_ATI = 0x0000882A, - GL_DRAW_BUFFER5_EXT = 0x0000882A, - GL_DRAW_BUFFER5_NV = 0x0000882A, - GL_DRAW_BUFFER6 = 0x0000882B, - GL_DRAW_BUFFER6_ARB = 0x0000882B, - GL_DRAW_BUFFER6_ATI = 0x0000882B, - GL_DRAW_BUFFER6_EXT = 0x0000882B, - GL_DRAW_BUFFER6_NV = 0x0000882B, - GL_DRAW_BUFFER7 = 0x0000882C, - GL_DRAW_BUFFER7_ARB = 0x0000882C, - GL_DRAW_BUFFER7_ATI = 0x0000882C, - GL_DRAW_BUFFER7_EXT = 0x0000882C, - GL_DRAW_BUFFER7_NV = 0x0000882C, - GL_DRAW_BUFFER8 = 0x0000882D, - GL_DRAW_BUFFER8_ARB = 0x0000882D, - GL_DRAW_BUFFER8_ATI = 0x0000882D, - GL_DRAW_BUFFER8_EXT = 0x0000882D, - GL_DRAW_BUFFER8_NV = 0x0000882D, - GL_DRAW_BUFFER9 = 0x0000882E, - GL_DRAW_BUFFER9_ARB = 0x0000882E, - GL_DRAW_BUFFER9_ATI = 0x0000882E, - GL_DRAW_BUFFER9_EXT = 0x0000882E, - GL_DRAW_BUFFER9_NV = 0x0000882E, - GL_DRAW_BUFFER10 = 0x0000882F, - GL_DRAW_BUFFER10_ARB = 0x0000882F, - GL_DRAW_BUFFER10_ATI = 0x0000882F, - GL_DRAW_BUFFER10_EXT = 0x0000882F, - GL_DRAW_BUFFER10_NV = 0x0000882F, - GL_DRAW_BUFFER11 = 0x00008830, - GL_DRAW_BUFFER11_ARB = 0x00008830, - GL_DRAW_BUFFER11_ATI = 0x00008830, - GL_DRAW_BUFFER11_EXT = 0x00008830, - GL_DRAW_BUFFER11_NV = 0x00008830, - GL_DRAW_BUFFER12 = 0x00008831, - GL_DRAW_BUFFER12_ARB = 0x00008831, - GL_DRAW_BUFFER12_ATI = 0x00008831, - GL_DRAW_BUFFER12_EXT = 0x00008831, - GL_DRAW_BUFFER12_NV = 0x00008831, - GL_DRAW_BUFFER13 = 0x00008832, - GL_DRAW_BUFFER13_ARB = 0x00008832, - GL_DRAW_BUFFER13_ATI = 0x00008832, - GL_DRAW_BUFFER13_EXT = 0x00008832, - GL_DRAW_BUFFER13_NV = 0x00008832, - GL_DRAW_BUFFER14 = 0x00008833, - GL_DRAW_BUFFER14_ARB = 0x00008833, - GL_DRAW_BUFFER14_ATI = 0x00008833, - GL_DRAW_BUFFER14_EXT = 0x00008833, - GL_DRAW_BUFFER14_NV = 0x00008833, - GL_DRAW_BUFFER15 = 0x00008834, - GL_DRAW_BUFFER15_ARB = 0x00008834, - GL_DRAW_BUFFER15_ATI = 0x00008834, - GL_DRAW_BUFFER15_EXT = 0x00008834, - GL_DRAW_BUFFER15_NV = 0x00008834, - GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI = 0x00008835, - GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI = 0x00008837, - GL_BLEND_EQUATION_ALPHA = 0x0000883D, - GL_BLEND_EQUATION_ALPHA_EXT = 0x0000883D, - GL_BLEND_EQUATION_ALPHA_OES = 0x0000883D, - GL_SUBSAMPLE_DISTANCE_AMD = 0x0000883F, - GL_MATRIX_PALETTE_ARB = 0x00008840, - GL_MATRIX_PALETTE_OES = 0x00008840, - GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB = 0x00008841, - GL_MAX_PALETTE_MATRICES_ARB = 0x00008842, - GL_MAX_PALETTE_MATRICES_OES = 0x00008842, - GL_CURRENT_PALETTE_MATRIX_ARB = 0x00008843, - GL_CURRENT_PALETTE_MATRIX_OES = 0x00008843, - GL_MATRIX_INDEX_ARRAY_ARB = 0x00008844, - GL_MATRIX_INDEX_ARRAY_OES = 0x00008844, - GL_CURRENT_MATRIX_INDEX_ARB = 0x00008845, - GL_MATRIX_INDEX_ARRAY_SIZE_ARB = 0x00008846, - GL_MATRIX_INDEX_ARRAY_SIZE_OES = 0x00008846, - GL_MATRIX_INDEX_ARRAY_TYPE_ARB = 0x00008847, - GL_MATRIX_INDEX_ARRAY_TYPE_OES = 0x00008847, - GL_MATRIX_INDEX_ARRAY_STRIDE_ARB = 0x00008848, - GL_MATRIX_INDEX_ARRAY_STRIDE_OES = 0x00008848, - GL_MATRIX_INDEX_ARRAY_POINTER_ARB = 0x00008849, - GL_MATRIX_INDEX_ARRAY_POINTER_OES = 0x00008849, - GL_TEXTURE_DEPTH_SIZE = 0x0000884A, - GL_TEXTURE_DEPTH_SIZE_ARB = 0x0000884A, - GL_DEPTH_TEXTURE_MODE = 0x0000884B, - GL_DEPTH_TEXTURE_MODE_ARB = 0x0000884B, - GL_TEXTURE_COMPARE_MODE = 0x0000884C, - GL_TEXTURE_COMPARE_MODE_ARB = 0x0000884C, - GL_TEXTURE_COMPARE_MODE_EXT = 0x0000884C, - GL_TEXTURE_COMPARE_FUNC = 0x0000884D, - GL_TEXTURE_COMPARE_FUNC_ARB = 0x0000884D, - GL_TEXTURE_COMPARE_FUNC_EXT = 0x0000884D, - GL_COMPARE_R_TO_TEXTURE = 0x0000884E, - GL_COMPARE_R_TO_TEXTURE_ARB = 0x0000884E, - GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT = 0x0000884E, - GL_COMPARE_REF_TO_TEXTURE = 0x0000884E, - GL_COMPARE_REF_TO_TEXTURE_EXT = 0x0000884E, - GL_TEXTURE_CUBE_MAP_SEAMLESS = 0x0000884F, - GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV = 0x00008850, - GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV = 0x00008851, - GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV = 0x00008852, - GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV = 0x00008853, - GL_OFFSET_HILO_TEXTURE_2D_NV = 0x00008854, - GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV = 0x00008855, - GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV = 0x00008856, - GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV = 0x00008857, - GL_DEPENDENT_HILO_TEXTURE_2D_NV = 0x00008858, - GL_DEPENDENT_RGB_TEXTURE_3D_NV = 0x00008859, - GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV = 0x0000885A, - GL_DOT_PRODUCT_PASS_THROUGH_NV = 0x0000885B, - GL_DOT_PRODUCT_TEXTURE_1D_NV = 0x0000885C, - GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV = 0x0000885D, - GL_HILO8_NV = 0x0000885E, - GL_SIGNED_HILO8_NV = 0x0000885F, - GL_FORCE_BLUE_TO_ONE_NV = 0x00008860, - GL_POINT_SPRITE = 0x00008861, - GL_POINT_SPRITE_ARB = 0x00008861, - GL_POINT_SPRITE_NV = 0x00008861, - GL_POINT_SPRITE_OES = 0x00008861, - GL_COORD_REPLACE = 0x00008862, - GL_COORD_REPLACE_ARB = 0x00008862, - GL_COORD_REPLACE_NV = 0x00008862, - GL_COORD_REPLACE_OES = 0x00008862, - GL_POINT_SPRITE_R_MODE_NV = 0x00008863, - GL_PIXEL_COUNTER_BITS_NV = 0x00008864, - GL_QUERY_COUNTER_BITS = 0x00008864, - GL_QUERY_COUNTER_BITS_ARB = 0x00008864, - GL_QUERY_COUNTER_BITS_EXT = 0x00008864, - GL_CURRENT_OCCLUSION_QUERY_ID_NV = 0x00008865, - GL_CURRENT_QUERY = 0x00008865, - GL_CURRENT_QUERY_ARB = 0x00008865, - GL_CURRENT_QUERY_EXT = 0x00008865, - GL_PIXEL_COUNT_NV = 0x00008866, - GL_QUERY_RESULT = 0x00008866, - GL_QUERY_RESULT_ARB = 0x00008866, - GL_QUERY_RESULT_EXT = 0x00008866, - GL_PIXEL_COUNT_AVAILABLE_NV = 0x00008867, - GL_QUERY_RESULT_AVAILABLE = 0x00008867, - GL_QUERY_RESULT_AVAILABLE_ARB = 0x00008867, - GL_QUERY_RESULT_AVAILABLE_EXT = 0x00008867, - GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV = 0x00008868, - GL_MAX_VERTEX_ATTRIBS = 0x00008869, - GL_MAX_VERTEX_ATTRIBS_ARB = 0x00008869, - GL_VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x0000886A, - GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB = 0x0000886A, - GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 0x0000886C, - GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_EXT = 0x0000886C, - GL_MAX_TESS_CONTROL_INPUT_COMPONENTS_OES = 0x0000886C, - GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 0x0000886D, - GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_EXT = 0x0000886D, - GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS_OES = 0x0000886D, - GL_DEPTH_STENCIL_TO_RGBA_NV = 0x0000886E, - GL_DEPTH_STENCIL_TO_BGRA_NV = 0x0000886F, - GL_FRAGMENT_PROGRAM_NV = 0x00008870, - GL_MAX_TEXTURE_COORDS = 0x00008871, - GL_MAX_TEXTURE_COORDS_ARB = 0x00008871, - GL_MAX_TEXTURE_COORDS_NV = 0x00008871, - GL_MAX_TEXTURE_IMAGE_UNITS = 0x00008872, - GL_MAX_TEXTURE_IMAGE_UNITS_ARB = 0x00008872, - GL_MAX_TEXTURE_IMAGE_UNITS_NV = 0x00008872, - GL_FRAGMENT_PROGRAM_BINDING_NV = 0x00008873, - GL_PROGRAM_ERROR_STRING_ARB = 0x00008874, - GL_PROGRAM_ERROR_STRING_NV = 0x00008874, - GL_PROGRAM_FORMAT_ASCII_ARB = 0x00008875, - GL_PROGRAM_FORMAT_ARB = 0x00008876, - GL_WRITE_PIXEL_DATA_RANGE_NV = 0x00008878, - GL_READ_PIXEL_DATA_RANGE_NV = 0x00008879, - GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV = 0x0000887A, - GL_READ_PIXEL_DATA_RANGE_LENGTH_NV = 0x0000887B, - GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV = 0x0000887C, - GL_READ_PIXEL_DATA_RANGE_POINTER_NV = 0x0000887D, - GL_GEOMETRY_SHADER_INVOCATIONS = 0x0000887F, - GL_GEOMETRY_SHADER_INVOCATIONS_EXT = 0x0000887F, - GL_GEOMETRY_SHADER_INVOCATIONS_OES = 0x0000887F, - GL_FLOAT_R_NV = 0x00008880, - GL_FLOAT_RG_NV = 0x00008881, - GL_FLOAT_RGB_NV = 0x00008882, - GL_FLOAT_RGBA_NV = 0x00008883, - GL_FLOAT_R16_NV = 0x00008884, - GL_FLOAT_R32_NV = 0x00008885, - GL_FLOAT_RG16_NV = 0x00008886, - GL_FLOAT_RG32_NV = 0x00008887, - GL_FLOAT_RGB16_NV = 0x00008888, - GL_FLOAT_RGB32_NV = 0x00008889, - GL_FLOAT_RGBA16_NV = 0x0000888A, - GL_FLOAT_RGBA32_NV = 0x0000888B, - GL_TEXTURE_FLOAT_COMPONENTS_NV = 0x0000888C, - GL_FLOAT_CLEAR_COLOR_VALUE_NV = 0x0000888D, - GL_FLOAT_RGBA_MODE_NV = 0x0000888E, - GL_TEXTURE_UNSIGNED_REMAP_MODE_NV = 0x0000888F, - GL_DEPTH_BOUNDS_TEST_EXT = 0x00008890, - GL_DEPTH_BOUNDS_EXT = 0x00008891, - GL_ARRAY_BUFFER = 0x00008892, - GL_ARRAY_BUFFER_ARB = 0x00008892, - GL_ELEMENT_ARRAY_BUFFER = 0x00008893, - GL_ELEMENT_ARRAY_BUFFER_ARB = 0x00008893, - GL_ARRAY_BUFFER_BINDING = 0x00008894, - GL_ARRAY_BUFFER_BINDING_ARB = 0x00008894, - GL_ELEMENT_ARRAY_BUFFER_BINDING = 0x00008895, - GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB = 0x00008895, - GL_VERTEX_ARRAY_BUFFER_BINDING = 0x00008896, - GL_VERTEX_ARRAY_BUFFER_BINDING_ARB = 0x00008896, - GL_NORMAL_ARRAY_BUFFER_BINDING = 0x00008897, - GL_NORMAL_ARRAY_BUFFER_BINDING_ARB = 0x00008897, - GL_COLOR_ARRAY_BUFFER_BINDING = 0x00008898, - GL_COLOR_ARRAY_BUFFER_BINDING_ARB = 0x00008898, - GL_INDEX_ARRAY_BUFFER_BINDING = 0x00008899, - GL_INDEX_ARRAY_BUFFER_BINDING_ARB = 0x00008899, - GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING = 0x0000889A, - GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB = 0x0000889A, - GL_EDGE_FLAG_ARRAY_BUFFER_BINDING = 0x0000889B, - GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB = 0x0000889B, - GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING = 0x0000889C, - GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB = 0x0000889C, - GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB = 0x0000889D, - GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING = 0x0000889D, - GL_FOG_COORD_ARRAY_BUFFER_BINDING = 0x0000889D, - GL_WEIGHT_ARRAY_BUFFER_BINDING = 0x0000889E, - GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB = 0x0000889E, - GL_WEIGHT_ARRAY_BUFFER_BINDING_OES = 0x0000889E, - GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x0000889F, - GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB = 0x0000889F, - GL_PROGRAM_INSTRUCTIONS_ARB = 0x000088A0, - GL_MAX_PROGRAM_INSTRUCTIONS_ARB = 0x000088A1, - GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB = 0x000088A2, - GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB = 0x000088A3, - GL_PROGRAM_TEMPORARIES_ARB = 0x000088A4, - GL_MAX_PROGRAM_TEMPORARIES_ARB = 0x000088A5, - GL_PROGRAM_NATIVE_TEMPORARIES_ARB = 0x000088A6, - GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB = 0x000088A7, - GL_PROGRAM_PARAMETERS_ARB = 0x000088A8, - GL_MAX_PROGRAM_PARAMETERS_ARB = 0x000088A9, - GL_PROGRAM_NATIVE_PARAMETERS_ARB = 0x000088AA, - GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB = 0x000088AB, - GL_PROGRAM_ATTRIBS_ARB = 0x000088AC, - GL_MAX_PROGRAM_ATTRIBS_ARB = 0x000088AD, - GL_PROGRAM_NATIVE_ATTRIBS_ARB = 0x000088AE, - GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB = 0x000088AF, - GL_PROGRAM_ADDRESS_REGISTERS_ARB = 0x000088B0, - GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB = 0x000088B1, - GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = 0x000088B2, - GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB = 0x000088B3, - GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB = 0x000088B4, - GL_MAX_PROGRAM_ENV_PARAMETERS_ARB = 0x000088B5, - GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB = 0x000088B6, - GL_TRANSPOSE_CURRENT_MATRIX_ARB = 0x000088B7, - GL_READ_ONLY = 0x000088B8, - GL_READ_ONLY_ARB = 0x000088B8, - GL_WRITE_ONLY = 0x000088B9, - GL_WRITE_ONLY_ARB = 0x000088B9, - GL_WRITE_ONLY_OES = 0x000088B9, - GL_READ_WRITE = 0x000088BA, - GL_READ_WRITE_ARB = 0x000088BA, - GL_BUFFER_ACCESS = 0x000088BB, - GL_BUFFER_ACCESS_ARB = 0x000088BB, - GL_BUFFER_ACCESS_OES = 0x000088BB, - GL_BUFFER_MAPPED = 0x000088BC, - GL_BUFFER_MAPPED_ARB = 0x000088BC, - GL_BUFFER_MAPPED_OES = 0x000088BC, - GL_BUFFER_MAP_POINTER = 0x000088BD, - GL_BUFFER_MAP_POINTER_ARB = 0x000088BD, - GL_BUFFER_MAP_POINTER_OES = 0x000088BD, - GL_WRITE_DISCARD_NV = 0x000088BE, - GL_TIME_ELAPSED = 0x000088BF, - GL_TIME_ELAPSED_EXT = 0x000088BF, - GL_MATRIX0_ARB = 0x000088C0, - GL_MATRIX1_ARB = 0x000088C1, - GL_MATRIX2_ARB = 0x000088C2, - GL_MATRIX3_ARB = 0x000088C3, - GL_MATRIX4_ARB = 0x000088C4, - GL_MATRIX5_ARB = 0x000088C5, - GL_MATRIX6_ARB = 0x000088C6, - GL_MATRIX7_ARB = 0x000088C7, - GL_MATRIX8_ARB = 0x000088C8, - GL_MATRIX9_ARB = 0x000088C9, - GL_MATRIX10_ARB = 0x000088CA, - GL_MATRIX11_ARB = 0x000088CB, - GL_MATRIX12_ARB = 0x000088CC, - GL_MATRIX13_ARB = 0x000088CD, - GL_MATRIX14_ARB = 0x000088CE, - GL_MATRIX15_ARB = 0x000088CF, - GL_MATRIX16_ARB = 0x000088D0, - GL_MATRIX17_ARB = 0x000088D1, - GL_MATRIX18_ARB = 0x000088D2, - GL_MATRIX19_ARB = 0x000088D3, - GL_MATRIX20_ARB = 0x000088D4, - GL_MATRIX21_ARB = 0x000088D5, - GL_MATRIX22_ARB = 0x000088D6, - GL_MATRIX23_ARB = 0x000088D7, - GL_MATRIX24_ARB = 0x000088D8, - GL_MATRIX25_ARB = 0x000088D9, - GL_MATRIX26_ARB = 0x000088DA, - GL_MATRIX27_ARB = 0x000088DB, - GL_MATRIX28_ARB = 0x000088DC, - GL_MATRIX29_ARB = 0x000088DD, - GL_MATRIX30_ARB = 0x000088DE, - GL_MATRIX31_ARB = 0x000088DF, - GL_STREAM_DRAW = 0x000088E0, - GL_STREAM_DRAW_ARB = 0x000088E0, - GL_STREAM_READ = 0x000088E1, - GL_STREAM_READ_ARB = 0x000088E1, - GL_STREAM_COPY = 0x000088E2, - GL_STREAM_COPY_ARB = 0x000088E2, - GL_STATIC_DRAW = 0x000088E4, - GL_STATIC_DRAW_ARB = 0x000088E4, - GL_STATIC_READ = 0x000088E5, - GL_STATIC_READ_ARB = 0x000088E5, - GL_STATIC_COPY = 0x000088E6, - GL_STATIC_COPY_ARB = 0x000088E6, - GL_DYNAMIC_DRAW = 0x000088E8, - GL_DYNAMIC_DRAW_ARB = 0x000088E8, - GL_DYNAMIC_READ = 0x000088E9, - GL_DYNAMIC_READ_ARB = 0x000088E9, - GL_DYNAMIC_COPY = 0x000088EA, - GL_DYNAMIC_COPY_ARB = 0x000088EA, - GL_PIXEL_PACK_BUFFER = 0x000088EB, - GL_PIXEL_PACK_BUFFER_ARB = 0x000088EB, - GL_PIXEL_PACK_BUFFER_EXT = 0x000088EB, - GL_PIXEL_UNPACK_BUFFER = 0x000088EC, - GL_PIXEL_UNPACK_BUFFER_ARB = 0x000088EC, - GL_PIXEL_UNPACK_BUFFER_EXT = 0x000088EC, - GL_PIXEL_PACK_BUFFER_BINDING = 0x000088ED, - GL_PIXEL_PACK_BUFFER_BINDING_ARB = 0x000088ED, - GL_PIXEL_PACK_BUFFER_BINDING_EXT = 0x000088ED, - GL_ETC1_SRGB8_NV = 0x000088EE, - GL_PIXEL_UNPACK_BUFFER_BINDING = 0x000088EF, - GL_PIXEL_UNPACK_BUFFER_BINDING_ARB = 0x000088EF, - GL_PIXEL_UNPACK_BUFFER_BINDING_EXT = 0x000088EF, - GL_DEPTH24_STENCIL8 = 0x000088F0, - GL_DEPTH24_STENCIL8_EXT = 0x000088F0, - GL_DEPTH24_STENCIL8_OES = 0x000088F0, - GL_TEXTURE_STENCIL_SIZE = 0x000088F1, - GL_TEXTURE_STENCIL_SIZE_EXT = 0x000088F1, - GL_STENCIL_TAG_BITS_EXT = 0x000088F2, - GL_STENCIL_CLEAR_TAG_VALUE_EXT = 0x000088F3, - GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV = 0x000088F4, - GL_MAX_PROGRAM_CALL_DEPTH_NV = 0x000088F5, - GL_MAX_PROGRAM_IF_DEPTH_NV = 0x000088F6, - GL_MAX_PROGRAM_LOOP_DEPTH_NV = 0x000088F7, - GL_MAX_PROGRAM_LOOP_COUNT_NV = 0x000088F8, - GL_SRC1_COLOR = 0x000088F9, - GL_SRC1_COLOR_EXT = 0x000088F9, - GL_ONE_MINUS_SRC1_COLOR = 0x000088FA, - GL_ONE_MINUS_SRC1_COLOR_EXT = 0x000088FA, - GL_ONE_MINUS_SRC1_ALPHA = 0x000088FB, - GL_ONE_MINUS_SRC1_ALPHA_EXT = 0x000088FB, - GL_MAX_DUAL_SOURCE_DRAW_BUFFERS = 0x000088FC, - GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT = 0x000088FC, - GL_VERTEX_ATTRIB_ARRAY_INTEGER = 0x000088FD, - GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT = 0x000088FD, - GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV = 0x000088FD, - GL_VERTEX_ATTRIB_ARRAY_DIVISOR = 0x000088FE, - GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE = 0x000088FE, - GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB = 0x000088FE, - GL_VERTEX_ATTRIB_ARRAY_DIVISOR_EXT = 0x000088FE, - GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV = 0x000088FE, - GL_MAX_ARRAY_TEXTURE_LAYERS = 0x000088FF, - GL_MAX_ARRAY_TEXTURE_LAYERS_EXT = 0x000088FF, - GL_MIN_PROGRAM_TEXEL_OFFSET = 0x00008904, - GL_MIN_PROGRAM_TEXEL_OFFSET_EXT = 0x00008904, - GL_MIN_PROGRAM_TEXEL_OFFSET_NV = 0x00008904, - GL_MAX_PROGRAM_TEXEL_OFFSET = 0x00008905, - GL_MAX_PROGRAM_TEXEL_OFFSET_EXT = 0x00008905, - GL_MAX_PROGRAM_TEXEL_OFFSET_NV = 0x00008905, - GL_PROGRAM_ATTRIB_COMPONENTS_NV = 0x00008906, - GL_PROGRAM_RESULT_COMPONENTS_NV = 0x00008907, - GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV = 0x00008908, - GL_MAX_PROGRAM_RESULT_COMPONENTS_NV = 0x00008909, - GL_STENCIL_TEST_TWO_SIDE_EXT = 0x00008910, - GL_ACTIVE_STENCIL_FACE_EXT = 0x00008911, - GL_MIRROR_CLAMP_TO_BORDER_EXT = 0x00008912, - GL_SAMPLES_PASSED = 0x00008914, - GL_SAMPLES_PASSED_ARB = 0x00008914, - GL_GEOMETRY_VERTICES_OUT = 0x00008916, - GL_GEOMETRY_LINKED_VERTICES_OUT_EXT = 0x00008916, - GL_GEOMETRY_LINKED_VERTICES_OUT_OES = 0x00008916, - GL_GEOMETRY_INPUT_TYPE = 0x00008917, - GL_GEOMETRY_LINKED_INPUT_TYPE_EXT = 0x00008917, - GL_GEOMETRY_LINKED_INPUT_TYPE_OES = 0x00008917, - GL_GEOMETRY_OUTPUT_TYPE = 0x00008918, - GL_GEOMETRY_LINKED_OUTPUT_TYPE_EXT = 0x00008918, - GL_GEOMETRY_LINKED_OUTPUT_TYPE_OES = 0x00008918, - GL_SAMPLER_BINDING = 0x00008919, - GL_CLAMP_VERTEX_COLOR = 0x0000891A, - GL_CLAMP_VERTEX_COLOR_ARB = 0x0000891A, - GL_CLAMP_FRAGMENT_COLOR = 0x0000891B, - GL_CLAMP_FRAGMENT_COLOR_ARB = 0x0000891B, - GL_CLAMP_READ_COLOR = 0x0000891C, - GL_CLAMP_READ_COLOR_ARB = 0x0000891C, - GL_FIXED_ONLY = 0x0000891D, - GL_FIXED_ONLY_ARB = 0x0000891D, - GL_TESS_CONTROL_PROGRAM_NV = 0x0000891E, - GL_TESS_EVALUATION_PROGRAM_NV = 0x0000891F, - GL_FRAGMENT_SHADER_ATI = 0x00008920, - GL_REG_0_ATI = 0x00008921, - GL_REG_1_ATI = 0x00008922, - GL_REG_2_ATI = 0x00008923, - GL_REG_3_ATI = 0x00008924, - GL_REG_4_ATI = 0x00008925, - GL_REG_5_ATI = 0x00008926, - GL_REG_6_ATI = 0x00008927, - GL_REG_7_ATI = 0x00008928, - GL_REG_8_ATI = 0x00008929, - GL_REG_9_ATI = 0x0000892A, - GL_REG_10_ATI = 0x0000892B, - GL_REG_11_ATI = 0x0000892C, - GL_REG_12_ATI = 0x0000892D, - GL_REG_13_ATI = 0x0000892E, - GL_REG_14_ATI = 0x0000892F, - GL_REG_15_ATI = 0x00008930, - GL_REG_16_ATI = 0x00008931, - GL_REG_17_ATI = 0x00008932, - GL_REG_18_ATI = 0x00008933, - GL_REG_19_ATI = 0x00008934, - GL_REG_20_ATI = 0x00008935, - GL_REG_21_ATI = 0x00008936, - GL_REG_22_ATI = 0x00008937, - GL_REG_23_ATI = 0x00008938, - GL_REG_24_ATI = 0x00008939, - GL_REG_25_ATI = 0x0000893A, - GL_REG_26_ATI = 0x0000893B, - GL_REG_27_ATI = 0x0000893C, - GL_REG_28_ATI = 0x0000893D, - GL_REG_29_ATI = 0x0000893E, - GL_REG_30_ATI = 0x0000893F, - GL_REG_31_ATI = 0x00008940, - GL_CON_0_ATI = 0x00008941, - GL_CON_1_ATI = 0x00008942, - GL_CON_2_ATI = 0x00008943, - GL_CON_3_ATI = 0x00008944, - GL_CON_4_ATI = 0x00008945, - GL_CON_5_ATI = 0x00008946, - GL_CON_6_ATI = 0x00008947, - GL_CON_7_ATI = 0x00008948, - GL_CON_8_ATI = 0x00008949, - GL_CON_9_ATI = 0x0000894A, - GL_CON_10_ATI = 0x0000894B, - GL_CON_11_ATI = 0x0000894C, - GL_CON_12_ATI = 0x0000894D, - GL_CON_13_ATI = 0x0000894E, - GL_CON_14_ATI = 0x0000894F, - GL_CON_15_ATI = 0x00008950, - GL_CON_16_ATI = 0x00008951, - GL_CON_17_ATI = 0x00008952, - GL_CON_18_ATI = 0x00008953, - GL_CON_19_ATI = 0x00008954, - GL_CON_20_ATI = 0x00008955, - GL_CON_21_ATI = 0x00008956, - GL_CON_22_ATI = 0x00008957, - GL_CON_23_ATI = 0x00008958, - GL_CON_24_ATI = 0x00008959, - GL_CON_25_ATI = 0x0000895A, - GL_CON_26_ATI = 0x0000895B, - GL_CON_27_ATI = 0x0000895C, - GL_CON_28_ATI = 0x0000895D, - GL_CON_29_ATI = 0x0000895E, - GL_CON_30_ATI = 0x0000895F, - GL_CON_31_ATI = 0x00008960, - GL_MOV_ATI = 0x00008961, - GL_ADD_ATI = 0x00008963, - GL_MUL_ATI = 0x00008964, - GL_SUB_ATI = 0x00008965, - GL_DOT3_ATI = 0x00008966, - GL_DOT4_ATI = 0x00008967, - GL_MAD_ATI = 0x00008968, - GL_LERP_ATI = 0x00008969, - GL_CND_ATI = 0x0000896A, - GL_CND0_ATI = 0x0000896B, - GL_DOT2_ADD_ATI = 0x0000896C, - GL_SECONDARY_INTERPOLATOR_ATI = 0x0000896D, - GL_NUM_FRAGMENT_REGISTERS_ATI = 0x0000896E, - GL_NUM_FRAGMENT_CONSTANTS_ATI = 0x0000896F, - GL_NUM_PASSES_ATI = 0x00008970, - GL_NUM_INSTRUCTIONS_PER_PASS_ATI = 0x00008971, - GL_NUM_INSTRUCTIONS_TOTAL_ATI = 0x00008972, - GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI = 0x00008973, - GL_NUM_LOOPBACK_COMPONENTS_ATI = 0x00008974, - GL_COLOR_ALPHA_PAIRING_ATI = 0x00008975, - GL_SWIZZLE_STR_ATI = 0x00008976, - GL_SWIZZLE_STQ_ATI = 0x00008977, - GL_SWIZZLE_STR_DR_ATI = 0x00008978, - GL_SWIZZLE_STQ_DQ_ATI = 0x00008979, - GL_SWIZZLE_STRQ_ATI = 0x0000897A, - GL_SWIZZLE_STRQ_DQ_ATI = 0x0000897B, - GL_INTERLACE_OML = 0x00008980, - GL_INTERLACE_READ_OML = 0x00008981, - GL_FORMAT_SUBSAMPLE_24_24_OML = 0x00008982, - GL_FORMAT_SUBSAMPLE_244_244_OML = 0x00008983, - GL_PACK_RESAMPLE_OML = 0x00008984, - GL_UNPACK_RESAMPLE_OML = 0x00008985, - GL_RESAMPLE_REPLICATE_OML = 0x00008986, - GL_RESAMPLE_ZERO_FILL_OML = 0x00008987, - GL_RESAMPLE_AVERAGE_OML = 0x00008988, - GL_RESAMPLE_DECIMATE_OML = 0x00008989, - GL_POINT_SIZE_ARRAY_TYPE_OES = 0x0000898A, - GL_POINT_SIZE_ARRAY_STRIDE_OES = 0x0000898B, - GL_POINT_SIZE_ARRAY_POINTER_OES = 0x0000898C, - GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES = 0x0000898D, - GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES = 0x0000898E, - GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES = 0x0000898F, - GL_VERTEX_ATTRIB_MAP1_APPLE = 0x00008A00, - GL_VERTEX_ATTRIB_MAP2_APPLE = 0x00008A01, - GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE = 0x00008A02, - GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE = 0x00008A03, - GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE = 0x00008A04, - GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE = 0x00008A05, - GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE = 0x00008A06, - GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE = 0x00008A07, - GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE = 0x00008A08, - GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE = 0x00008A09, - GL_DRAW_PIXELS_APPLE = 0x00008A0A, - GL_FENCE_APPLE = 0x00008A0B, - GL_ELEMENT_ARRAY_APPLE = 0x00008A0C, - GL_ELEMENT_ARRAY_TYPE_APPLE = 0x00008A0D, - GL_ELEMENT_ARRAY_POINTER_APPLE = 0x00008A0E, - GL_COLOR_FLOAT_APPLE = 0x00008A0F, - GL_UNIFORM_BUFFER = 0x00008A11, - GL_BUFFER_SERIALIZED_MODIFY_APPLE = 0x00008A12, - GL_BUFFER_FLUSHING_UNMAP_APPLE = 0x00008A13, - GL_AUX_DEPTH_STENCIL_APPLE = 0x00008A14, - GL_PACK_ROW_BYTES_APPLE = 0x00008A15, - GL_UNPACK_ROW_BYTES_APPLE = 0x00008A16, - GL_RELEASED_APPLE = 0x00008A19, - GL_VOLATILE_APPLE = 0x00008A1A, - GL_RETAINED_APPLE = 0x00008A1B, - GL_UNDEFINED_APPLE = 0x00008A1C, - GL_PURGEABLE_APPLE = 0x00008A1D, - GL_RGB_422_APPLE = 0x00008A1F, - GL_UNIFORM_BUFFER_BINDING = 0x00008A28, - GL_UNIFORM_BUFFER_START = 0x00008A29, - GL_UNIFORM_BUFFER_SIZE = 0x00008A2A, - GL_MAX_VERTEX_UNIFORM_BLOCKS = 0x00008A2B, - GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 0x00008A2C, - GL_MAX_GEOMETRY_UNIFORM_BLOCKS_EXT = 0x00008A2C, - GL_MAX_GEOMETRY_UNIFORM_BLOCKS_OES = 0x00008A2C, - GL_MAX_FRAGMENT_UNIFORM_BLOCKS = 0x00008A2D, - GL_MAX_COMBINED_UNIFORM_BLOCKS = 0x00008A2E, - GL_MAX_UNIFORM_BUFFER_BINDINGS = 0x00008A2F, - GL_MAX_UNIFORM_BLOCK_SIZE = 0x00008A30, - GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS = 0x00008A31, - GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 0x00008A32, - GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_EXT = 0x00008A32, - GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS_OES = 0x00008A32, - GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS = 0x00008A33, - GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x00008A34, - GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH = 0x00008A35, - GL_ACTIVE_UNIFORM_BLOCKS = 0x00008A36, - GL_UNIFORM_TYPE = 0x00008A37, - GL_UNIFORM_SIZE = 0x00008A38, - GL_UNIFORM_NAME_LENGTH = 0x00008A39, - GL_UNIFORM_BLOCK_INDEX = 0x00008A3A, - GL_UNIFORM_OFFSET = 0x00008A3B, - GL_UNIFORM_ARRAY_STRIDE = 0x00008A3C, - GL_UNIFORM_MATRIX_STRIDE = 0x00008A3D, - GL_UNIFORM_IS_ROW_MAJOR = 0x00008A3E, - GL_UNIFORM_BLOCK_BINDING = 0x00008A3F, - GL_UNIFORM_BLOCK_DATA_SIZE = 0x00008A40, - GL_UNIFORM_BLOCK_NAME_LENGTH = 0x00008A41, - GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS = 0x00008A42, - GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES = 0x00008A43, - GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER = 0x00008A44, - GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER = 0x00008A45, - GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER = 0x00008A46, - GL_TEXTURE_SRGB_DECODE_EXT = 0x00008A48, - GL_DECODE_EXT = 0x00008A49, - GL_SKIP_DECODE_EXT = 0x00008A4A, - GL_PROGRAM_PIPELINE_OBJECT_EXT = 0x00008A4F, - GL_RGB_RAW_422_APPLE = 0x00008A51, - GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT = 0x00008A52, - GL_SYNC_OBJECT_APPLE = 0x00008A53, - GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT = 0x00008A54, - GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT = 0x00008A55, - GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT = 0x00008A56, - GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT = 0x00008A57, - GL_FRAGMENT_SHADER = 0x00008B30, - GL_FRAGMENT_SHADER_ARB = 0x00008B30, - GL_VERTEX_SHADER = 0x00008B31, - GL_VERTEX_SHADER_ARB = 0x00008B31, - GL_PROGRAM_OBJECT_ARB = 0x00008B40, - GL_PROGRAM_OBJECT_EXT = 0x00008B40, - GL_SHADER_OBJECT_ARB = 0x00008B48, - GL_SHADER_OBJECT_EXT = 0x00008B48, - GL_MAX_FRAGMENT_UNIFORM_COMPONENTS = 0x00008B49, - GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB = 0x00008B49, - GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x00008B4A, - GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB = 0x00008B4A, - GL_MAX_VARYING_FLOATS = 0x00008B4B, - GL_MAX_VARYING_COMPONENTS = 0x00008B4B, - GL_MAX_VARYING_COMPONENTS_EXT = 0x00008B4B, - GL_MAX_VARYING_FLOATS_ARB = 0x00008B4B, - GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x00008B4C, - GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB = 0x00008B4C, - GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x00008B4D, - GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB = 0x00008B4D, - GL_OBJECT_TYPE_ARB = 0x00008B4E, - GL_SHADER_TYPE = 0x00008B4F, - GL_OBJECT_SUBTYPE_ARB = 0x00008B4F, - GL_FLOAT_VEC2 = 0x00008B50, - GL_FLOAT_VEC2_ARB = 0x00008B50, - GL_FLOAT_VEC3 = 0x00008B51, - GL_FLOAT_VEC3_ARB = 0x00008B51, - GL_FLOAT_VEC4 = 0x00008B52, - GL_FLOAT_VEC4_ARB = 0x00008B52, - GL_INT_VEC2 = 0x00008B53, - GL_INT_VEC2_ARB = 0x00008B53, - GL_INT_VEC3 = 0x00008B54, - GL_INT_VEC3_ARB = 0x00008B54, - GL_INT_VEC4 = 0x00008B55, - GL_INT_VEC4_ARB = 0x00008B55, - GL_BOOL = 0x00008B56, - GL_BOOL_ARB = 0x00008B56, - GL_BOOL_VEC2 = 0x00008B57, - GL_BOOL_VEC2_ARB = 0x00008B57, - GL_BOOL_VEC3 = 0x00008B58, - GL_BOOL_VEC3_ARB = 0x00008B58, - GL_BOOL_VEC4 = 0x00008B59, - GL_BOOL_VEC4_ARB = 0x00008B59, - GL_FLOAT_MAT2 = 0x00008B5A, - GL_FLOAT_MAT2_ARB = 0x00008B5A, - GL_FLOAT_MAT3 = 0x00008B5B, - GL_FLOAT_MAT3_ARB = 0x00008B5B, - GL_FLOAT_MAT4 = 0x00008B5C, - GL_FLOAT_MAT4_ARB = 0x00008B5C, - GL_SAMPLER_1D = 0x00008B5D, - GL_SAMPLER_1D_ARB = 0x00008B5D, - GL_SAMPLER_2D = 0x00008B5E, - GL_SAMPLER_2D_ARB = 0x00008B5E, - GL_SAMPLER_3D = 0x00008B5F, - GL_SAMPLER_3D_ARB = 0x00008B5F, - GL_SAMPLER_3D_OES = 0x00008B5F, - GL_SAMPLER_CUBE = 0x00008B60, - GL_SAMPLER_CUBE_ARB = 0x00008B60, - GL_SAMPLER_1D_SHADOW = 0x00008B61, - GL_SAMPLER_1D_SHADOW_ARB = 0x00008B61, - GL_SAMPLER_2D_SHADOW = 0x00008B62, - GL_SAMPLER_2D_SHADOW_ARB = 0x00008B62, - GL_SAMPLER_2D_SHADOW_EXT = 0x00008B62, - GL_SAMPLER_2D_RECT = 0x00008B63, - GL_SAMPLER_2D_RECT_ARB = 0x00008B63, - GL_SAMPLER_2D_RECT_SHADOW = 0x00008B64, - GL_SAMPLER_2D_RECT_SHADOW_ARB = 0x00008B64, - GL_FLOAT_MAT2x3 = 0x00008B65, - GL_FLOAT_MAT2x3_NV = 0x00008B65, - GL_FLOAT_MAT2x4 = 0x00008B66, - GL_FLOAT_MAT2x4_NV = 0x00008B66, - GL_FLOAT_MAT3x2 = 0x00008B67, - GL_FLOAT_MAT3x2_NV = 0x00008B67, - GL_FLOAT_MAT3x4 = 0x00008B68, - GL_FLOAT_MAT3x4_NV = 0x00008B68, - GL_FLOAT_MAT4x2 = 0x00008B69, - GL_FLOAT_MAT4x2_NV = 0x00008B69, - GL_FLOAT_MAT4x3 = 0x00008B6A, - GL_FLOAT_MAT4x3_NV = 0x00008B6A, - GL_DELETE_STATUS = 0x00008B80, - GL_OBJECT_DELETE_STATUS_ARB = 0x00008B80, - GL_COMPILE_STATUS = 0x00008B81, - GL_OBJECT_COMPILE_STATUS_ARB = 0x00008B81, - GL_LINK_STATUS = 0x00008B82, - GL_OBJECT_LINK_STATUS_ARB = 0x00008B82, - GL_VALIDATE_STATUS = 0x00008B83, - GL_OBJECT_VALIDATE_STATUS_ARB = 0x00008B83, - GL_INFO_LOG_LENGTH = 0x00008B84, - GL_OBJECT_INFO_LOG_LENGTH_ARB = 0x00008B84, - GL_ATTACHED_SHADERS = 0x00008B85, - GL_OBJECT_ATTACHED_OBJECTS_ARB = 0x00008B85, - GL_ACTIVE_UNIFORMS = 0x00008B86, - GL_OBJECT_ACTIVE_UNIFORMS_ARB = 0x00008B86, - GL_ACTIVE_UNIFORM_MAX_LENGTH = 0x00008B87, - GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB = 0x00008B87, - GL_SHADER_SOURCE_LENGTH = 0x00008B88, - GL_OBJECT_SHADER_SOURCE_LENGTH_ARB = 0x00008B88, - GL_ACTIVE_ATTRIBUTES = 0x00008B89, - GL_OBJECT_ACTIVE_ATTRIBUTES_ARB = 0x00008B89, - GL_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x00008B8A, - GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB = 0x00008B8A, - GL_FRAGMENT_SHADER_DERIVATIVE_HINT = 0x00008B8B, - GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB = 0x00008B8B, - GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES = 0x00008B8B, - GL_SHADING_LANGUAGE_VERSION = 0x00008B8C, - GL_SHADING_LANGUAGE_VERSION_ARB = 0x00008B8C, - GL_CURRENT_PROGRAM = 0x00008B8D, - GL_PALETTE4_RGB8_OES = 0x00008B90, - GL_PALETTE4_RGBA8_OES = 0x00008B91, - GL_PALETTE4_R5_G6_B5_OES = 0x00008B92, - GL_PALETTE4_RGBA4_OES = 0x00008B93, - GL_PALETTE4_RGB5_A1_OES = 0x00008B94, - GL_PALETTE8_RGB8_OES = 0x00008B95, - GL_PALETTE8_RGBA8_OES = 0x00008B96, - GL_PALETTE8_R5_G6_B5_OES = 0x00008B97, - GL_PALETTE8_RGBA4_OES = 0x00008B98, - GL_PALETTE8_RGB5_A1_OES = 0x00008B99, - GL_IMPLEMENTATION_COLOR_READ_TYPE = 0x00008B9A, - GL_IMPLEMENTATION_COLOR_READ_TYPE_OES = 0x00008B9A, - GL_IMPLEMENTATION_COLOR_READ_FORMAT = 0x00008B9B, - GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES = 0x00008B9B, - GL_POINT_SIZE_ARRAY_OES = 0x00008B9C, - GL_TEXTURE_CROP_RECT_OES = 0x00008B9D, - GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES = 0x00008B9E, - GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES = 0x00008B9F, - GL_FRAGMENT_PROGRAM_POSITION_MESA = 0x00008BB0, - GL_FRAGMENT_PROGRAM_CALLBACK_MESA = 0x00008BB1, - GL_FRAGMENT_PROGRAM_CALLBACK_FUNC_MESA = 0x00008BB2, - GL_FRAGMENT_PROGRAM_CALLBACK_DATA_MESA = 0x00008BB3, - GL_VERTEX_PROGRAM_POSITION_MESA = 0x00008BB4, - GL_VERTEX_PROGRAM_CALLBACK_MESA = 0x00008BB5, - GL_VERTEX_PROGRAM_CALLBACK_FUNC_MESA = 0x00008BB6, - GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA = 0x00008BB7, - GL_COUNTER_TYPE_AMD = 0x00008BC0, - GL_COUNTER_RANGE_AMD = 0x00008BC1, - GL_UNSIGNED_INT64_AMD = 0x00008BC2, - GL_PERCENTAGE_AMD = 0x00008BC3, - GL_PERFMON_RESULT_AVAILABLE_AMD = 0x00008BC4, - GL_PERFMON_RESULT_SIZE_AMD = 0x00008BC5, - GL_PERFMON_RESULT_AMD = 0x00008BC6, - GL_TEXTURE_WIDTH_QCOM = 0x00008BD2, - GL_TEXTURE_HEIGHT_QCOM = 0x00008BD3, - GL_TEXTURE_DEPTH_QCOM = 0x00008BD4, - GL_TEXTURE_INTERNAL_FORMAT_QCOM = 0x00008BD5, - GL_TEXTURE_FORMAT_QCOM = 0x00008BD6, - GL_TEXTURE_TYPE_QCOM = 0x00008BD7, - GL_TEXTURE_IMAGE_VALID_QCOM = 0x00008BD8, - GL_TEXTURE_NUM_LEVELS_QCOM = 0x00008BD9, - GL_TEXTURE_TARGET_QCOM = 0x00008BDA, - GL_TEXTURE_OBJECT_VALID_QCOM = 0x00008BDB, - GL_STATE_RESTORE = 0x00008BDC, - GL_SAMPLER_EXTERNAL_2D_Y2Y_EXT = 0x00008BE7, - GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x00008C00, - GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x00008C01, - GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x00008C02, - GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x00008C03, - GL_MODULATE_COLOR_IMG = 0x00008C04, - GL_RECIP_ADD_SIGNED_ALPHA_IMG = 0x00008C05, - GL_TEXTURE_ALPHA_MODULATE_IMG = 0x00008C06, - GL_FACTOR_ALPHA_MODULATE_IMG = 0x00008C07, - GL_FRAGMENT_ALPHA_MODULATE_IMG = 0x00008C08, - GL_ADD_BLEND_IMG = 0x00008C09, - GL_SGX_BINARY_IMG = 0x00008C0A, - GL_TEXTURE_RED_TYPE = 0x00008C10, - GL_TEXTURE_RED_TYPE_ARB = 0x00008C10, - GL_TEXTURE_GREEN_TYPE = 0x00008C11, - GL_TEXTURE_GREEN_TYPE_ARB = 0x00008C11, - GL_TEXTURE_BLUE_TYPE = 0x00008C12, - GL_TEXTURE_BLUE_TYPE_ARB = 0x00008C12, - GL_TEXTURE_ALPHA_TYPE = 0x00008C13, - GL_TEXTURE_ALPHA_TYPE_ARB = 0x00008C13, - GL_TEXTURE_LUMINANCE_TYPE = 0x00008C14, - GL_TEXTURE_LUMINANCE_TYPE_ARB = 0x00008C14, - GL_TEXTURE_INTENSITY_TYPE = 0x00008C15, - GL_TEXTURE_INTENSITY_TYPE_ARB = 0x00008C15, - GL_TEXTURE_DEPTH_TYPE = 0x00008C16, - GL_TEXTURE_DEPTH_TYPE_ARB = 0x00008C16, - GL_UNSIGNED_NORMALIZED = 0x00008C17, - GL_UNSIGNED_NORMALIZED_ARB = 0x00008C17, - GL_UNSIGNED_NORMALIZED_EXT = 0x00008C17, - GL_TEXTURE_1D_ARRAY = 0x00008C18, - GL_TEXTURE_1D_ARRAY_EXT = 0x00008C18, - GL_PROXY_TEXTURE_1D_ARRAY = 0x00008C19, - GL_PROXY_TEXTURE_1D_ARRAY_EXT = 0x00008C19, - GL_TEXTURE_2D_ARRAY = 0x00008C1A, - GL_TEXTURE_2D_ARRAY_EXT = 0x00008C1A, - GL_PROXY_TEXTURE_2D_ARRAY = 0x00008C1B, - GL_PROXY_TEXTURE_2D_ARRAY_EXT = 0x00008C1B, - GL_TEXTURE_BINDING_1D_ARRAY = 0x00008C1C, - GL_TEXTURE_BINDING_1D_ARRAY_EXT = 0x00008C1C, - GL_TEXTURE_BINDING_2D_ARRAY = 0x00008C1D, - GL_TEXTURE_BINDING_2D_ARRAY_EXT = 0x00008C1D, - GL_GEOMETRY_PROGRAM_NV = 0x00008C26, - GL_MAX_PROGRAM_OUTPUT_VERTICES_NV = 0x00008C27, - GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV = 0x00008C28, - GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 0x00008C29, - GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB = 0x00008C29, - GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT = 0x00008C29, - GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_OES = 0x00008C29, - GL_TEXTURE_BUFFER = 0x00008C2A, - GL_TEXTURE_BUFFER_ARB = 0x00008C2A, - GL_TEXTURE_BUFFER_EXT = 0x00008C2A, - GL_TEXTURE_BUFFER_OES = 0x00008C2A, - GL_TEXTURE_BUFFER_BINDING = 0x00008C2A, - GL_TEXTURE_BUFFER_BINDING_EXT = 0x00008C2A, - GL_TEXTURE_BUFFER_BINDING_OES = 0x00008C2A, - GL_MAX_TEXTURE_BUFFER_SIZE = 0x00008C2B, - GL_MAX_TEXTURE_BUFFER_SIZE_ARB = 0x00008C2B, - GL_MAX_TEXTURE_BUFFER_SIZE_EXT = 0x00008C2B, - GL_MAX_TEXTURE_BUFFER_SIZE_OES = 0x00008C2B, - GL_TEXTURE_BINDING_BUFFER = 0x00008C2C, - GL_TEXTURE_BINDING_BUFFER_ARB = 0x00008C2C, - GL_TEXTURE_BINDING_BUFFER_EXT = 0x00008C2C, - GL_TEXTURE_BINDING_BUFFER_OES = 0x00008C2C, - GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 0x00008C2D, - GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB = 0x00008C2D, - GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT = 0x00008C2D, - GL_TEXTURE_BUFFER_DATA_STORE_BINDING_OES = 0x00008C2D, - GL_TEXTURE_BUFFER_FORMAT_ARB = 0x00008C2E, - GL_TEXTURE_BUFFER_FORMAT_EXT = 0x00008C2E, - GL_ANY_SAMPLES_PASSED = 0x00008C2F, - GL_ANY_SAMPLES_PASSED_EXT = 0x00008C2F, - GL_SAMPLE_SHADING = 0x00008C36, - GL_SAMPLE_SHADING_ARB = 0x00008C36, - GL_SAMPLE_SHADING_OES = 0x00008C36, - GL_MIN_SAMPLE_SHADING_VALUE = 0x00008C37, - GL_MIN_SAMPLE_SHADING_VALUE_ARB = 0x00008C37, - GL_MIN_SAMPLE_SHADING_VALUE_OES = 0x00008C37, - GL_R11F_G11F_B10F = 0x00008C3A, - GL_R11F_G11F_B10F_APPLE = 0x00008C3A, - GL_R11F_G11F_B10F_EXT = 0x00008C3A, - GL_UNSIGNED_INT_10F_11F_11F_REV = 0x00008C3B, - GL_UNSIGNED_INT_10F_11F_11F_REV_APPLE = 0x00008C3B, - GL_UNSIGNED_INT_10F_11F_11F_REV_EXT = 0x00008C3B, - GL_RGBA_SIGNED_COMPONENTS_EXT = 0x00008C3C, - GL_RGB9_E5 = 0x00008C3D, - GL_RGB9_E5_APPLE = 0x00008C3D, - GL_RGB9_E5_EXT = 0x00008C3D, - GL_UNSIGNED_INT_5_9_9_9_REV = 0x00008C3E, - GL_UNSIGNED_INT_5_9_9_9_REV_APPLE = 0x00008C3E, - GL_UNSIGNED_INT_5_9_9_9_REV_EXT = 0x00008C3E, - GL_TEXTURE_SHARED_SIZE = 0x00008C3F, - GL_TEXTURE_SHARED_SIZE_EXT = 0x00008C3F, - GL_SRGB = 0x00008C40, - GL_SRGB_EXT = 0x00008C40, - GL_SRGB8 = 0x00008C41, - GL_SRGB8_EXT = 0x00008C41, - GL_SRGB8_NV = 0x00008C41, - GL_SRGB_ALPHA = 0x00008C42, - GL_SRGB_ALPHA_EXT = 0x00008C42, - GL_SRGB8_ALPHA8 = 0x00008C43, - GL_SRGB8_ALPHA8_EXT = 0x00008C43, - GL_SLUMINANCE_ALPHA = 0x00008C44, - GL_SLUMINANCE_ALPHA_EXT = 0x00008C44, - GL_SLUMINANCE_ALPHA_NV = 0x00008C44, - GL_SLUMINANCE8_ALPHA8 = 0x00008C45, - GL_SLUMINANCE8_ALPHA8_EXT = 0x00008C45, - GL_SLUMINANCE8_ALPHA8_NV = 0x00008C45, - GL_SLUMINANCE = 0x00008C46, - GL_SLUMINANCE_EXT = 0x00008C46, - GL_SLUMINANCE_NV = 0x00008C46, - GL_SLUMINANCE8 = 0x00008C47, - GL_SLUMINANCE8_EXT = 0x00008C47, - GL_SLUMINANCE8_NV = 0x00008C47, - GL_COMPRESSED_SRGB = 0x00008C48, - GL_COMPRESSED_SRGB_EXT = 0x00008C48, - GL_COMPRESSED_SRGB_ALPHA = 0x00008C49, - GL_COMPRESSED_SRGB_ALPHA_EXT = 0x00008C49, - GL_COMPRESSED_SLUMINANCE = 0x00008C4A, - GL_COMPRESSED_SLUMINANCE_EXT = 0x00008C4A, - GL_COMPRESSED_SLUMINANCE_ALPHA = 0x00008C4B, - GL_COMPRESSED_SLUMINANCE_ALPHA_EXT = 0x00008C4B, - GL_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x00008C4C, - GL_COMPRESSED_SRGB_S3TC_DXT1_NV = 0x00008C4C, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x00008C4D, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV = 0x00008C4D, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x00008C4E, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV = 0x00008C4E, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x00008C4F, - GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV = 0x00008C4F, - GL_COMPRESSED_LUMINANCE_LATC1_EXT = 0x00008C70, - GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x00008C71, - GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x00008C72, - GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x00008C73, - GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV = 0x00008C74, - GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV = 0x00008C75, - GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH = 0x00008C76, - GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT = 0x00008C76, - GL_BACK_PRIMARY_COLOR_NV = 0x00008C77, - GL_BACK_SECONDARY_COLOR_NV = 0x00008C78, - GL_TEXTURE_COORD_NV = 0x00008C79, - GL_CLIP_DISTANCE_NV = 0x00008C7A, - GL_VERTEX_ID_NV = 0x00008C7B, - GL_PRIMITIVE_ID_NV = 0x00008C7C, - GL_GENERIC_ATTRIB_NV = 0x00008C7D, - GL_TRANSFORM_FEEDBACK_ATTRIBS_NV = 0x00008C7E, - GL_TRANSFORM_FEEDBACK_BUFFER_MODE = 0x00008C7F, - GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT = 0x00008C7F, - GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV = 0x00008C7F, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS = 0x00008C80, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT = 0x00008C80, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV = 0x00008C80, - GL_ACTIVE_VARYINGS_NV = 0x00008C81, - GL_ACTIVE_VARYING_MAX_LENGTH_NV = 0x00008C82, - GL_TRANSFORM_FEEDBACK_VARYINGS = 0x00008C83, - GL_TRANSFORM_FEEDBACK_VARYINGS_EXT = 0x00008C83, - GL_TRANSFORM_FEEDBACK_VARYINGS_NV = 0x00008C83, - GL_TRANSFORM_FEEDBACK_BUFFER_START = 0x00008C84, - GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT = 0x00008C84, - GL_TRANSFORM_FEEDBACK_BUFFER_START_NV = 0x00008C84, - GL_TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x00008C85, - GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT = 0x00008C85, - GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV = 0x00008C85, - GL_TRANSFORM_FEEDBACK_RECORD_NV = 0x00008C86, - GL_PRIMITIVES_GENERATED = 0x00008C87, - GL_PRIMITIVES_GENERATED_EXT = 0x00008C87, - GL_PRIMITIVES_GENERATED_NV = 0x00008C87, - GL_PRIMITIVES_GENERATED_OES = 0x00008C87, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = 0x00008C88, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT = 0x00008C88, - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV = 0x00008C88, - GL_RASTERIZER_DISCARD = 0x00008C89, - GL_RASTERIZER_DISCARD_EXT = 0x00008C89, - GL_RASTERIZER_DISCARD_NV = 0x00008C89, - GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x00008C8A, - GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT = 0x00008C8A, - GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV = 0x00008C8A, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x00008C8B, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT = 0x00008C8B, - GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV = 0x00008C8B, - GL_INTERLEAVED_ATTRIBS = 0x00008C8C, - GL_INTERLEAVED_ATTRIBS_EXT = 0x00008C8C, - GL_INTERLEAVED_ATTRIBS_NV = 0x00008C8C, - GL_SEPARATE_ATTRIBS = 0x00008C8D, - GL_SEPARATE_ATTRIBS_EXT = 0x00008C8D, - GL_SEPARATE_ATTRIBS_NV = 0x00008C8D, - GL_TRANSFORM_FEEDBACK_BUFFER = 0x00008C8E, - GL_TRANSFORM_FEEDBACK_BUFFER_EXT = 0x00008C8E, - GL_TRANSFORM_FEEDBACK_BUFFER_NV = 0x00008C8E, - GL_TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x00008C8F, - GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT = 0x00008C8F, - GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV = 0x00008C8F, - GL_ATC_RGB_AMD = 0x00008C92, - GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = 0x00008C93, - GL_POINT_SPRITE_COORD_ORIGIN = 0x00008CA0, - GL_LOWER_LEFT = 0x00008CA1, - GL_UPPER_LEFT = 0x00008CA2, - GL_STENCIL_BACK_REF = 0x00008CA3, - GL_STENCIL_BACK_VALUE_MASK = 0x00008CA4, - GL_STENCIL_BACK_WRITEMASK = 0x00008CA5, - GL_DRAW_FRAMEBUFFER_BINDING = 0x00008CA6, - GL_DRAW_FRAMEBUFFER_BINDING_ANGLE = 0x00008CA6, - GL_DRAW_FRAMEBUFFER_BINDING_APPLE = 0x00008CA6, - GL_DRAW_FRAMEBUFFER_BINDING_EXT = 0x00008CA6, - GL_DRAW_FRAMEBUFFER_BINDING_NV = 0x00008CA6, - GL_FRAMEBUFFER_BINDING = 0x00008CA6, - GL_FRAMEBUFFER_BINDING_ANGLE = 0x00008CA6, - GL_FRAMEBUFFER_BINDING_EXT = 0x00008CA6, - GL_FRAMEBUFFER_BINDING_OES = 0x00008CA6, - GL_RENDERBUFFER_BINDING = 0x00008CA7, - GL_RENDERBUFFER_BINDING_ANGLE = 0x00008CA7, - GL_RENDERBUFFER_BINDING_EXT = 0x00008CA7, - GL_RENDERBUFFER_BINDING_OES = 0x00008CA7, - GL_READ_FRAMEBUFFER = 0x00008CA8, - GL_READ_FRAMEBUFFER_ANGLE = 0x00008CA8, - GL_READ_FRAMEBUFFER_APPLE = 0x00008CA8, - GL_READ_FRAMEBUFFER_EXT = 0x00008CA8, - GL_READ_FRAMEBUFFER_NV = 0x00008CA8, - GL_DRAW_FRAMEBUFFER = 0x00008CA9, - GL_DRAW_FRAMEBUFFER_ANGLE = 0x00008CA9, - GL_DRAW_FRAMEBUFFER_APPLE = 0x00008CA9, - GL_DRAW_FRAMEBUFFER_EXT = 0x00008CA9, - GL_DRAW_FRAMEBUFFER_NV = 0x00008CA9, - GL_READ_FRAMEBUFFER_BINDING = 0x00008CAA, - GL_READ_FRAMEBUFFER_BINDING_ANGLE = 0x00008CAA, - GL_READ_FRAMEBUFFER_BINDING_APPLE = 0x00008CAA, - GL_READ_FRAMEBUFFER_BINDING_EXT = 0x00008CAA, - GL_READ_FRAMEBUFFER_BINDING_NV = 0x00008CAA, - GL_RENDERBUFFER_COVERAGE_SAMPLES_NV = 0x00008CAB, - GL_RENDERBUFFER_SAMPLES = 0x00008CAB, - GL_RENDERBUFFER_SAMPLES_ANGLE = 0x00008CAB, - GL_RENDERBUFFER_SAMPLES_APPLE = 0x00008CAB, - GL_RENDERBUFFER_SAMPLES_EXT = 0x00008CAB, - GL_RENDERBUFFER_SAMPLES_NV = 0x00008CAB, - GL_DEPTH_COMPONENT32F = 0x00008CAC, - GL_DEPTH32F_STENCIL8 = 0x00008CAD, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x00008CD0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT = 0x00008CD0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES = 0x00008CD0, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x00008CD1, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT = 0x00008CD1, - GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES = 0x00008CD1, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x00008CD2, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT = 0x00008CD2, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES = 0x00008CD2, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x00008CD3, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT = 0x00008CD3, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES = 0x00008CD3, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT = 0x00008CD4, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES = 0x00008CD4, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER = 0x00008CD4, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT = 0x00008CD4, - GL_FRAMEBUFFER_COMPLETE = 0x00008CD5, - GL_FRAMEBUFFER_COMPLETE_EXT = 0x00008CD5, - GL_FRAMEBUFFER_COMPLETE_OES = 0x00008CD5, - GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x00008CD6, - GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT = 0x00008CD6, - GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES = 0x00008CD6, - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x00008CD7, - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT = 0x00008CD7, - GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES = 0x00008CD7, - GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x00008CD9, - GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT = 0x00008CD9, - GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES = 0x00008CD9, - GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT = 0x00008CDA, - GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES = 0x00008CDA, - GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER = 0x00008CDB, - GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT = 0x00008CDB, - GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES = 0x00008CDB, - GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER = 0x00008CDC, - GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = 0x00008CDC, - GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES = 0x00008CDC, - GL_FRAMEBUFFER_UNSUPPORTED = 0x00008CDD, - GL_FRAMEBUFFER_UNSUPPORTED_EXT = 0x00008CDD, - GL_FRAMEBUFFER_UNSUPPORTED_OES = 0x00008CDD, - GL_MAX_COLOR_ATTACHMENTS = 0x00008CDF, - GL_MAX_COLOR_ATTACHMENTS_EXT = 0x00008CDF, - GL_MAX_COLOR_ATTACHMENTS_NV = 0x00008CDF, - GL_COLOR_ATTACHMENT0 = 0x00008CE0, - GL_COLOR_ATTACHMENT0_EXT = 0x00008CE0, - GL_COLOR_ATTACHMENT0_NV = 0x00008CE0, - GL_COLOR_ATTACHMENT0_OES = 0x00008CE0, - GL_COLOR_ATTACHMENT1 = 0x00008CE1, - GL_COLOR_ATTACHMENT1_EXT = 0x00008CE1, - GL_COLOR_ATTACHMENT1_NV = 0x00008CE1, - GL_COLOR_ATTACHMENT2 = 0x00008CE2, - GL_COLOR_ATTACHMENT2_EXT = 0x00008CE2, - GL_COLOR_ATTACHMENT2_NV = 0x00008CE2, - GL_COLOR_ATTACHMENT3 = 0x00008CE3, - GL_COLOR_ATTACHMENT3_EXT = 0x00008CE3, - GL_COLOR_ATTACHMENT3_NV = 0x00008CE3, - GL_COLOR_ATTACHMENT4 = 0x00008CE4, - GL_COLOR_ATTACHMENT4_EXT = 0x00008CE4, - GL_COLOR_ATTACHMENT4_NV = 0x00008CE4, - GL_COLOR_ATTACHMENT5 = 0x00008CE5, - GL_COLOR_ATTACHMENT5_EXT = 0x00008CE5, - GL_COLOR_ATTACHMENT5_NV = 0x00008CE5, - GL_COLOR_ATTACHMENT6 = 0x00008CE6, - GL_COLOR_ATTACHMENT6_EXT = 0x00008CE6, - GL_COLOR_ATTACHMENT6_NV = 0x00008CE6, - GL_COLOR_ATTACHMENT7 = 0x00008CE7, - GL_COLOR_ATTACHMENT7_EXT = 0x00008CE7, - GL_COLOR_ATTACHMENT7_NV = 0x00008CE7, - GL_COLOR_ATTACHMENT8 = 0x00008CE8, - GL_COLOR_ATTACHMENT8_EXT = 0x00008CE8, - GL_COLOR_ATTACHMENT8_NV = 0x00008CE8, - GL_COLOR_ATTACHMENT9 = 0x00008CE9, - GL_COLOR_ATTACHMENT9_EXT = 0x00008CE9, - GL_COLOR_ATTACHMENT9_NV = 0x00008CE9, - GL_COLOR_ATTACHMENT10 = 0x00008CEA, - GL_COLOR_ATTACHMENT10_EXT = 0x00008CEA, - GL_COLOR_ATTACHMENT10_NV = 0x00008CEA, - GL_COLOR_ATTACHMENT11 = 0x00008CEB, - GL_COLOR_ATTACHMENT11_EXT = 0x00008CEB, - GL_COLOR_ATTACHMENT11_NV = 0x00008CEB, - GL_COLOR_ATTACHMENT12 = 0x00008CEC, - GL_COLOR_ATTACHMENT12_EXT = 0x00008CEC, - GL_COLOR_ATTACHMENT12_NV = 0x00008CEC, - GL_COLOR_ATTACHMENT13 = 0x00008CED, - GL_COLOR_ATTACHMENT13_EXT = 0x00008CED, - GL_COLOR_ATTACHMENT13_NV = 0x00008CED, - GL_COLOR_ATTACHMENT14 = 0x00008CEE, - GL_COLOR_ATTACHMENT14_EXT = 0x00008CEE, - GL_COLOR_ATTACHMENT14_NV = 0x00008CEE, - GL_COLOR_ATTACHMENT15 = 0x00008CEF, - GL_COLOR_ATTACHMENT15_EXT = 0x00008CEF, - GL_COLOR_ATTACHMENT15_NV = 0x00008CEF, - GL_COLOR_ATTACHMENT16 = 0x00008CF0, - GL_COLOR_ATTACHMENT17 = 0x00008CF1, - GL_COLOR_ATTACHMENT18 = 0x00008CF2, - GL_COLOR_ATTACHMENT19 = 0x00008CF3, - GL_COLOR_ATTACHMENT20 = 0x00008CF4, - GL_COLOR_ATTACHMENT21 = 0x00008CF5, - GL_COLOR_ATTACHMENT22 = 0x00008CF6, - GL_COLOR_ATTACHMENT23 = 0x00008CF7, - GL_COLOR_ATTACHMENT24 = 0x00008CF8, - GL_COLOR_ATTACHMENT25 = 0x00008CF9, - GL_COLOR_ATTACHMENT26 = 0x00008CFA, - GL_COLOR_ATTACHMENT27 = 0x00008CFB, - GL_COLOR_ATTACHMENT28 = 0x00008CFC, - GL_COLOR_ATTACHMENT29 = 0x00008CFD, - GL_COLOR_ATTACHMENT30 = 0x00008CFE, - GL_COLOR_ATTACHMENT31 = 0x00008CFF, - GL_DEPTH_ATTACHMENT = 0x00008D00, - GL_DEPTH_ATTACHMENT_EXT = 0x00008D00, - GL_DEPTH_ATTACHMENT_OES = 0x00008D00, - GL_STENCIL_ATTACHMENT = 0x00008D20, - GL_STENCIL_ATTACHMENT_EXT = 0x00008D20, - GL_STENCIL_ATTACHMENT_OES = 0x00008D20, - GL_FRAMEBUFFER = 0x00008D40, - GL_FRAMEBUFFER_EXT = 0x00008D40, - GL_FRAMEBUFFER_OES = 0x00008D40, - GL_RENDERBUFFER = 0x00008D41, - GL_RENDERBUFFER_EXT = 0x00008D41, - GL_RENDERBUFFER_OES = 0x00008D41, - GL_RENDERBUFFER_WIDTH = 0x00008D42, - GL_RENDERBUFFER_WIDTH_EXT = 0x00008D42, - GL_RENDERBUFFER_WIDTH_OES = 0x00008D42, - GL_RENDERBUFFER_HEIGHT = 0x00008D43, - GL_RENDERBUFFER_HEIGHT_EXT = 0x00008D43, - GL_RENDERBUFFER_HEIGHT_OES = 0x00008D43, - GL_RENDERBUFFER_INTERNAL_FORMAT = 0x00008D44, - GL_RENDERBUFFER_INTERNAL_FORMAT_EXT = 0x00008D44, - GL_RENDERBUFFER_INTERNAL_FORMAT_OES = 0x00008D44, - GL_STENCIL_INDEX1 = 0x00008D46, - GL_STENCIL_INDEX1_EXT = 0x00008D46, - GL_STENCIL_INDEX1_OES = 0x00008D46, - GL_STENCIL_INDEX4 = 0x00008D47, - GL_STENCIL_INDEX4_EXT = 0x00008D47, - GL_STENCIL_INDEX4_OES = 0x00008D47, - GL_STENCIL_INDEX8 = 0x00008D48, - GL_STENCIL_INDEX8_EXT = 0x00008D48, - GL_STENCIL_INDEX8_OES = 0x00008D48, - GL_STENCIL_INDEX16 = 0x00008D49, - GL_STENCIL_INDEX16_EXT = 0x00008D49, - GL_RENDERBUFFER_RED_SIZE = 0x00008D50, - GL_RENDERBUFFER_RED_SIZE_EXT = 0x00008D50, - GL_RENDERBUFFER_RED_SIZE_OES = 0x00008D50, - GL_RENDERBUFFER_GREEN_SIZE = 0x00008D51, - GL_RENDERBUFFER_GREEN_SIZE_EXT = 0x00008D51, - GL_RENDERBUFFER_GREEN_SIZE_OES = 0x00008D51, - GL_RENDERBUFFER_BLUE_SIZE = 0x00008D52, - GL_RENDERBUFFER_BLUE_SIZE_EXT = 0x00008D52, - GL_RENDERBUFFER_BLUE_SIZE_OES = 0x00008D52, - GL_RENDERBUFFER_ALPHA_SIZE = 0x00008D53, - GL_RENDERBUFFER_ALPHA_SIZE_EXT = 0x00008D53, - GL_RENDERBUFFER_ALPHA_SIZE_OES = 0x00008D53, - GL_RENDERBUFFER_DEPTH_SIZE = 0x00008D54, - GL_RENDERBUFFER_DEPTH_SIZE_EXT = 0x00008D54, - GL_RENDERBUFFER_DEPTH_SIZE_OES = 0x00008D54, - GL_RENDERBUFFER_STENCIL_SIZE = 0x00008D55, - GL_RENDERBUFFER_STENCIL_SIZE_EXT = 0x00008D55, - GL_RENDERBUFFER_STENCIL_SIZE_OES = 0x00008D55, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE = 0x00008D56, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE = 0x00008D56, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE = 0x00008D56, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = 0x00008D56, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV = 0x00008D56, - GL_MAX_SAMPLES = 0x00008D57, - GL_MAX_SAMPLES_ANGLE = 0x00008D57, - GL_MAX_SAMPLES_APPLE = 0x00008D57, - GL_MAX_SAMPLES_EXT = 0x00008D57, - GL_MAX_SAMPLES_NV = 0x00008D57, - GL_TEXTURE_GEN_STR_OES = 0x00008D60, - GL_HALF_FLOAT_OES = 0x00008D61, - GL_RGB565_OES = 0x00008D62, - GL_RGB565 = 0x00008D62, - GL_ETC1_RGB8_OES = 0x00008D64, - GL_TEXTURE_EXTERNAL_OES = 0x00008D65, - GL_SAMPLER_EXTERNAL_OES = 0x00008D66, - GL_TEXTURE_BINDING_EXTERNAL_OES = 0x00008D67, - GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES = 0x00008D68, - GL_PRIMITIVE_RESTART_FIXED_INDEX = 0x00008D69, - GL_ANY_SAMPLES_PASSED_CONSERVATIVE = 0x00008D6A, - GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT = 0x00008D6A, - GL_MAX_ELEMENT_INDEX = 0x00008D6B, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT = 0x00008D6C, - GL_RGBA32UI = 0x00008D70, - GL_RGBA32UI_EXT = 0x00008D70, - GL_RGB32UI = 0x00008D71, - GL_RGB32UI_EXT = 0x00008D71, - GL_ALPHA32UI_EXT = 0x00008D72, - GL_INTENSITY32UI_EXT = 0x00008D73, - GL_LUMINANCE32UI_EXT = 0x00008D74, - GL_LUMINANCE_ALPHA32UI_EXT = 0x00008D75, - GL_RGBA16UI = 0x00008D76, - GL_RGBA16UI_EXT = 0x00008D76, - GL_RGB16UI = 0x00008D77, - GL_RGB16UI_EXT = 0x00008D77, - GL_ALPHA16UI_EXT = 0x00008D78, - GL_INTENSITY16UI_EXT = 0x00008D79, - GL_LUMINANCE16UI_EXT = 0x00008D7A, - GL_LUMINANCE_ALPHA16UI_EXT = 0x00008D7B, - GL_RGBA8UI = 0x00008D7C, - GL_RGBA8UI_EXT = 0x00008D7C, - GL_RGB8UI = 0x00008D7D, - GL_RGB8UI_EXT = 0x00008D7D, - GL_ALPHA8UI_EXT = 0x00008D7E, - GL_INTENSITY8UI_EXT = 0x00008D7F, - GL_LUMINANCE8UI_EXT = 0x00008D80, - GL_LUMINANCE_ALPHA8UI_EXT = 0x00008D81, - GL_RGBA32I = 0x00008D82, - GL_RGBA32I_EXT = 0x00008D82, - GL_RGB32I = 0x00008D83, - GL_RGB32I_EXT = 0x00008D83, - GL_ALPHA32I_EXT = 0x00008D84, - GL_INTENSITY32I_EXT = 0x00008D85, - GL_LUMINANCE32I_EXT = 0x00008D86, - GL_LUMINANCE_ALPHA32I_EXT = 0x00008D87, - GL_RGBA16I = 0x00008D88, - GL_RGBA16I_EXT = 0x00008D88, - GL_RGB16I = 0x00008D89, - GL_RGB16I_EXT = 0x00008D89, - GL_ALPHA16I_EXT = 0x00008D8A, - GL_INTENSITY16I_EXT = 0x00008D8B, - GL_LUMINANCE16I_EXT = 0x00008D8C, - GL_LUMINANCE_ALPHA16I_EXT = 0x00008D8D, - GL_RGBA8I = 0x00008D8E, - GL_RGBA8I_EXT = 0x00008D8E, - GL_RGB8I = 0x00008D8F, - GL_RGB8I_EXT = 0x00008D8F, - GL_ALPHA8I_EXT = 0x00008D90, - GL_INTENSITY8I_EXT = 0x00008D91, - GL_LUMINANCE8I_EXT = 0x00008D92, - GL_LUMINANCE_ALPHA8I_EXT = 0x00008D93, - GL_RED_INTEGER = 0x00008D94, - GL_RED_INTEGER_EXT = 0x00008D94, - GL_GREEN_INTEGER = 0x00008D95, - GL_GREEN_INTEGER_EXT = 0x00008D95, - GL_BLUE_INTEGER = 0x00008D96, - GL_BLUE_INTEGER_EXT = 0x00008D96, - GL_ALPHA_INTEGER = 0x00008D97, - GL_ALPHA_INTEGER_EXT = 0x00008D97, - GL_RGB_INTEGER = 0x00008D98, - GL_RGB_INTEGER_EXT = 0x00008D98, - GL_RGBA_INTEGER = 0x00008D99, - GL_RGBA_INTEGER_EXT = 0x00008D99, - GL_BGR_INTEGER = 0x00008D9A, - GL_BGR_INTEGER_EXT = 0x00008D9A, - GL_BGRA_INTEGER = 0x00008D9B, - GL_BGRA_INTEGER_EXT = 0x00008D9B, - GL_LUMINANCE_INTEGER_EXT = 0x00008D9C, - GL_LUMINANCE_ALPHA_INTEGER_EXT = 0x00008D9D, - GL_RGBA_INTEGER_MODE_EXT = 0x00008D9E, - GL_INT_2_10_10_10_REV = 0x00008D9F, - GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV = 0x00008DA0, - GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV = 0x00008DA1, - GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV = 0x00008DA2, - GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV = 0x00008DA3, - GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV = 0x00008DA4, - GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV = 0x00008DA5, - GL_MAX_PROGRAM_GENERIC_RESULTS_NV = 0x00008DA6, - GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 0x00008DA7, - GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB = 0x00008DA7, - GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT = 0x00008DA7, - GL_FRAMEBUFFER_ATTACHMENT_LAYERED_OES = 0x00008DA7, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 0x00008DA8, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB = 0x00008DA8, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT = 0x00008DA8, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_OES = 0x00008DA8, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB = 0x00008DA9, - GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT = 0x00008DA9, - GL_LAYER_NV = 0x00008DAA, - GL_DEPTH_COMPONENT32F_NV = 0x00008DAB, - GL_DEPTH32F_STENCIL8_NV = 0x00008DAC, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x00008DAD, - GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV = 0x00008DAD, - GL_SHADER_INCLUDE_ARB = 0x00008DAE, - GL_DEPTH_BUFFER_FLOAT_MODE_NV = 0x00008DAF, - GL_FRAMEBUFFER_SRGB = 0x00008DB9, - GL_FRAMEBUFFER_SRGB_EXT = 0x00008DB9, - GL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x00008DBA, - GL_COMPRESSED_RED_RGTC1 = 0x00008DBB, - GL_COMPRESSED_RED_RGTC1_EXT = 0x00008DBB, - GL_COMPRESSED_SIGNED_RED_RGTC1 = 0x00008DBC, - GL_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x00008DBC, - GL_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x00008DBD, - GL_COMPRESSED_RG_RGTC2 = 0x00008DBD, - GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x00008DBE, - GL_COMPRESSED_SIGNED_RG_RGTC2 = 0x00008DBE, - GL_SAMPLER_1D_ARRAY = 0x00008DC0, - GL_SAMPLER_1D_ARRAY_EXT = 0x00008DC0, - GL_SAMPLER_2D_ARRAY = 0x00008DC1, - GL_SAMPLER_2D_ARRAY_EXT = 0x00008DC1, - GL_SAMPLER_BUFFER = 0x00008DC2, - GL_SAMPLER_BUFFER_EXT = 0x00008DC2, - GL_SAMPLER_BUFFER_OES = 0x00008DC2, - GL_SAMPLER_1D_ARRAY_SHADOW = 0x00008DC3, - GL_SAMPLER_1D_ARRAY_SHADOW_EXT = 0x00008DC3, - GL_SAMPLER_2D_ARRAY_SHADOW = 0x00008DC4, - GL_SAMPLER_2D_ARRAY_SHADOW_EXT = 0x00008DC4, - GL_SAMPLER_2D_ARRAY_SHADOW_NV = 0x00008DC4, - GL_SAMPLER_CUBE_SHADOW = 0x00008DC5, - GL_SAMPLER_CUBE_SHADOW_EXT = 0x00008DC5, - GL_SAMPLER_CUBE_SHADOW_NV = 0x00008DC5, - GL_UNSIGNED_INT_VEC2 = 0x00008DC6, - GL_UNSIGNED_INT_VEC2_EXT = 0x00008DC6, - GL_UNSIGNED_INT_VEC3 = 0x00008DC7, - GL_UNSIGNED_INT_VEC3_EXT = 0x00008DC7, - GL_UNSIGNED_INT_VEC4 = 0x00008DC8, - GL_UNSIGNED_INT_VEC4_EXT = 0x00008DC8, - GL_INT_SAMPLER_1D = 0x00008DC9, - GL_INT_SAMPLER_1D_EXT = 0x00008DC9, - GL_INT_SAMPLER_2D = 0x00008DCA, - GL_INT_SAMPLER_2D_EXT = 0x00008DCA, - GL_INT_SAMPLER_3D = 0x00008DCB, - GL_INT_SAMPLER_3D_EXT = 0x00008DCB, - GL_INT_SAMPLER_CUBE = 0x00008DCC, - GL_INT_SAMPLER_CUBE_EXT = 0x00008DCC, - GL_INT_SAMPLER_2D_RECT = 0x00008DCD, - GL_INT_SAMPLER_2D_RECT_EXT = 0x00008DCD, - GL_INT_SAMPLER_1D_ARRAY = 0x00008DCE, - GL_INT_SAMPLER_1D_ARRAY_EXT = 0x00008DCE, - GL_INT_SAMPLER_2D_ARRAY = 0x00008DCF, - GL_INT_SAMPLER_2D_ARRAY_EXT = 0x00008DCF, - GL_INT_SAMPLER_BUFFER = 0x00008DD0, - GL_INT_SAMPLER_BUFFER_EXT = 0x00008DD0, - GL_INT_SAMPLER_BUFFER_OES = 0x00008DD0, - GL_UNSIGNED_INT_SAMPLER_1D = 0x00008DD1, - GL_UNSIGNED_INT_SAMPLER_1D_EXT = 0x00008DD1, - GL_UNSIGNED_INT_SAMPLER_2D = 0x00008DD2, - GL_UNSIGNED_INT_SAMPLER_2D_EXT = 0x00008DD2, - GL_UNSIGNED_INT_SAMPLER_3D = 0x00008DD3, - GL_UNSIGNED_INT_SAMPLER_3D_EXT = 0x00008DD3, - GL_UNSIGNED_INT_SAMPLER_CUBE = 0x00008DD4, - GL_UNSIGNED_INT_SAMPLER_CUBE_EXT = 0x00008DD4, - GL_UNSIGNED_INT_SAMPLER_2D_RECT = 0x00008DD5, - GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT = 0x00008DD5, - GL_UNSIGNED_INT_SAMPLER_1D_ARRAY = 0x00008DD6, - GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT = 0x00008DD6, - GL_UNSIGNED_INT_SAMPLER_2D_ARRAY = 0x00008DD7, - GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT = 0x00008DD7, - GL_UNSIGNED_INT_SAMPLER_BUFFER = 0x00008DD8, - GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT = 0x00008DD8, - GL_UNSIGNED_INT_SAMPLER_BUFFER_OES = 0x00008DD8, - GL_GEOMETRY_SHADER = 0x00008DD9, - GL_GEOMETRY_SHADER_ARB = 0x00008DD9, - GL_GEOMETRY_SHADER_EXT = 0x00008DD9, - GL_GEOMETRY_SHADER_OES = 0x00008DD9, - GL_GEOMETRY_VERTICES_OUT_ARB = 0x00008DDA, - GL_GEOMETRY_VERTICES_OUT_EXT = 0x00008DDA, - GL_GEOMETRY_INPUT_TYPE_ARB = 0x00008DDB, - GL_GEOMETRY_INPUT_TYPE_EXT = 0x00008DDB, - GL_GEOMETRY_OUTPUT_TYPE_ARB = 0x00008DDC, - GL_GEOMETRY_OUTPUT_TYPE_EXT = 0x00008DDC, - GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB = 0x00008DDD, - GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT = 0x00008DDD, - GL_MAX_VERTEX_VARYING_COMPONENTS_ARB = 0x00008DDE, - GL_MAX_VERTEX_VARYING_COMPONENTS_EXT = 0x00008DDE, - GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 0x00008DDF, - GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB = 0x00008DDF, - GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT = 0x00008DDF, - GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_OES = 0x00008DDF, - GL_MAX_GEOMETRY_OUTPUT_VERTICES = 0x00008DE0, - GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB = 0x00008DE0, - GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT = 0x00008DE0, - GL_MAX_GEOMETRY_OUTPUT_VERTICES_OES = 0x00008DE0, - GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 0x00008DE1, - GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB = 0x00008DE1, - GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT = 0x00008DE1, - GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_OES = 0x00008DE1, - GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT = 0x00008DE2, - GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT = 0x00008DE3, - GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT = 0x00008DE4, - GL_ACTIVE_SUBROUTINES = 0x00008DE5, - GL_ACTIVE_SUBROUTINE_UNIFORMS = 0x00008DE6, - GL_MAX_SUBROUTINES = 0x00008DE7, - GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS = 0x00008DE8, - GL_NAMED_STRING_LENGTH_ARB = 0x00008DE9, - GL_NAMED_STRING_TYPE_ARB = 0x00008DEA, - GL_MAX_BINDABLE_UNIFORM_SIZE_EXT = 0x00008DED, - GL_UNIFORM_BUFFER_EXT = 0x00008DEE, - GL_UNIFORM_BUFFER_BINDING_EXT = 0x00008DEF, - GL_LOW_FLOAT = 0x00008DF0, - GL_MEDIUM_FLOAT = 0x00008DF1, - GL_HIGH_FLOAT = 0x00008DF2, - GL_LOW_INT = 0x00008DF3, - GL_MEDIUM_INT = 0x00008DF4, - GL_HIGH_INT = 0x00008DF5, - GL_UNSIGNED_INT_10_10_10_2_OES = 0x00008DF6, - GL_INT_10_10_10_2_OES = 0x00008DF7, - GL_SHADER_BINARY_FORMATS = 0x00008DF8, - GL_NUM_SHADER_BINARY_FORMATS = 0x00008DF9, - GL_SHADER_COMPILER = 0x00008DFA, - GL_MAX_VERTEX_UNIFORM_VECTORS = 0x00008DFB, - GL_MAX_VARYING_VECTORS = 0x00008DFC, - GL_MAX_FRAGMENT_UNIFORM_VECTORS = 0x00008DFD, - GL_RENDERBUFFER_COLOR_SAMPLES_NV = 0x00008E10, - GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV = 0x00008E11, - GL_MULTISAMPLE_COVERAGE_MODES_NV = 0x00008E12, - GL_QUERY_WAIT = 0x00008E13, - GL_QUERY_WAIT_NV = 0x00008E13, - GL_QUERY_NO_WAIT = 0x00008E14, - GL_QUERY_NO_WAIT_NV = 0x00008E14, - GL_QUERY_BY_REGION_WAIT = 0x00008E15, - GL_QUERY_BY_REGION_WAIT_NV = 0x00008E15, - GL_QUERY_BY_REGION_NO_WAIT = 0x00008E16, - GL_QUERY_BY_REGION_NO_WAIT_NV = 0x00008E16, - GL_QUERY_WAIT_INVERTED = 0x00008E17, - GL_QUERY_NO_WAIT_INVERTED = 0x00008E18, - GL_QUERY_BY_REGION_WAIT_INVERTED = 0x00008E19, - GL_QUERY_BY_REGION_NO_WAIT_INVERTED = 0x00008E1A, - GL_POLYGON_OFFSET_CLAMP_EXT = 0x00008E1B, - GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 0x00008E1E, - GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_EXT = 0x00008E1E, - GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS_OES = 0x00008E1E, - GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x00008E1F, - GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT = 0x00008E1F, - GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS_OES = 0x00008E1F, - GL_COLOR_SAMPLES_NV = 0x00008E20, - GL_TRANSFORM_FEEDBACK = 0x00008E22, - GL_TRANSFORM_FEEDBACK_NV = 0x00008E22, - GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED = 0x00008E23, - GL_TRANSFORM_FEEDBACK_PAUSED = 0x00008E23, - GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV = 0x00008E23, - GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE = 0x00008E24, - GL_TRANSFORM_FEEDBACK_ACTIVE = 0x00008E24, - GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV = 0x00008E24, - GL_TRANSFORM_FEEDBACK_BINDING = 0x00008E25, - GL_TRANSFORM_FEEDBACK_BINDING_NV = 0x00008E25, - GL_FRAME_NV = 0x00008E26, - GL_FIELDS_NV = 0x00008E27, - GL_CURRENT_TIME_NV = 0x00008E28, - GL_TIMESTAMP = 0x00008E28, - GL_TIMESTAMP_EXT = 0x00008E28, - GL_NUM_FILL_STREAMS_NV = 0x00008E29, - GL_PRESENT_TIME_NV = 0x00008E2A, - GL_PRESENT_DURATION_NV = 0x00008E2B, - GL_DEPTH_COMPONENT16_NONLINEAR_NV = 0x00008E2C, - GL_PROGRAM_MATRIX_EXT = 0x00008E2D, - GL_TRANSPOSE_PROGRAM_MATRIX_EXT = 0x00008E2E, - GL_PROGRAM_MATRIX_STACK_DEPTH_EXT = 0x00008E2F, - GL_TEXTURE_SWIZZLE_R = 0x00008E42, - GL_TEXTURE_SWIZZLE_R_EXT = 0x00008E42, - GL_TEXTURE_SWIZZLE_G = 0x00008E43, - GL_TEXTURE_SWIZZLE_G_EXT = 0x00008E43, - GL_TEXTURE_SWIZZLE_B = 0x00008E44, - GL_TEXTURE_SWIZZLE_B_EXT = 0x00008E44, - GL_TEXTURE_SWIZZLE_A = 0x00008E45, - GL_TEXTURE_SWIZZLE_A_EXT = 0x00008E45, - GL_TEXTURE_SWIZZLE_RGBA = 0x00008E46, - GL_TEXTURE_SWIZZLE_RGBA_EXT = 0x00008E46, - GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS = 0x00008E47, - GL_ACTIVE_SUBROUTINE_MAX_LENGTH = 0x00008E48, - GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH = 0x00008E49, - GL_NUM_COMPATIBLE_SUBROUTINES = 0x00008E4A, - GL_COMPATIBLE_SUBROUTINES = 0x00008E4B, - GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION = 0x00008E4C, - GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT = 0x00008E4C, - GL_FIRST_VERTEX_CONVENTION = 0x00008E4D, - GL_FIRST_VERTEX_CONVENTION_EXT = 0x00008E4D, - GL_FIRST_VERTEX_CONVENTION_OES = 0x00008E4D, - GL_LAST_VERTEX_CONVENTION = 0x00008E4E, - GL_LAST_VERTEX_CONVENTION_EXT = 0x00008E4E, - GL_LAST_VERTEX_CONVENTION_OES = 0x00008E4E, - GL_PROVOKING_VERTEX = 0x00008E4F, - GL_PROVOKING_VERTEX_EXT = 0x00008E4F, - GL_SAMPLE_POSITION = 0x00008E50, - GL_SAMPLE_POSITION_NV = 0x00008E50, - GL_SAMPLE_LOCATION_ARB = 0x00008E50, - GL_SAMPLE_LOCATION_NV = 0x00008E50, - GL_SAMPLE_MASK = 0x00008E51, - GL_SAMPLE_MASK_NV = 0x00008E51, - GL_SAMPLE_MASK_VALUE = 0x00008E52, - GL_SAMPLE_MASK_VALUE_NV = 0x00008E52, - GL_TEXTURE_BINDING_RENDERBUFFER_NV = 0x00008E53, - GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV = 0x00008E54, - GL_TEXTURE_RENDERBUFFER_NV = 0x00008E55, - GL_SAMPLER_RENDERBUFFER_NV = 0x00008E56, - GL_INT_SAMPLER_RENDERBUFFER_NV = 0x00008E57, - GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV = 0x00008E58, - GL_MAX_SAMPLE_MASK_WORDS = 0x00008E59, - GL_MAX_SAMPLE_MASK_WORDS_NV = 0x00008E59, - GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV = 0x00008E5A, - GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 0x00008E5A, - GL_MAX_GEOMETRY_SHADER_INVOCATIONS_EXT = 0x00008E5A, - GL_MAX_GEOMETRY_SHADER_INVOCATIONS_OES = 0x00008E5A, - GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 0x00008E5B, - GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES = 0x00008E5B, - GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV = 0x00008E5B, - GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 0x00008E5C, - GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES = 0x00008E5C, - GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV = 0x00008E5C, - GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 0x00008E5D, - GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES = 0x00008E5D, - GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV = 0x00008E5D, - GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET = 0x00008E5E, - GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB = 0x00008E5E, - GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV = 0x00008E5E, - GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET = 0x00008E5F, - GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB = 0x00008E5F, - GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV = 0x00008E5F, - GL_MAX_TRANSFORM_FEEDBACK_BUFFERS = 0x00008E70, - GL_MAX_VERTEX_STREAMS = 0x00008E71, - GL_PATCH_VERTICES = 0x00008E72, - GL_PATCH_VERTICES_EXT = 0x00008E72, - GL_PATCH_VERTICES_OES = 0x00008E72, - GL_PATCH_DEFAULT_INNER_LEVEL = 0x00008E73, - GL_PATCH_DEFAULT_INNER_LEVEL_EXT = 0x00008E73, - GL_PATCH_DEFAULT_OUTER_LEVEL = 0x00008E74, - GL_PATCH_DEFAULT_OUTER_LEVEL_EXT = 0x00008E74, - GL_TESS_CONTROL_OUTPUT_VERTICES = 0x00008E75, - GL_TESS_CONTROL_OUTPUT_VERTICES_EXT = 0x00008E75, - GL_TESS_CONTROL_OUTPUT_VERTICES_OES = 0x00008E75, - GL_TESS_GEN_MODE = 0x00008E76, - GL_TESS_GEN_MODE_EXT = 0x00008E76, - GL_TESS_GEN_MODE_OES = 0x00008E76, - GL_TESS_GEN_SPACING = 0x00008E77, - GL_TESS_GEN_SPACING_EXT = 0x00008E77, - GL_TESS_GEN_SPACING_OES = 0x00008E77, - GL_TESS_GEN_VERTEX_ORDER = 0x00008E78, - GL_TESS_GEN_VERTEX_ORDER_EXT = 0x00008E78, - GL_TESS_GEN_VERTEX_ORDER_OES = 0x00008E78, - GL_TESS_GEN_POINT_MODE = 0x00008E79, - GL_TESS_GEN_POINT_MODE_EXT = 0x00008E79, - GL_TESS_GEN_POINT_MODE_OES = 0x00008E79, - GL_ISOLINES = 0x00008E7A, - GL_ISOLINES_EXT = 0x00008E7A, - GL_ISOLINES_OES = 0x00008E7A, - GL_FRACTIONAL_ODD = 0x00008E7B, - GL_FRACTIONAL_ODD_EXT = 0x00008E7B, - GL_FRACTIONAL_ODD_OES = 0x00008E7B, - GL_FRACTIONAL_EVEN = 0x00008E7C, - GL_FRACTIONAL_EVEN_EXT = 0x00008E7C, - GL_FRACTIONAL_EVEN_OES = 0x00008E7C, - GL_MAX_PATCH_VERTICES = 0x00008E7D, - GL_MAX_PATCH_VERTICES_EXT = 0x00008E7D, - GL_MAX_PATCH_VERTICES_OES = 0x00008E7D, - GL_MAX_TESS_GEN_LEVEL = 0x00008E7E, - GL_MAX_TESS_GEN_LEVEL_EXT = 0x00008E7E, - GL_MAX_TESS_GEN_LEVEL_OES = 0x00008E7E, - GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 0x00008E7F, - GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_EXT = 0x00008E7F, - GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS_OES = 0x00008E7F, - GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x00008E80, - GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_EXT = 0x00008E80, - GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS_OES = 0x00008E80, - GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 0x00008E81, - GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_EXT = 0x00008E81, - GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS_OES = 0x00008E81, - GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 0x00008E82, - GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_EXT = 0x00008E82, - GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS_OES = 0x00008E82, - GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 0x00008E83, - GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_EXT = 0x00008E83, - GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS_OES = 0x00008E83, - GL_MAX_TESS_PATCH_COMPONENTS = 0x00008E84, - GL_MAX_TESS_PATCH_COMPONENTS_EXT = 0x00008E84, - GL_MAX_TESS_PATCH_COMPONENTS_OES = 0x00008E84, - GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 0x00008E85, - GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_EXT = 0x00008E85, - GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS_OES = 0x00008E85, - GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 0x00008E86, - GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_EXT = 0x00008E86, - GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS_OES = 0x00008E86, - GL_TESS_EVALUATION_SHADER = 0x00008E87, - GL_TESS_EVALUATION_SHADER_EXT = 0x00008E87, - GL_TESS_EVALUATION_SHADER_OES = 0x00008E87, - GL_TESS_CONTROL_SHADER = 0x00008E88, - GL_TESS_CONTROL_SHADER_EXT = 0x00008E88, - GL_TESS_CONTROL_SHADER_OES = 0x00008E88, - GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 0x00008E89, - GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_EXT = 0x00008E89, - GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS_OES = 0x00008E89, - GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 0x00008E8A, - GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_EXT = 0x00008E8A, - GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS_OES = 0x00008E8A, - GL_COMPRESSED_RGBA_BPTC_UNORM = 0x00008E8C, - GL_COMPRESSED_RGBA_BPTC_UNORM_ARB = 0x00008E8C, - GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x00008E8D, - GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB = 0x00008E8D, - GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x00008E8E, - GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB = 0x00008E8E, - GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x00008E8F, - GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB = 0x00008E8F, - GL_COVERAGE_COMPONENT_NV = 0x00008ED0, - GL_COVERAGE_COMPONENT4_NV = 0x00008ED1, - GL_COVERAGE_ATTACHMENT_NV = 0x00008ED2, - GL_COVERAGE_BUFFERS_NV = 0x00008ED3, - GL_COVERAGE_SAMPLES_NV = 0x00008ED4, - GL_COVERAGE_ALL_FRAGMENTS_NV = 0x00008ED5, - GL_COVERAGE_EDGE_FRAGMENTS_NV = 0x00008ED6, - GL_COVERAGE_AUTOMATIC_NV = 0x00008ED7, - GL_BUFFER_GPU_ADDRESS_NV = 0x00008F1D, - GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV = 0x00008F1E, - GL_ELEMENT_ARRAY_UNIFIED_NV = 0x00008F1F, - GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV = 0x00008F20, - GL_VERTEX_ARRAY_ADDRESS_NV = 0x00008F21, - GL_NORMAL_ARRAY_ADDRESS_NV = 0x00008F22, - GL_COLOR_ARRAY_ADDRESS_NV = 0x00008F23, - GL_INDEX_ARRAY_ADDRESS_NV = 0x00008F24, - GL_TEXTURE_COORD_ARRAY_ADDRESS_NV = 0x00008F25, - GL_EDGE_FLAG_ARRAY_ADDRESS_NV = 0x00008F26, - GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV = 0x00008F27, - GL_FOG_COORD_ARRAY_ADDRESS_NV = 0x00008F28, - GL_ELEMENT_ARRAY_ADDRESS_NV = 0x00008F29, - GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV = 0x00008F2A, - GL_VERTEX_ARRAY_LENGTH_NV = 0x00008F2B, - GL_NORMAL_ARRAY_LENGTH_NV = 0x00008F2C, - GL_COLOR_ARRAY_LENGTH_NV = 0x00008F2D, - GL_INDEX_ARRAY_LENGTH_NV = 0x00008F2E, - GL_TEXTURE_COORD_ARRAY_LENGTH_NV = 0x00008F2F, - GL_EDGE_FLAG_ARRAY_LENGTH_NV = 0x00008F30, - GL_SECONDARY_COLOR_ARRAY_LENGTH_NV = 0x00008F31, - GL_FOG_COORD_ARRAY_LENGTH_NV = 0x00008F32, - GL_ELEMENT_ARRAY_LENGTH_NV = 0x00008F33, - GL_GPU_ADDRESS_NV = 0x00008F34, - GL_MAX_SHADER_BUFFER_ADDRESS_NV = 0x00008F35, - GL_COPY_READ_BUFFER = 0x00008F36, - GL_COPY_READ_BUFFER_NV = 0x00008F36, - GL_COPY_READ_BUFFER_BINDING = 0x00008F36, - GL_COPY_WRITE_BUFFER = 0x00008F37, - GL_COPY_WRITE_BUFFER_NV = 0x00008F37, - GL_COPY_WRITE_BUFFER_BINDING = 0x00008F37, - GL_MAX_IMAGE_UNITS = 0x00008F38, - GL_MAX_IMAGE_UNITS_EXT = 0x00008F38, - GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS = 0x00008F39, - GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT = 0x00008F39, - GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES = 0x00008F39, - GL_IMAGE_BINDING_NAME = 0x00008F3A, - GL_IMAGE_BINDING_NAME_EXT = 0x00008F3A, - GL_IMAGE_BINDING_LEVEL = 0x00008F3B, - GL_IMAGE_BINDING_LEVEL_EXT = 0x00008F3B, - GL_IMAGE_BINDING_LAYERED = 0x00008F3C, - GL_IMAGE_BINDING_LAYERED_EXT = 0x00008F3C, - GL_IMAGE_BINDING_LAYER = 0x00008F3D, - GL_IMAGE_BINDING_LAYER_EXT = 0x00008F3D, - GL_IMAGE_BINDING_ACCESS = 0x00008F3E, - GL_IMAGE_BINDING_ACCESS_EXT = 0x00008F3E, - GL_DRAW_INDIRECT_BUFFER = 0x00008F3F, - GL_DRAW_INDIRECT_UNIFIED_NV = 0x00008F40, - GL_DRAW_INDIRECT_ADDRESS_NV = 0x00008F41, - GL_DRAW_INDIRECT_LENGTH_NV = 0x00008F42, - GL_DRAW_INDIRECT_BUFFER_BINDING = 0x00008F43, - GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV = 0x00008F44, - GL_MAX_PROGRAM_SUBROUTINE_NUM_NV = 0x00008F45, - GL_DOUBLE_MAT2 = 0x00008F46, - GL_DOUBLE_MAT2_EXT = 0x00008F46, - GL_DOUBLE_MAT3 = 0x00008F47, - GL_DOUBLE_MAT3_EXT = 0x00008F47, - GL_DOUBLE_MAT4 = 0x00008F48, - GL_DOUBLE_MAT4_EXT = 0x00008F48, - GL_DOUBLE_MAT2x3 = 0x00008F49, - GL_DOUBLE_MAT2x3_EXT = 0x00008F49, - GL_DOUBLE_MAT2x4 = 0x00008F4A, - GL_DOUBLE_MAT2x4_EXT = 0x00008F4A, - GL_DOUBLE_MAT3x2 = 0x00008F4B, - GL_DOUBLE_MAT3x2_EXT = 0x00008F4B, - GL_DOUBLE_MAT3x4 = 0x00008F4C, - GL_DOUBLE_MAT3x4_EXT = 0x00008F4C, - GL_DOUBLE_MAT4x2 = 0x00008F4D, - GL_DOUBLE_MAT4x2_EXT = 0x00008F4D, - GL_DOUBLE_MAT4x3 = 0x00008F4E, - GL_DOUBLE_MAT4x3_EXT = 0x00008F4E, - GL_VERTEX_BINDING_BUFFER = 0x00008F4F, - GL_MALI_SHADER_BINARY_ARM = 0x00008F60, - GL_MALI_PROGRAM_BINARY_ARM = 0x00008F61, - GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT = 0x00008F63, - GL_SHADER_PIXEL_LOCAL_STORAGE_EXT = 0x00008F64, - GL_FETCH_PER_SAMPLE_ARM = 0x00008F65, - GL_FRAGMENT_SHADER_FRAMEBUFFER_FETCH_MRT_ARM = 0x00008F66, - GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_SIZE_EXT = 0x00008F67, - GL_RED_SNORM = 0x00008F90, - GL_RG_SNORM = 0x00008F91, - GL_RGB_SNORM = 0x00008F92, - GL_RGBA_SNORM = 0x00008F93, - GL_R8_SNORM = 0x00008F94, - GL_RG8_SNORM = 0x00008F95, - GL_RGB8_SNORM = 0x00008F96, - GL_RGBA8_SNORM = 0x00008F97, - GL_R16_SNORM = 0x00008F98, - GL_R16_SNORM_EXT = 0x00008F98, - GL_RG16_SNORM = 0x00008F99, - GL_RG16_SNORM_EXT = 0x00008F99, - GL_RGB16_SNORM = 0x00008F9A, - GL_RGB16_SNORM_EXT = 0x00008F9A, - GL_RGBA16_SNORM = 0x00008F9B, - GL_RGBA16_SNORM_EXT = 0x00008F9B, - GL_SIGNED_NORMALIZED = 0x00008F9C, - GL_PRIMITIVE_RESTART = 0x00008F9D, - GL_PRIMITIVE_RESTART_INDEX = 0x00008F9E, - GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB = 0x00008F9F, - GL_PERFMON_GLOBAL_MODE_QCOM = 0x00008FA0, - GL_BINNING_CONTROL_HINT_QCOM = 0x00008FB0, - GL_CPU_OPTIMIZED_QCOM = 0x00008FB1, - GL_GPU_OPTIMIZED_QCOM = 0x00008FB2, - GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM = 0x00008FB3, - GL_GPU_DISJOINT_EXT = 0x00008FBB, - GL_SR8_EXT = 0x00008FBD, - GL_SRG8_EXT = 0x00008FBE, - GL_SHADER_BINARY_VIV = 0x00008FC4, - GL_INT8_NV = 0x00008FE0, - GL_INT8_VEC2_NV = 0x00008FE1, - GL_INT8_VEC3_NV = 0x00008FE2, - GL_INT8_VEC4_NV = 0x00008FE3, - GL_INT16_NV = 0x00008FE4, - GL_INT16_VEC2_NV = 0x00008FE5, - GL_INT16_VEC3_NV = 0x00008FE6, - GL_INT16_VEC4_NV = 0x00008FE7, - GL_INT64_VEC2_ARB = 0x00008FE9, - GL_INT64_VEC2_NV = 0x00008FE9, - GL_INT64_VEC3_ARB = 0x00008FEA, - GL_INT64_VEC3_NV = 0x00008FEA, - GL_INT64_VEC4_ARB = 0x00008FEB, - GL_INT64_VEC4_NV = 0x00008FEB, - GL_UNSIGNED_INT8_NV = 0x00008FEC, - GL_UNSIGNED_INT8_VEC2_NV = 0x00008FED, - GL_UNSIGNED_INT8_VEC3_NV = 0x00008FEE, - GL_UNSIGNED_INT8_VEC4_NV = 0x00008FEF, - GL_UNSIGNED_INT16_NV = 0x00008FF0, - GL_UNSIGNED_INT16_VEC2_NV = 0x00008FF1, - GL_UNSIGNED_INT16_VEC3_NV = 0x00008FF2, - GL_UNSIGNED_INT16_VEC4_NV = 0x00008FF3, - GL_UNSIGNED_INT64_VEC2_ARB = 0x00008FF5, - GL_UNSIGNED_INT64_VEC2_NV = 0x00008FF5, - GL_UNSIGNED_INT64_VEC3_ARB = 0x00008FF6, - GL_UNSIGNED_INT64_VEC3_NV = 0x00008FF6, - GL_UNSIGNED_INT64_VEC4_ARB = 0x00008FF7, - GL_UNSIGNED_INT64_VEC4_NV = 0x00008FF7, - GL_FLOAT16_NV = 0x00008FF8, - GL_FLOAT16_VEC2_NV = 0x00008FF9, - GL_FLOAT16_VEC3_NV = 0x00008FFA, - GL_FLOAT16_VEC4_NV = 0x00008FFB, - GL_DOUBLE_VEC2 = 0x00008FFC, - GL_DOUBLE_VEC2_EXT = 0x00008FFC, - GL_DOUBLE_VEC3 = 0x00008FFD, - GL_DOUBLE_VEC3_EXT = 0x00008FFD, - GL_DOUBLE_VEC4 = 0x00008FFE, - GL_DOUBLE_VEC4_EXT = 0x00008FFE, - GL_SAMPLER_BUFFER_AMD = 0x00009001, - GL_INT_SAMPLER_BUFFER_AMD = 0x00009002, - GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD = 0x00009003, - GL_TESSELLATION_MODE_AMD = 0x00009004, - GL_TESSELLATION_FACTOR_AMD = 0x00009005, - GL_DISCRETE_AMD = 0x00009006, - GL_CONTINUOUS_AMD = 0x00009007, - GL_TEXTURE_CUBE_MAP_ARRAY = 0x00009009, - GL_TEXTURE_CUBE_MAP_ARRAY_ARB = 0x00009009, - GL_TEXTURE_CUBE_MAP_ARRAY_EXT = 0x00009009, - GL_TEXTURE_CUBE_MAP_ARRAY_OES = 0x00009009, - GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 0x0000900A, - GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB = 0x0000900A, - GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_EXT = 0x0000900A, - GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_OES = 0x0000900A, - GL_PROXY_TEXTURE_CUBE_MAP_ARRAY = 0x0000900B, - GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB = 0x0000900B, - GL_SAMPLER_CUBE_MAP_ARRAY = 0x0000900C, - GL_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x0000900C, - GL_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x0000900C, - GL_SAMPLER_CUBE_MAP_ARRAY_OES = 0x0000900C, - GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 0x0000900D, - GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB = 0x0000900D, - GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_EXT = 0x0000900D, - GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_OES = 0x0000900D, - GL_INT_SAMPLER_CUBE_MAP_ARRAY = 0x0000900E, - GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x0000900E, - GL_INT_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x0000900E, - GL_INT_SAMPLER_CUBE_MAP_ARRAY_OES = 0x0000900E, - GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 0x0000900F, - GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB = 0x0000900F, - GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_EXT = 0x0000900F, - GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_OES = 0x0000900F, - GL_ALPHA_SNORM = 0x00009010, - GL_LUMINANCE_SNORM = 0x00009011, - GL_LUMINANCE_ALPHA_SNORM = 0x00009012, - GL_INTENSITY_SNORM = 0x00009013, - GL_ALPHA8_SNORM = 0x00009014, - GL_LUMINANCE8_SNORM = 0x00009015, - GL_LUMINANCE8_ALPHA8_SNORM = 0x00009016, - GL_INTENSITY8_SNORM = 0x00009017, - GL_ALPHA16_SNORM = 0x00009018, - GL_LUMINANCE16_SNORM = 0x00009019, - GL_LUMINANCE16_ALPHA16_SNORM = 0x0000901A, - GL_INTENSITY16_SNORM = 0x0000901B, - GL_FACTOR_MIN_AMD = 0x0000901C, - GL_FACTOR_MAX_AMD = 0x0000901D, - GL_DEPTH_CLAMP_NEAR_AMD = 0x0000901E, - GL_DEPTH_CLAMP_FAR_AMD = 0x0000901F, - GL_VIDEO_BUFFER_NV = 0x00009020, - GL_VIDEO_BUFFER_BINDING_NV = 0x00009021, - GL_FIELD_UPPER_NV = 0x00009022, - GL_FIELD_LOWER_NV = 0x00009023, - GL_NUM_VIDEO_CAPTURE_STREAMS_NV = 0x00009024, - GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV = 0x00009025, - GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV = 0x00009026, - GL_LAST_VIDEO_CAPTURE_STATUS_NV = 0x00009027, - GL_VIDEO_BUFFER_PITCH_NV = 0x00009028, - GL_VIDEO_COLOR_CONVERSION_MATRIX_NV = 0x00009029, - GL_VIDEO_COLOR_CONVERSION_MAX_NV = 0x0000902A, - GL_VIDEO_COLOR_CONVERSION_MIN_NV = 0x0000902B, - GL_VIDEO_COLOR_CONVERSION_OFFSET_NV = 0x0000902C, - GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV = 0x0000902D, - GL_PARTIAL_SUCCESS_NV = 0x0000902E, - GL_SUCCESS_NV = 0x0000902F, - GL_FAILURE_NV = 0x00009030, - GL_YCBYCR8_422_NV = 0x00009031, - GL_YCBAYCR8A_4224_NV = 0x00009032, - GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV = 0x00009033, - GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV = 0x00009034, - GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV = 0x00009035, - GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV = 0x00009036, - GL_Z4Y12Z4CB12Z4CR12_444_NV = 0x00009037, - GL_VIDEO_CAPTURE_FRAME_WIDTH_NV = 0x00009038, - GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV = 0x00009039, - GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV = 0x0000903A, - GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV = 0x0000903B, - GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV = 0x0000903C, - GL_TEXTURE_COVERAGE_SAMPLES_NV = 0x00009045, - GL_TEXTURE_COLOR_SAMPLES_NV = 0x00009046, - GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX = 0x00009047, - GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x00009048, - GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x00009049, - GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x0000904A, - GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x0000904B, - GL_IMAGE_1D = 0x0000904C, - GL_IMAGE_1D_EXT = 0x0000904C, - GL_IMAGE_2D = 0x0000904D, - GL_IMAGE_2D_EXT = 0x0000904D, - GL_IMAGE_3D = 0x0000904E, - GL_IMAGE_3D_EXT = 0x0000904E, - GL_IMAGE_2D_RECT = 0x0000904F, - GL_IMAGE_2D_RECT_EXT = 0x0000904F, - GL_IMAGE_CUBE = 0x00009050, - GL_IMAGE_CUBE_EXT = 0x00009050, - GL_IMAGE_BUFFER = 0x00009051, - GL_IMAGE_BUFFER_EXT = 0x00009051, - GL_IMAGE_BUFFER_OES = 0x00009051, - GL_IMAGE_1D_ARRAY = 0x00009052, - GL_IMAGE_1D_ARRAY_EXT = 0x00009052, - GL_IMAGE_2D_ARRAY = 0x00009053, - GL_IMAGE_2D_ARRAY_EXT = 0x00009053, - GL_IMAGE_CUBE_MAP_ARRAY = 0x00009054, - GL_IMAGE_CUBE_MAP_ARRAY_EXT = 0x00009054, - GL_IMAGE_CUBE_MAP_ARRAY_OES = 0x00009054, - GL_IMAGE_2D_MULTISAMPLE = 0x00009055, - GL_IMAGE_2D_MULTISAMPLE_EXT = 0x00009055, - GL_IMAGE_2D_MULTISAMPLE_ARRAY = 0x00009056, - GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x00009056, - GL_INT_IMAGE_1D = 0x00009057, - GL_INT_IMAGE_1D_EXT = 0x00009057, - GL_INT_IMAGE_2D = 0x00009058, - GL_INT_IMAGE_2D_EXT = 0x00009058, - GL_INT_IMAGE_3D = 0x00009059, - GL_INT_IMAGE_3D_EXT = 0x00009059, - GL_INT_IMAGE_2D_RECT = 0x0000905A, - GL_INT_IMAGE_2D_RECT_EXT = 0x0000905A, - GL_INT_IMAGE_CUBE = 0x0000905B, - GL_INT_IMAGE_CUBE_EXT = 0x0000905B, - GL_INT_IMAGE_BUFFER = 0x0000905C, - GL_INT_IMAGE_BUFFER_EXT = 0x0000905C, - GL_INT_IMAGE_BUFFER_OES = 0x0000905C, - GL_INT_IMAGE_1D_ARRAY = 0x0000905D, - GL_INT_IMAGE_1D_ARRAY_EXT = 0x0000905D, - GL_INT_IMAGE_2D_ARRAY = 0x0000905E, - GL_INT_IMAGE_2D_ARRAY_EXT = 0x0000905E, - GL_INT_IMAGE_CUBE_MAP_ARRAY = 0x0000905F, - GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x0000905F, - GL_INT_IMAGE_CUBE_MAP_ARRAY_OES = 0x0000905F, - GL_INT_IMAGE_2D_MULTISAMPLE = 0x00009060, - GL_INT_IMAGE_2D_MULTISAMPLE_EXT = 0x00009060, - GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x00009061, - GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x00009061, - GL_UNSIGNED_INT_IMAGE_1D = 0x00009062, - GL_UNSIGNED_INT_IMAGE_1D_EXT = 0x00009062, - GL_UNSIGNED_INT_IMAGE_2D = 0x00009063, - GL_UNSIGNED_INT_IMAGE_2D_EXT = 0x00009063, - GL_UNSIGNED_INT_IMAGE_3D = 0x00009064, - GL_UNSIGNED_INT_IMAGE_3D_EXT = 0x00009064, - GL_UNSIGNED_INT_IMAGE_2D_RECT = 0x00009065, - GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT = 0x00009065, - GL_UNSIGNED_INT_IMAGE_CUBE = 0x00009066, - GL_UNSIGNED_INT_IMAGE_CUBE_EXT = 0x00009066, - GL_UNSIGNED_INT_IMAGE_BUFFER = 0x00009067, - GL_UNSIGNED_INT_IMAGE_BUFFER_EXT = 0x00009067, - GL_UNSIGNED_INT_IMAGE_BUFFER_OES = 0x00009067, - GL_UNSIGNED_INT_IMAGE_1D_ARRAY = 0x00009068, - GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT = 0x00009068, - GL_UNSIGNED_INT_IMAGE_2D_ARRAY = 0x00009069, - GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT = 0x00009069, - GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x0000906A, - GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT = 0x0000906A, - GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_OES = 0x0000906A, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE = 0x0000906B, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT = 0x0000906B, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY = 0x0000906C, - GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT = 0x0000906C, - GL_MAX_IMAGE_SAMPLES = 0x0000906D, - GL_MAX_IMAGE_SAMPLES_EXT = 0x0000906D, - GL_IMAGE_BINDING_FORMAT = 0x0000906E, - GL_IMAGE_BINDING_FORMAT_EXT = 0x0000906E, - GL_RGB10_A2UI = 0x0000906F, - GL_PATH_FORMAT_SVG_NV = 0x00009070, - GL_PATH_FORMAT_PS_NV = 0x00009071, - GL_STANDARD_FONT_NAME_NV = 0x00009072, - GL_SYSTEM_FONT_NAME_NV = 0x00009073, - GL_FILE_NAME_NV = 0x00009074, - GL_PATH_STROKE_WIDTH_NV = 0x00009075, - GL_PATH_END_CAPS_NV = 0x00009076, - GL_PATH_INITIAL_END_CAP_NV = 0x00009077, - GL_PATH_TERMINAL_END_CAP_NV = 0x00009078, - GL_PATH_JOIN_STYLE_NV = 0x00009079, - GL_PATH_MITER_LIMIT_NV = 0x0000907A, - GL_PATH_DASH_CAPS_NV = 0x0000907B, - GL_PATH_INITIAL_DASH_CAP_NV = 0x0000907C, - GL_PATH_TERMINAL_DASH_CAP_NV = 0x0000907D, - GL_PATH_DASH_OFFSET_NV = 0x0000907E, - GL_PATH_CLIENT_LENGTH_NV = 0x0000907F, - GL_PATH_FILL_MODE_NV = 0x00009080, - GL_PATH_FILL_MASK_NV = 0x00009081, - GL_PATH_FILL_COVER_MODE_NV = 0x00009082, - GL_PATH_STROKE_COVER_MODE_NV = 0x00009083, - GL_PATH_STROKE_MASK_NV = 0x00009084, - GL_COUNT_UP_NV = 0x00009088, - GL_COUNT_DOWN_NV = 0x00009089, - GL_PATH_OBJECT_BOUNDING_BOX_NV = 0x0000908A, - GL_CONVEX_HULL_NV = 0x0000908B, - GL_BOUNDING_BOX_NV = 0x0000908D, - GL_TRANSLATE_X_NV = 0x0000908E, - GL_TRANSLATE_Y_NV = 0x0000908F, - GL_TRANSLATE_2D_NV = 0x00009090, - GL_TRANSLATE_3D_NV = 0x00009091, - GL_AFFINE_2D_NV = 0x00009092, - GL_AFFINE_3D_NV = 0x00009094, - GL_TRANSPOSE_AFFINE_2D_NV = 0x00009096, - GL_TRANSPOSE_AFFINE_3D_NV = 0x00009098, - GL_UTF8_NV = 0x0000909A, - GL_UTF16_NV = 0x0000909B, - GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV = 0x0000909C, - GL_PATH_COMMAND_COUNT_NV = 0x0000909D, - GL_PATH_COORD_COUNT_NV = 0x0000909E, - GL_PATH_DASH_ARRAY_COUNT_NV = 0x0000909F, - GL_PATH_COMPUTED_LENGTH_NV = 0x000090A0, - GL_PATH_FILL_BOUNDING_BOX_NV = 0x000090A1, - GL_PATH_STROKE_BOUNDING_BOX_NV = 0x000090A2, - GL_SQUARE_NV = 0x000090A3, - GL_ROUND_NV = 0x000090A4, - GL_TRIANGULAR_NV = 0x000090A5, - GL_BEVEL_NV = 0x000090A6, - GL_MITER_REVERT_NV = 0x000090A7, - GL_MITER_TRUNCATE_NV = 0x000090A8, - GL_SKIP_MISSING_GLYPH_NV = 0x000090A9, - GL_USE_MISSING_GLYPH_NV = 0x000090AA, - GL_PATH_ERROR_POSITION_NV = 0x000090AB, - GL_PATH_FOG_GEN_MODE_NV = 0x000090AC, - GL_ACCUM_ADJACENT_PAIRS_NV = 0x000090AD, - GL_ADJACENT_PAIRS_NV = 0x000090AE, - GL_FIRST_TO_REST_NV = 0x000090AF, - GL_PATH_GEN_MODE_NV = 0x000090B0, - GL_PATH_GEN_COEFF_NV = 0x000090B1, - GL_PATH_GEN_COLOR_FORMAT_NV = 0x000090B2, - GL_PATH_GEN_COMPONENTS_NV = 0x000090B3, - GL_PATH_DASH_OFFSET_RESET_NV = 0x000090B4, - GL_MOVE_TO_RESETS_NV = 0x000090B5, - GL_MOVE_TO_CONTINUES_NV = 0x000090B6, - GL_PATH_STENCIL_FUNC_NV = 0x000090B7, - GL_PATH_STENCIL_REF_NV = 0x000090B8, - GL_PATH_STENCIL_VALUE_MASK_NV = 0x000090B9, - GL_SCALED_RESOLVE_FASTEST_EXT = 0x000090BA, - GL_SCALED_RESOLVE_NICEST_EXT = 0x000090BB, - GL_MIN_MAP_BUFFER_ALIGNMENT = 0x000090BC, - GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV = 0x000090BD, - GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV = 0x000090BE, - GL_PATH_COVER_DEPTH_FUNC_NV = 0x000090BF, - GL_IMAGE_FORMAT_COMPATIBILITY_TYPE = 0x000090C7, - GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE = 0x000090C8, - GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS = 0x000090C9, - GL_MAX_VERTEX_IMAGE_UNIFORMS = 0x000090CA, - GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 0x000090CB, - GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_EXT = 0x000090CB, - GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS_OES = 0x000090CB, - GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 0x000090CC, - GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_EXT = 0x000090CC, - GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS_OES = 0x000090CC, - GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 0x000090CD, - GL_MAX_GEOMETRY_IMAGE_UNIFORMS_EXT = 0x000090CD, - GL_MAX_GEOMETRY_IMAGE_UNIFORMS_OES = 0x000090CD, - GL_MAX_FRAGMENT_IMAGE_UNIFORMS = 0x000090CE, - GL_MAX_COMBINED_IMAGE_UNIFORMS = 0x000090CF, - GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV = 0x000090D0, - GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV = 0x000090D1, - GL_SHADER_STORAGE_BUFFER = 0x000090D2, - GL_SHADER_STORAGE_BUFFER_BINDING = 0x000090D3, - GL_SHADER_STORAGE_BUFFER_START = 0x000090D4, - GL_SHADER_STORAGE_BUFFER_SIZE = 0x000090D5, - GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS = 0x000090D6, - GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 0x000090D7, - GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_EXT = 0x000090D7, - GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS_OES = 0x000090D7, - GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 0x000090D8, - GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_EXT = 0x000090D8, - GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS_OES = 0x000090D8, - GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 0x000090D9, - GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_EXT = 0x000090D9, - GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS_OES = 0x000090D9, - GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS = 0x000090DA, - GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS = 0x000090DB, - GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS = 0x000090DC, - GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS = 0x000090DD, - GL_MAX_SHADER_STORAGE_BLOCK_SIZE = 0x000090DE, - GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT = 0x000090DF, - GL_SYNC_X11_FENCE_EXT = 0x000090E1, - GL_DEPTH_STENCIL_TEXTURE_MODE = 0x000090EA, - GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS = 0x000090EB, - GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB = 0x000090EB, - GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER = 0x000090EC, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER = 0x000090ED, - GL_DISPATCH_INDIRECT_BUFFER = 0x000090EE, - GL_DISPATCH_INDIRECT_BUFFER_BINDING = 0x000090EF, - GL_COLOR_ATTACHMENT_EXT = 0x000090F0, - GL_MULTIVIEW_EXT = 0x000090F1, - GL_MAX_MULTIVIEW_BUFFERS_EXT = 0x000090F2, - GL_CONTEXT_ROBUST_ACCESS = 0x000090F3, - GL_CONTEXT_ROBUST_ACCESS_EXT = 0x000090F3, - GL_CONTEXT_ROBUST_ACCESS_KHR = 0x000090F3, - GL_COMPUTE_PROGRAM_NV = 0x000090FB, - GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV = 0x000090FC, - GL_TEXTURE_2D_MULTISAMPLE = 0x00009100, - GL_PROXY_TEXTURE_2D_MULTISAMPLE = 0x00009101, - GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x00009102, - GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES = 0x00009102, - GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x00009103, - GL_TEXTURE_BINDING_2D_MULTISAMPLE = 0x00009104, - GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 0x00009105, - GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY_OES = 0x00009105, - GL_TEXTURE_SAMPLES = 0x00009106, - GL_TEXTURE_FIXED_SAMPLE_LOCATIONS = 0x00009107, - GL_SAMPLER_2D_MULTISAMPLE = 0x00009108, - GL_INT_SAMPLER_2D_MULTISAMPLE = 0x00009109, - GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 0x0000910A, - GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x0000910B, - GL_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x0000910B, - GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x0000910C, - GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x0000910C, - GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x0000910D, - GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY_OES = 0x0000910D, - GL_MAX_COLOR_TEXTURE_SAMPLES = 0x0000910E, - GL_MAX_DEPTH_TEXTURE_SAMPLES = 0x0000910F, - GL_MAX_INTEGER_SAMPLES = 0x00009110, - GL_MAX_SERVER_WAIT_TIMEOUT = 0x00009111, - GL_MAX_SERVER_WAIT_TIMEOUT_APPLE = 0x00009111, - GL_OBJECT_TYPE = 0x00009112, - GL_OBJECT_TYPE_APPLE = 0x00009112, - GL_SYNC_CONDITION = 0x00009113, - GL_SYNC_CONDITION_APPLE = 0x00009113, - GL_SYNC_STATUS = 0x00009114, - GL_SYNC_STATUS_APPLE = 0x00009114, - GL_SYNC_FLAGS = 0x00009115, - GL_SYNC_FLAGS_APPLE = 0x00009115, - GL_SYNC_FENCE = 0x00009116, - GL_SYNC_FENCE_APPLE = 0x00009116, - GL_SYNC_GPU_COMMANDS_COMPLETE = 0x00009117, - GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE = 0x00009117, - GL_UNSIGNALED = 0x00009118, - GL_UNSIGNALED_APPLE = 0x00009118, - GL_SIGNALED = 0x00009119, - GL_SIGNALED_APPLE = 0x00009119, - GL_ALREADY_SIGNALED = 0x0000911A, - GL_ALREADY_SIGNALED_APPLE = 0x0000911A, - GL_TIMEOUT_EXPIRED = 0x0000911B, - GL_TIMEOUT_EXPIRED_APPLE = 0x0000911B, - GL_CONDITION_SATISFIED = 0x0000911C, - GL_CONDITION_SATISFIED_APPLE = 0x0000911C, - GL_WAIT_FAILED = 0x0000911D, - GL_WAIT_FAILED_APPLE = 0x0000911D, - GL_BUFFER_ACCESS_FLAGS = 0x0000911F, - GL_BUFFER_MAP_LENGTH = 0x00009120, - GL_BUFFER_MAP_OFFSET = 0x00009121, - GL_MAX_VERTEX_OUTPUT_COMPONENTS = 0x00009122, - GL_MAX_GEOMETRY_INPUT_COMPONENTS = 0x00009123, - GL_MAX_GEOMETRY_INPUT_COMPONENTS_EXT = 0x00009123, - GL_MAX_GEOMETRY_INPUT_COMPONENTS_OES = 0x00009123, - GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 0x00009124, - GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_EXT = 0x00009124, - GL_MAX_GEOMETRY_OUTPUT_COMPONENTS_OES = 0x00009124, - GL_MAX_FRAGMENT_INPUT_COMPONENTS = 0x00009125, - GL_CONTEXT_PROFILE_MASK = 0x00009126, - GL_UNPACK_COMPRESSED_BLOCK_WIDTH = 0x00009127, - GL_UNPACK_COMPRESSED_BLOCK_HEIGHT = 0x00009128, - GL_UNPACK_COMPRESSED_BLOCK_DEPTH = 0x00009129, - GL_UNPACK_COMPRESSED_BLOCK_SIZE = 0x0000912A, - GL_PACK_COMPRESSED_BLOCK_WIDTH = 0x0000912B, - GL_PACK_COMPRESSED_BLOCK_HEIGHT = 0x0000912C, - GL_PACK_COMPRESSED_BLOCK_DEPTH = 0x0000912D, - GL_PACK_COMPRESSED_BLOCK_SIZE = 0x0000912E, - GL_TEXTURE_IMMUTABLE_FORMAT = 0x0000912F, - GL_TEXTURE_IMMUTABLE_FORMAT_EXT = 0x0000912F, - GL_SGX_PROGRAM_BINARY_IMG = 0x00009130, - GL_RENDERBUFFER_SAMPLES_IMG = 0x00009133, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG = 0x00009134, - GL_MAX_SAMPLES_IMG = 0x00009135, - GL_TEXTURE_SAMPLES_IMG = 0x00009136, - GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG = 0x00009137, - GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG = 0x00009138, - GL_MAX_DEBUG_MESSAGE_LENGTH = 0x00009143, - GL_MAX_DEBUG_MESSAGE_LENGTH_AMD = 0x00009143, - GL_MAX_DEBUG_MESSAGE_LENGTH_ARB = 0x00009143, - GL_MAX_DEBUG_MESSAGE_LENGTH_KHR = 0x00009143, - GL_MAX_DEBUG_LOGGED_MESSAGES = 0x00009144, - GL_MAX_DEBUG_LOGGED_MESSAGES_AMD = 0x00009144, - GL_MAX_DEBUG_LOGGED_MESSAGES_ARB = 0x00009144, - GL_MAX_DEBUG_LOGGED_MESSAGES_KHR = 0x00009144, - GL_DEBUG_LOGGED_MESSAGES = 0x00009145, - GL_DEBUG_LOGGED_MESSAGES_AMD = 0x00009145, - GL_DEBUG_LOGGED_MESSAGES_ARB = 0x00009145, - GL_DEBUG_LOGGED_MESSAGES_KHR = 0x00009145, - GL_DEBUG_SEVERITY_HIGH = 0x00009146, - GL_DEBUG_SEVERITY_HIGH_AMD = 0x00009146, - GL_DEBUG_SEVERITY_HIGH_ARB = 0x00009146, - GL_DEBUG_SEVERITY_HIGH_KHR = 0x00009146, - GL_DEBUG_SEVERITY_MEDIUM = 0x00009147, - GL_DEBUG_SEVERITY_MEDIUM_AMD = 0x00009147, - GL_DEBUG_SEVERITY_MEDIUM_ARB = 0x00009147, - GL_DEBUG_SEVERITY_MEDIUM_KHR = 0x00009147, - GL_DEBUG_SEVERITY_LOW = 0x00009148, - GL_DEBUG_SEVERITY_LOW_AMD = 0x00009148, - GL_DEBUG_SEVERITY_LOW_ARB = 0x00009148, - GL_DEBUG_SEVERITY_LOW_KHR = 0x00009148, - GL_DEBUG_CATEGORY_API_ERROR_AMD = 0x00009149, - GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD = 0x0000914A, - GL_DEBUG_CATEGORY_DEPRECATION_AMD = 0x0000914B, - GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD = 0x0000914C, - GL_DEBUG_CATEGORY_PERFORMANCE_AMD = 0x0000914D, - GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD = 0x0000914E, - GL_DEBUG_CATEGORY_APPLICATION_AMD = 0x0000914F, - GL_DEBUG_CATEGORY_OTHER_AMD = 0x00009150, - GL_BUFFER_OBJECT_EXT = 0x00009151, - GL_DATA_BUFFER_AMD = 0x00009151, - GL_PERFORMANCE_MONITOR_AMD = 0x00009152, - GL_QUERY_OBJECT_AMD = 0x00009153, - GL_QUERY_OBJECT_EXT = 0x00009153, - GL_VERTEX_ARRAY_OBJECT_AMD = 0x00009154, - GL_VERTEX_ARRAY_OBJECT_EXT = 0x00009154, - GL_SAMPLER_OBJECT_AMD = 0x00009155, - GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD = 0x00009160, - GL_QUERY_BUFFER = 0x00009192, - GL_QUERY_BUFFER_AMD = 0x00009192, - GL_QUERY_BUFFER_BINDING = 0x00009193, - GL_QUERY_BUFFER_BINDING_AMD = 0x00009193, - GL_QUERY_RESULT_NO_WAIT = 0x00009194, - GL_QUERY_RESULT_NO_WAIT_AMD = 0x00009194, - GL_VIRTUAL_PAGE_SIZE_X_ARB = 0x00009195, - GL_VIRTUAL_PAGE_SIZE_X_EXT = 0x00009195, - GL_VIRTUAL_PAGE_SIZE_X_AMD = 0x00009195, - GL_VIRTUAL_PAGE_SIZE_Y_ARB = 0x00009196, - GL_VIRTUAL_PAGE_SIZE_Y_EXT = 0x00009196, - GL_VIRTUAL_PAGE_SIZE_Y_AMD = 0x00009196, - GL_VIRTUAL_PAGE_SIZE_Z_ARB = 0x00009197, - GL_VIRTUAL_PAGE_SIZE_Z_EXT = 0x00009197, - GL_VIRTUAL_PAGE_SIZE_Z_AMD = 0x00009197, - GL_MAX_SPARSE_TEXTURE_SIZE_ARB = 0x00009198, - GL_MAX_SPARSE_TEXTURE_SIZE_EXT = 0x00009198, - GL_MAX_SPARSE_TEXTURE_SIZE_AMD = 0x00009198, - GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB = 0x00009199, - GL_MAX_SPARSE_3D_TEXTURE_SIZE_EXT = 0x00009199, - GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD = 0x00009199, - GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS = 0x0000919A, - GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB = 0x0000919A, - GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_EXT = 0x0000919A, - GL_MIN_SPARSE_LEVEL_AMD = 0x0000919B, - GL_MIN_LOD_WARNING_AMD = 0x0000919C, - GL_TEXTURE_BUFFER_OFFSET = 0x0000919D, - GL_TEXTURE_BUFFER_OFFSET_EXT = 0x0000919D, - GL_TEXTURE_BUFFER_OFFSET_OES = 0x0000919D, - GL_TEXTURE_BUFFER_SIZE = 0x0000919E, - GL_TEXTURE_BUFFER_SIZE_EXT = 0x0000919E, - GL_TEXTURE_BUFFER_SIZE_OES = 0x0000919E, - GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 0x0000919F, - GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_EXT = 0x0000919F, - GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES = 0x0000919F, - GL_STREAM_RASTERIZATION_AMD = 0x000091A0, - GL_VERTEX_ELEMENT_SWIZZLE_AMD = 0x000091A4, - GL_VERTEX_ID_SWIZZLE_AMD = 0x000091A5, - GL_TEXTURE_SPARSE_ARB = 0x000091A6, - GL_TEXTURE_SPARSE_EXT = 0x000091A6, - GL_VIRTUAL_PAGE_SIZE_INDEX_ARB = 0x000091A7, - GL_VIRTUAL_PAGE_SIZE_INDEX_EXT = 0x000091A7, - GL_NUM_VIRTUAL_PAGE_SIZES_ARB = 0x000091A8, - GL_NUM_VIRTUAL_PAGE_SIZES_EXT = 0x000091A8, - GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB = 0x000091A9, - GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_EXT = 0x000091A9, - GL_NUM_SPARSE_LEVELS_ARB = 0x000091AA, - GL_NUM_SPARSE_LEVELS_EXT = 0x000091AA, - GL_MAX_SHADER_COMPILER_THREADS_ARB = 0x000091B0, - GL_COMPLETION_STATUS_ARB = 0x000091B1, - GL_COMPUTE_SHADER = 0x000091B9, - GL_MAX_COMPUTE_UNIFORM_BLOCKS = 0x000091BB, - GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS = 0x000091BC, - GL_MAX_COMPUTE_IMAGE_UNIFORMS = 0x000091BD, - GL_MAX_COMPUTE_WORK_GROUP_COUNT = 0x000091BE, - GL_MAX_COMPUTE_WORK_GROUP_SIZE = 0x000091BF, - GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB = 0x000091BF, - GL_UNPACK_FLIP_Y_WEBGL = 0x00009240, - GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x00009241, - GL_CONTEXT_LOST_WEBGL = 0x00009242, - GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x00009243, - GL_BROWSER_DEFAULT_WEBGL = 0x00009244, - GL_SHADER_BINARY_DMP = 0x00009250, - GL_SMAPHS30_PROGRAM_BINARY_DMP = 0x00009251, - GL_SMAPHS_PROGRAM_BINARY_DMP = 0x00009252, - GL_DMP_PROGRAM_BINARY_DMP = 0x00009253, - GL_GCCSO_SHADER_BINARY_FJ = 0x00009260, - GL_COMPRESSED_R11_EAC = 0x00009270, - GL_COMPRESSED_R11_EAC_OES = 0x00009270, - GL_COMPRESSED_SIGNED_R11_EAC = 0x00009271, - GL_COMPRESSED_SIGNED_R11_EAC_OES = 0x00009271, - GL_COMPRESSED_RG11_EAC = 0x00009272, - GL_COMPRESSED_RG11_EAC_OES = 0x00009272, - GL_COMPRESSED_SIGNED_RG11_EAC = 0x00009273, - GL_COMPRESSED_SIGNED_RG11_EAC_OES = 0x00009273, - GL_COMPRESSED_RGB8_ETC2 = 0x00009274, - GL_COMPRESSED_RGB8_ETC2_OES = 0x00009274, - GL_COMPRESSED_SRGB8_ETC2 = 0x00009275, - GL_COMPRESSED_SRGB8_ETC2_OES = 0x00009275, - GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x00009276, - GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES = 0x00009276, - GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x00009277, - GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2_OES = 0x00009277, - GL_COMPRESSED_RGBA8_ETC2_EAC = 0x00009278, - GL_COMPRESSED_RGBA8_ETC2_EAC_OES = 0x00009278, - GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x00009279, - GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC_OES = 0x00009279, - GL_BLEND_PREMULTIPLIED_SRC_NV = 0x00009280, - GL_BLEND_OVERLAP_NV = 0x00009281, - GL_UNCORRELATED_NV = 0x00009282, - GL_DISJOINT_NV = 0x00009283, - GL_CONJOINT_NV = 0x00009284, - GL_BLEND_ADVANCED_COHERENT_KHR = 0x00009285, - GL_BLEND_ADVANCED_COHERENT_NV = 0x00009285, - GL_SRC_NV = 0x00009286, - GL_DST_NV = 0x00009287, - GL_SRC_OVER_NV = 0x00009288, - GL_DST_OVER_NV = 0x00009289, - GL_SRC_IN_NV = 0x0000928A, - GL_DST_IN_NV = 0x0000928B, - GL_SRC_OUT_NV = 0x0000928C, - GL_DST_OUT_NV = 0x0000928D, - GL_SRC_ATOP_NV = 0x0000928E, - GL_DST_ATOP_NV = 0x0000928F, - GL_PLUS_NV = 0x00009291, - GL_PLUS_DARKER_NV = 0x00009292, - GL_MULTIPLY = 0x00009294, - GL_MULTIPLY_KHR = 0x00009294, - GL_MULTIPLY_NV = 0x00009294, - GL_SCREEN = 0x00009295, - GL_SCREEN_KHR = 0x00009295, - GL_SCREEN_NV = 0x00009295, - GL_OVERLAY = 0x00009296, - GL_OVERLAY_KHR = 0x00009296, - GL_OVERLAY_NV = 0x00009296, - GL_DARKEN = 0x00009297, - GL_DARKEN_KHR = 0x00009297, - GL_DARKEN_NV = 0x00009297, - GL_LIGHTEN = 0x00009298, - GL_LIGHTEN_KHR = 0x00009298, - GL_LIGHTEN_NV = 0x00009298, - GL_COLORDODGE = 0x00009299, - GL_COLORDODGE_KHR = 0x00009299, - GL_COLORDODGE_NV = 0x00009299, - GL_COLORBURN = 0x0000929A, - GL_COLORBURN_KHR = 0x0000929A, - GL_COLORBURN_NV = 0x0000929A, - GL_HARDLIGHT = 0x0000929B, - GL_HARDLIGHT_KHR = 0x0000929B, - GL_HARDLIGHT_NV = 0x0000929B, - GL_SOFTLIGHT = 0x0000929C, - GL_SOFTLIGHT_KHR = 0x0000929C, - GL_SOFTLIGHT_NV = 0x0000929C, - GL_DIFFERENCE = 0x0000929E, - GL_DIFFERENCE_KHR = 0x0000929E, - GL_DIFFERENCE_NV = 0x0000929E, - GL_MINUS_NV = 0x0000929F, - GL_EXCLUSION = 0x000092A0, - GL_EXCLUSION_KHR = 0x000092A0, - GL_EXCLUSION_NV = 0x000092A0, - GL_CONTRAST_NV = 0x000092A1, - GL_INVERT_RGB_NV = 0x000092A3, - GL_LINEARDODGE_NV = 0x000092A4, - GL_LINEARBURN_NV = 0x000092A5, - GL_VIVIDLIGHT_NV = 0x000092A6, - GL_LINEARLIGHT_NV = 0x000092A7, - GL_PINLIGHT_NV = 0x000092A8, - GL_HARDMIX_NV = 0x000092A9, - GL_HSL_HUE = 0x000092AD, - GL_HSL_HUE_KHR = 0x000092AD, - GL_HSL_HUE_NV = 0x000092AD, - GL_HSL_SATURATION = 0x000092AE, - GL_HSL_SATURATION_KHR = 0x000092AE, - GL_HSL_SATURATION_NV = 0x000092AE, - GL_HSL_COLOR = 0x000092AF, - GL_HSL_COLOR_KHR = 0x000092AF, - GL_HSL_COLOR_NV = 0x000092AF, - GL_HSL_LUMINOSITY = 0x000092B0, - GL_HSL_LUMINOSITY_KHR = 0x000092B0, - GL_HSL_LUMINOSITY_NV = 0x000092B0, - GL_PLUS_CLAMPED_NV = 0x000092B1, - GL_PLUS_CLAMPED_ALPHA_NV = 0x000092B2, - GL_MINUS_CLAMPED_NV = 0x000092B3, - GL_INVERT_OVG_NV = 0x000092B4, - GL_PRIMITIVE_BOUNDING_BOX_ARB = 0x000092BE, - GL_PRIMITIVE_BOUNDING_BOX = 0x000092BE, - GL_PRIMITIVE_BOUNDING_BOX_EXT = 0x000092BE, - GL_PRIMITIVE_BOUNDING_BOX_OES = 0x000092BE, - GL_ATOMIC_COUNTER_BUFFER = 0x000092C0, - GL_ATOMIC_COUNTER_BUFFER_BINDING = 0x000092C1, - GL_ATOMIC_COUNTER_BUFFER_START = 0x000092C2, - GL_ATOMIC_COUNTER_BUFFER_SIZE = 0x000092C3, - GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE = 0x000092C4, - GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS = 0x000092C5, - GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES = 0x000092C6, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER = 0x000092C7, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER = 0x000092C8, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x000092C9, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER = 0x000092CA, - GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER = 0x000092CB, - GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS = 0x000092CC, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 0x000092CD, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_EXT = 0x000092CD, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS_OES = 0x000092CD, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 0x000092CE, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_EXT = 0x000092CE, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS_OES = 0x000092CE, - GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 0x000092CF, - GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_EXT = 0x000092CF, - GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS_OES = 0x000092CF, - GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS = 0x000092D0, - GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS = 0x000092D1, - GL_MAX_VERTEX_ATOMIC_COUNTERS = 0x000092D2, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 0x000092D3, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_EXT = 0x000092D3, - GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS_OES = 0x000092D3, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 0x000092D4, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_EXT = 0x000092D4, - GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS_OES = 0x000092D4, - GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 0x000092D5, - GL_MAX_GEOMETRY_ATOMIC_COUNTERS_EXT = 0x000092D5, - GL_MAX_GEOMETRY_ATOMIC_COUNTERS_OES = 0x000092D5, - GL_MAX_FRAGMENT_ATOMIC_COUNTERS = 0x000092D6, - GL_MAX_COMBINED_ATOMIC_COUNTERS = 0x000092D7, - GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE = 0x000092D8, - GL_ACTIVE_ATOMIC_COUNTER_BUFFERS = 0x000092D9, - GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX = 0x000092DA, - GL_UNSIGNED_INT_ATOMIC_COUNTER = 0x000092DB, - GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS = 0x000092DC, - GL_FRAGMENT_COVERAGE_TO_COLOR_NV = 0x000092DD, - GL_FRAGMENT_COVERAGE_COLOR_NV = 0x000092DE, - GL_DEBUG_OUTPUT = 0x000092E0, - GL_DEBUG_OUTPUT_KHR = 0x000092E0, - GL_UNIFORM = 0x000092E1, - GL_UNIFORM_BLOCK = 0x000092E2, - GL_PROGRAM_INPUT = 0x000092E3, - GL_PROGRAM_OUTPUT = 0x000092E4, - GL_BUFFER_VARIABLE = 0x000092E5, - GL_SHADER_STORAGE_BLOCK = 0x000092E6, - GL_IS_PER_PATCH = 0x000092E7, - GL_IS_PER_PATCH_EXT = 0x000092E7, - GL_IS_PER_PATCH_OES = 0x000092E7, - GL_VERTEX_SUBROUTINE = 0x000092E8, - GL_TESS_CONTROL_SUBROUTINE = 0x000092E9, - GL_TESS_EVALUATION_SUBROUTINE = 0x000092EA, - GL_GEOMETRY_SUBROUTINE = 0x000092EB, - GL_FRAGMENT_SUBROUTINE = 0x000092EC, - GL_COMPUTE_SUBROUTINE = 0x000092ED, - GL_VERTEX_SUBROUTINE_UNIFORM = 0x000092EE, - GL_TESS_CONTROL_SUBROUTINE_UNIFORM = 0x000092EF, - GL_TESS_EVALUATION_SUBROUTINE_UNIFORM = 0x000092F0, - GL_GEOMETRY_SUBROUTINE_UNIFORM = 0x000092F1, - GL_FRAGMENT_SUBROUTINE_UNIFORM = 0x000092F2, - GL_COMPUTE_SUBROUTINE_UNIFORM = 0x000092F3, - GL_TRANSFORM_FEEDBACK_VARYING = 0x000092F4, - GL_ACTIVE_RESOURCES = 0x000092F5, - GL_MAX_NAME_LENGTH = 0x000092F6, - GL_MAX_NUM_ACTIVE_VARIABLES = 0x000092F7, - GL_MAX_NUM_COMPATIBLE_SUBROUTINES = 0x000092F8, - GL_NAME_LENGTH = 0x000092F9, - GL_TYPE = 0x000092FA, - GL_ARRAY_SIZE = 0x000092FB, - GL_OFFSET = 0x000092FC, - GL_BLOCK_INDEX = 0x000092FD, - GL_ARRAY_STRIDE = 0x000092FE, - GL_MATRIX_STRIDE = 0x000092FF, - GL_IS_ROW_MAJOR = 0x00009300, - GL_ATOMIC_COUNTER_BUFFER_INDEX = 0x00009301, - GL_BUFFER_BINDING = 0x00009302, - GL_BUFFER_DATA_SIZE = 0x00009303, - GL_NUM_ACTIVE_VARIABLES = 0x00009304, - GL_ACTIVE_VARIABLES = 0x00009305, - GL_REFERENCED_BY_VERTEX_SHADER = 0x00009306, - GL_REFERENCED_BY_TESS_CONTROL_SHADER = 0x00009307, - GL_REFERENCED_BY_TESS_CONTROL_SHADER_EXT = 0x00009307, - GL_REFERENCED_BY_TESS_CONTROL_SHADER_OES = 0x00009307, - GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x00009308, - GL_REFERENCED_BY_TESS_EVALUATION_SHADER_EXT = 0x00009308, - GL_REFERENCED_BY_TESS_EVALUATION_SHADER_OES = 0x00009308, - GL_REFERENCED_BY_GEOMETRY_SHADER = 0x00009309, - GL_REFERENCED_BY_GEOMETRY_SHADER_EXT = 0x00009309, - GL_REFERENCED_BY_GEOMETRY_SHADER_OES = 0x00009309, - GL_REFERENCED_BY_FRAGMENT_SHADER = 0x0000930A, - GL_REFERENCED_BY_COMPUTE_SHADER = 0x0000930B, - GL_TOP_LEVEL_ARRAY_SIZE = 0x0000930C, - GL_TOP_LEVEL_ARRAY_STRIDE = 0x0000930D, - GL_LOCATION = 0x0000930E, - GL_LOCATION_INDEX = 0x0000930F, - GL_LOCATION_INDEX_EXT = 0x0000930F, - GL_FRAMEBUFFER_DEFAULT_WIDTH = 0x00009310, - GL_FRAMEBUFFER_DEFAULT_HEIGHT = 0x00009311, - GL_FRAMEBUFFER_DEFAULT_LAYERS = 0x00009312, - GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT = 0x00009312, - GL_FRAMEBUFFER_DEFAULT_LAYERS_OES = 0x00009312, - GL_FRAMEBUFFER_DEFAULT_SAMPLES = 0x00009313, - GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 0x00009314, - GL_MAX_FRAMEBUFFER_WIDTH = 0x00009315, - GL_MAX_FRAMEBUFFER_HEIGHT = 0x00009316, - GL_MAX_FRAMEBUFFER_LAYERS = 0x00009317, - GL_MAX_FRAMEBUFFER_LAYERS_EXT = 0x00009317, - GL_MAX_FRAMEBUFFER_LAYERS_OES = 0x00009317, - GL_MAX_FRAMEBUFFER_SAMPLES = 0x00009318, - GL_RASTER_MULTISAMPLE_EXT = 0x00009327, - GL_RASTER_SAMPLES_EXT = 0x00009328, - GL_MAX_RASTER_SAMPLES_EXT = 0x00009329, - GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT = 0x0000932A, - GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT = 0x0000932B, - GL_EFFECTIVE_RASTER_SAMPLES_EXT = 0x0000932C, - GL_DEPTH_SAMPLES_NV = 0x0000932D, - GL_STENCIL_SAMPLES_NV = 0x0000932E, - GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV = 0x0000932F, - GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV = 0x00009330, - GL_COVERAGE_MODULATION_TABLE_NV = 0x00009331, - GL_COVERAGE_MODULATION_NV = 0x00009332, - GL_COVERAGE_MODULATION_TABLE_SIZE_NV = 0x00009333, - GL_WARP_SIZE_NV = 0x00009339, - GL_WARPS_PER_SM_NV = 0x0000933A, - GL_SM_COUNT_NV = 0x0000933B, - GL_FILL_RECTANGLE_NV = 0x0000933C, - GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB = 0x0000933D, - GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV = 0x0000933D, - GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB = 0x0000933E, - GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV = 0x0000933E, - GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB = 0x0000933F, - GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV = 0x0000933F, - GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB = 0x00009340, - GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV = 0x00009340, - GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB = 0x00009341, - GL_PROGRAMMABLE_SAMPLE_LOCATION_NV = 0x00009341, - GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB = 0x00009342, - GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV = 0x00009342, - GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB = 0x00009343, - GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV = 0x00009343, - GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB = 0x00009344, - GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB = 0x00009345, - GL_CONSERVATIVE_RASTERIZATION_NV = 0x00009346, - GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV = 0x00009347, - GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV = 0x00009348, - GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV = 0x00009349, - GL_LOCATION_COMPONENT = 0x0000934A, - GL_TRANSFORM_FEEDBACK_BUFFER_INDEX = 0x0000934B, - GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE = 0x0000934C, - GL_CLIP_ORIGIN = 0x0000935C, - GL_CLIP_DEPTH_MODE = 0x0000935D, - GL_NEGATIVE_ONE_TO_ONE = 0x0000935E, - GL_ZERO_TO_ONE = 0x0000935F, - GL_CLEAR_TEXTURE = 0x00009365, - GL_TEXTURE_REDUCTION_MODE_ARB = 0x00009366, - GL_WEIGHTED_AVERAGE_ARB = 0x00009367, - GL_FONT_GLYPHS_AVAILABLE_NV = 0x00009368, - GL_FONT_TARGET_UNAVAILABLE_NV = 0x00009369, - GL_FONT_UNAVAILABLE_NV = 0x0000936A, - GL_FONT_UNINTELLIGIBLE_NV = 0x0000936B, - GL_STANDARD_FONT_FORMAT_NV = 0x0000936C, - GL_FRAGMENT_INPUT_NV = 0x0000936D, - GL_UNIFORM_BUFFER_UNIFIED_NV = 0x0000936E, - GL_UNIFORM_BUFFER_ADDRESS_NV = 0x0000936F, - GL_UNIFORM_BUFFER_LENGTH_NV = 0x00009370, - GL_MULTISAMPLES_NV = 0x00009371, - GL_SUPERSAMPLE_SCALE_X_NV = 0x00009372, - GL_SUPERSAMPLE_SCALE_Y_NV = 0x00009373, - GL_CONFORMANT_NV = 0x00009374, - GL_CONSERVATIVE_RASTER_DILATE_NV = 0x00009379, - GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV = 0x0000937A, - GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV = 0x0000937B, - GL_NUM_SAMPLE_COUNTS = 0x00009380, - GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB = 0x00009381, - GL_MULTISAMPLE_LINE_WIDTH_RANGE = 0x00009381, - GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB = 0x00009382, - GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 0x00009382, - GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE = 0x000093A0, - GL_BGRA8_EXT = 0x000093A1, - GL_TEXTURE_USAGE_ANGLE = 0x000093A2, - GL_FRAMEBUFFER_ATTACHMENT_ANGLE = 0x000093A3, - GL_PACK_REVERSE_ROW_ORDER_ANGLE = 0x000093A4, - GL_PROGRAM_BINARY_ANGLE = 0x000093A6, - GL_COMPRESSED_RGBA_ASTC_4x4 = 0x000093B0, - GL_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x000093B0, - GL_COMPRESSED_RGBA_ASTC_5x4 = 0x000093B1, - GL_COMPRESSED_RGBA_ASTC_5x4_KHR = 0x000093B1, - GL_COMPRESSED_RGBA_ASTC_5x5 = 0x000093B2, - GL_COMPRESSED_RGBA_ASTC_5x5_KHR = 0x000093B2, - GL_COMPRESSED_RGBA_ASTC_6x5 = 0x000093B3, - GL_COMPRESSED_RGBA_ASTC_6x5_KHR = 0x000093B3, - GL_COMPRESSED_RGBA_ASTC_6x6 = 0x000093B4, - GL_COMPRESSED_RGBA_ASTC_6x6_KHR = 0x000093B4, - GL_COMPRESSED_RGBA_ASTC_8x5 = 0x000093B5, - GL_COMPRESSED_RGBA_ASTC_8x5_KHR = 0x000093B5, - GL_COMPRESSED_RGBA_ASTC_8x6 = 0x000093B6, - GL_COMPRESSED_RGBA_ASTC_8x6_KHR = 0x000093B6, - GL_COMPRESSED_RGBA_ASTC_8x8 = 0x000093B7, - GL_COMPRESSED_RGBA_ASTC_8x8_KHR = 0x000093B7, - GL_COMPRESSED_RGBA_ASTC_10x5 = 0x000093B8, - GL_COMPRESSED_RGBA_ASTC_10x5_KHR = 0x000093B8, - GL_COMPRESSED_RGBA_ASTC_10x6 = 0x000093B9, - GL_COMPRESSED_RGBA_ASTC_10x6_KHR = 0x000093B9, - GL_COMPRESSED_RGBA_ASTC_10x8 = 0x000093BA, - GL_COMPRESSED_RGBA_ASTC_10x8_KHR = 0x000093BA, - GL_COMPRESSED_RGBA_ASTC_10x10 = 0x000093BB, - GL_COMPRESSED_RGBA_ASTC_10x10_KHR = 0x000093BB, - GL_COMPRESSED_RGBA_ASTC_12x10 = 0x000093BC, - GL_COMPRESSED_RGBA_ASTC_12x10_KHR = 0x000093BC, - GL_COMPRESSED_RGBA_ASTC_12x12 = 0x000093BD, - GL_COMPRESSED_RGBA_ASTC_12x12_KHR = 0x000093BD, - GL_COMPRESSED_RGBA_ASTC_3x3x3_OES = 0x000093C0, - GL_COMPRESSED_RGBA_ASTC_4x3x3_OES = 0x000093C1, - GL_COMPRESSED_RGBA_ASTC_4x4x3_OES = 0x000093C2, - GL_COMPRESSED_RGBA_ASTC_4x4x4_OES = 0x000093C3, - GL_COMPRESSED_RGBA_ASTC_5x4x4_OES = 0x000093C4, - GL_COMPRESSED_RGBA_ASTC_5x5x4_OES = 0x000093C5, - GL_COMPRESSED_RGBA_ASTC_5x5x5_OES = 0x000093C6, - GL_COMPRESSED_RGBA_ASTC_6x5x5_OES = 0x000093C7, - GL_COMPRESSED_RGBA_ASTC_6x6x5_OES = 0x000093C8, - GL_COMPRESSED_RGBA_ASTC_6x6x6_OES = 0x000093C9, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 0x000093D0, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR = 0x000093D0, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 0x000093D1, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR = 0x000093D1, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 0x000093D2, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR = 0x000093D2, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 0x000093D3, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR = 0x000093D3, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 0x000093D4, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR = 0x000093D4, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 0x000093D5, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR = 0x000093D5, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 0x000093D6, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR = 0x000093D6, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 0x000093D7, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR = 0x000093D7, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 0x000093D8, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR = 0x000093D8, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 0x000093D9, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR = 0x000093D9, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 0x000093DA, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR = 0x000093DA, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 0x000093DB, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR = 0x000093DB, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 0x000093DC, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x000093DC, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 0x000093DD, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x000093DD, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES = 0x000093E0, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES = 0x000093E1, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES = 0x000093E2, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES = 0x000093E3, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES = 0x000093E4, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES = 0x000093E5, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES = 0x000093E6, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES = 0x000093E7, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES = 0x000093E8, - GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES = 0x000093E9, - GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG = 0x000093F0, - GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG = 0x000093F1, - GL_PERFQUERY_COUNTER_EVENT_INTEL = 0x000094F0, - GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL = 0x000094F1, - GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL = 0x000094F2, - GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL = 0x000094F3, - GL_PERFQUERY_COUNTER_RAW_INTEL = 0x000094F4, - GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL = 0x000094F5, - GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL = 0x000094F8, - GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL = 0x000094F9, - GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL = 0x000094FA, - GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL = 0x000094FB, - GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL = 0x000094FC, - GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL = 0x000094FD, - GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL = 0x000094FE, - GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL = 0x000094FF, - GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL = 0x00009500, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR = 0x00009630, - GL_MAX_VIEWS_OVR = 0x00009631, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR = 0x00009632, - GL_GS_SHADER_BINARY_MTK = 0x00009640, - GL_GS_PROGRAM_BINARY_MTK = 0x00009641, - GL_RASTER_POSITION_UNCLIPPED_IBM = 0x00019262, - GL_CULL_VERTEX_IBM = 0x0001928A, - GL_ALL_STATIC_DATA_IBM = 0x00019294, - GL_STATIC_VERTEX_ARRAY_IBM = 0x00019295, - GL_VERTEX_ARRAY_LIST_IBM = 0x0001929E, - GL_NORMAL_ARRAY_LIST_IBM = 0x0001929F, - GL_COLOR_ARRAY_LIST_IBM = 0x000192A0, - GL_INDEX_ARRAY_LIST_IBM = 0x000192A1, - GL_TEXTURE_COORD_ARRAY_LIST_IBM = 0x000192A2, - GL_EDGE_FLAG_ARRAY_LIST_IBM = 0x000192A3, - GL_FOG_COORDINATE_ARRAY_LIST_IBM = 0x000192A4, - GL_SECONDARY_COLOR_ARRAY_LIST_IBM = 0x000192A5, - GL_VERTEX_ARRAY_LIST_STRIDE_IBM = 0x000192A8, - GL_NORMAL_ARRAY_LIST_STRIDE_IBM = 0x000192A9, - GL_COLOR_ARRAY_LIST_STRIDE_IBM = 0x000192AA, - GL_INDEX_ARRAY_LIST_STRIDE_IBM = 0x000192AB, - GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM = 0x000192AC, - GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM = 0x000192AD, - GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM = 0x000192AE, - GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM = 0x000192AF, - GL_PREFER_DOUBLEBUFFER_HINT_PGI = 0x0001A1F8, - GL_CONSERVE_MEMORY_HINT_PGI = 0x0001A1FD, - GL_RECLAIM_MEMORY_HINT_PGI = 0x0001A1FE, - GL_NATIVE_GRAPHICS_HANDLE_PGI = 0x0001A202, - GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI = 0x0001A203, - GL_NATIVE_GRAPHICS_END_HINT_PGI = 0x0001A204, - GL_ALWAYS_FAST_HINT_PGI = 0x0001A20C, - GL_ALWAYS_SOFT_HINT_PGI = 0x0001A20D, - GL_ALLOW_DRAW_OBJ_HINT_PGI = 0x0001A20E, - GL_ALLOW_DRAW_WIN_HINT_PGI = 0x0001A20F, - GL_ALLOW_DRAW_FRG_HINT_PGI = 0x0001A210, - GL_ALLOW_DRAW_MEM_HINT_PGI = 0x0001A211, - GL_STRICT_DEPTHFUNC_HINT_PGI = 0x0001A216, - GL_STRICT_LIGHTING_HINT_PGI = 0x0001A217, - GL_STRICT_SCISSOR_HINT_PGI = 0x0001A218, - GL_FULL_STIPPLE_HINT_PGI = 0x0001A219, - GL_CLIP_NEAR_HINT_PGI = 0x0001A220, - GL_CLIP_FAR_HINT_PGI = 0x0001A221, - GL_WIDE_LINE_HINT_PGI = 0x0001A222, - GL_BACK_NORMALS_HINT_PGI = 0x0001A223, - GL_VERTEX_DATA_HINT_PGI = 0x0001A22A, - GL_VERTEX_CONSISTENT_HINT_PGI = 0x0001A22B, - GL_MATERIAL_SIDE_HINT_PGI = 0x0001A22C, - GL_MAX_VERTEX_HINT_PGI = 0x0001A22D, - GL_NUM_WINDOW_RECTANGLES_EXT = 0x00008F15, - GL_FLOAT16_MAT4_AMD = 0x000091C7, - GL_VIEWPORT_INDEX_PROVOKING_VERTEX_OES = 0x0000825F, - GL_VIEWPORT_POSITION_W_SCALE_NV = 0x0000937C, - GL_MAX_VIEWPORTS_OES = 0x0000825B, - GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG = 0x0000913C, - GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV = 0x00009356, - GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG = 0x0000913F, - GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV = 0x0000937D, - GL_VIEWPORT_SWIZZLE_Y_NV = 0x00009359, - GL_CUBIC_MIPMAP_NEAREST_IMG = 0x0000913A, - GL_FLOAT16_MAT2_AMD = 0x000091C5, - GL_CUBIC_IMG = 0x00009139, - GL_DOWNSAMPLE_SCALES_IMG = 0x0000913E, - GL_NUM_DOWNSAMPLE_SCALES_IMG = 0x0000913D, - GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD = 0x000091AE, - GL_FLOAT16_MAT4x3_AMD = 0x000091CD, - GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT = 0x000082FA, - GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_FAST_SIZE_EXT = 0x00009650, - GL_FLOAT16_MAT2x3_AMD = 0x000091C8, - GL_CONSERVATIVE_RASTERIZATION_INTEL = 0x000083FE, - GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV = 0x00009354, - GL_VIEWPORT_SWIZZLE_W_NV = 0x0000935B, - GL_MAX_WINDOW_RECTANGLES_EXT = 0x00008F14, - GL_EXCLUSIVE_EXT = 0x00008F11, - GL_WINDOW_RECTANGLE_EXT = 0x00008F12, - GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR = 0x00009633, - GL_CLIP_DISTANCE1_EXT = 0x00003001, - GL_FLOAT16_MAT4x2_AMD = 0x000091CC, - GL_CONSERVATIVE_RASTER_MODE_NV = 0x0000954D, - GL_CLIP_DISTANCE7_EXT = 0x00003007, - GL_VIEWPORT_SWIZZLE_Z_NV = 0x0000935A, - GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV = 0x00009353, - GL_PURGED_CONTEXT_RESET_NV = 0x000092BB, - GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV = 0x0000954E, - GL_FLOAT16_MAT2x4_AMD = 0x000091C9, - GL_CUBIC_MIPMAP_LINEAR_IMG = 0x0000913B, - GL_ALL_PIXELS_AMD = 0xFFFFFFFF, - GL_CLIP_DISTANCE5_EXT = 0x00003005, - GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV = 0x00009352, - GL_CLIP_DISTANCE4_EXT = 0x00003004, - GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD = 0x000091AF, - GL_VIEWPORT_SUBPIXEL_BITS_OES = 0x0000825C, - GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV = 0x00009355, - GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV = 0x0000954F, - GL_FLOAT16_MAT3_AMD = 0x000091C6, - GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV = 0x00009357, - GL_CLIP_DISTANCE3_EXT = 0x00003003, - GL_FLOAT16_MAT3x4_AMD = 0x000091CB, - GL_VIEWPORT_BOUNDS_RANGE_OES = 0x0000825D, - GL_MAX_CULL_DISTANCES_EXT = 0x000082F9, - GL_VIEWPORT_SWIZZLE_X_NV = 0x00009358, - GL_MAX_CLIP_DISTANCES_EXT = 0x00000D32, - GL_CLIP_DISTANCE2_EXT = 0x00003002, - GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV = 0x00009351, - GL_FLOAT16_MAT3x2_AMD = 0x000091CA, - GL_FRAMEBUFFER_INCOMPLETE_INSUFFICIENT_SHADER_COMBINED_LOCAL_STORAGE_EXT = 0x00009652, - GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV = 0x0000937E, - GL_WINDOW_RECTANGLE_MODE_EXT = 0x00008F13, - GL_INCLUSIVE_EXT = 0x00008F10, - GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV = 0x00009350, - GL_TEXTURE_PROTECTED_EXT = 0x00008BFA, - GL_MAX_SHADER_COMBINED_LOCAL_STORAGE_SIZE_EXT = 0x00009651, - GL_CLIP_DISTANCE6_EXT = 0x00003006, - GL_CLIP_DISTANCE0_EXT = 0x00003000, -} diff --git a/gapis/api/gles/api/image_format.api b/gapis/api/gles/api/image_format.api deleted file mode 100644 index a55aacde50..0000000000 --- a/gapis/api/gles/api/image_format.api +++ /dev/null @@ -1,517 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class UnsizedFormatInfo { - u32 Count - @unused GLenum Channel0 - @unused GLenum Channel1 - @unused GLenum Channel2 - @unused GLenum Channel3 - @unused bool Integer -} - -sub UnsizedFormatInfo GetUnsizedFormatInfo(GLenum uf) { - x := GL_NONE - R := GL_RED - G := GL_GREEN - B := GL_BLUE - A := GL_ALPHA - L := GL_LUMINANCE - D := GL_DEPTH_COMPONENT - S := GL_STENCIL_INDEX - INTEGER := true - return switch uf { - // TODO: Where is this defined? - case GL_ABGR_EXT: UnsizedFormatInfo(4, A, B, G, R) - @if(Version.GLES20) - case GL_ALPHA: UnsizedFormatInfo(1, A) - case GL_ALPHA_INTEGER_EXT: UnsizedFormatInfo(1, A, x, x, x, INTEGER) - case GL_BGR: UnsizedFormatInfo(3, B, G, R) - case GL_BGR_INTEGER: UnsizedFormatInfo(3, B, G, R, x, INTEGER) - @if(Extension.GL_EXT_texture_format_BGRA8888) - case GL_BGRA: UnsizedFormatInfo(4, B, G, R, A) - case GL_BGRA_INTEGER: UnsizedFormatInfo(4, B, G, R, A, INTEGER) - @if(Version.GLES30 || Extension.GL_OES_depth_texture) - case GL_DEPTH_COMPONENT: UnsizedFormatInfo(1, D) - @if(Version.GLES30 || Extension.GL_OES_packed_depth_stencil) - case GL_DEPTH_STENCIL: UnsizedFormatInfo(2, D, S) - @if(Version.GLES20) - case GL_LUMINANCE: UnsizedFormatInfo(1, L) - case GL_LUMINANCE_INTEGER_EXT: UnsizedFormatInfo(1, L, x, x, x, INTEGER) - @if(Version.GLES20) - case GL_LUMINANCE_ALPHA: UnsizedFormatInfo(2, L, A) - case GL_LUMINANCE_ALPHA_INTEGER_EXT: UnsizedFormatInfo(2, L, A, x, x, INTEGER) - @if(Version.GLES30 || Extension.GL_EXT_texture_rg) - case GL_RED: UnsizedFormatInfo(1, R) - @if(Version.GLES30) - case GL_RED_INTEGER: UnsizedFormatInfo(1, R, x, x, x, INTEGER) - @if(Version.GLES30 || Extension.GL_EXT_texture_rg) - case GL_RG: UnsizedFormatInfo(2, R, G) - @if(Version.GLES30) - case GL_RG_INTEGER: UnsizedFormatInfo(2, R, G, x, x, INTEGER) - @if(Version.GLES20) - case GL_RGB: UnsizedFormatInfo(3, R, G, B) - @if(Version.GLES30) - case GL_RGB_INTEGER: UnsizedFormatInfo(3, R, G, B, x, INTEGER) - @if(Version.GLES20) - case GL_RGBA: UnsizedFormatInfo(4, R, G, B, A) - @if(Version.GLES30) - case GL_RGBA_INTEGER: UnsizedFormatInfo(4, R, G, B, A, INTEGER) - @if(Version.GLES32 || Extension.GL_OES_texture_stencil8) - case GL_STENCIL_INDEX: UnsizedFormatInfo(1, S) - default: UnsizedFormatInfo() - } -} - -@internal -class SizedFormatInfo { - // "Internal format" with explicit memory size. Includes compressed formats. - // (RGB565, RGBA8, R16UI, DEPTH24_STENCIL8, COMPRESSED_SRGB8_ETC2, ...) - @unused GLenum SizedFormat - - // "Base format" which specifies just the channels. Includes the _INTEGER suffix. - // This must be just the {R,G,B,A,D,S,INTEGER} part of the sized format above. - // (RGB, RGBA, RED, DEPTH_STENCIL, RGB_INTEGER, ...) - GLenum UnsizedFormat - - // Type of either one channel or the whole pixel. NONE for compressed formats. - // This must be just the data type part of the sized format above (exactly). - // For example, RGB565 must use UNSIGNED_SHORT_5_6_5, not UNSIGNED_BYTE. - // (UNSIGNED_BYTE, FLOAT, UNSIGNED_SHORT_5_6_5...) - GLenum DataType - - // True if the data is converted from sRGB to liner space by the sampler. - // Note that GL does not care about colour spaces, and colour textures - // will generally contain sRGB content even if this flag is off. - // Thus, this flag just allows sRGB conscious developer to save a few - // fragment shader instructions by doing the conversion in texture unit. - @unused bool SRGB - - // Information about the compression algorithm - CompressionAlgorithm Compression - @unused u32 BlockWidth - @unused u32 BlockHeight - @unused u32 BlockSize -} - -@internal -enum CompressionAlgorithm { - Uncompressed = 0, - ETC1 = 1, - ETC2 = 2, - S3TC = 3, - ASTC = 4, - ATC = 5, - EAC = 6, -} - -// uncompressedImageSize returns image size based on given format and type. -// TODO: Users of this function generally ignore packing/unpacking rules. -sub u32 uncompressedImageSize(GLsizei width, GLsizei height, GLenum format, GLenum ty) { - return as!u32(width) * as!u32(height) * uncompressedPixelSize(format, ty) -} - -// uncompressedPixelSize returns the pixel data size in bytes for the given format and type. -sub u32 uncompressedPixelSize(GLenum unsizedFormat, GLenum ty) { - fmtInfo := GetUnsizedFormatInfo(unsizedFormat) - num_components := fmtInfo.Count - - return switch ty { - case GL_UNSIGNED_BYTE: num_components * 1 - case GL_BYTE: num_components * 1 - case GL_UNSIGNED_SHORT: num_components * 2 - case GL_SHORT: num_components * 2 - case GL_UNSIGNED_INT: num_components * 4 - case GL_INT: num_components * 4 - case GL_HALF_FLOAT: num_components * 2 - case GL_HALF_FLOAT_OES: num_components * 2 - case GL_FLOAT: num_components * 4 - case GL_UNSIGNED_SHORT_5_6_5: 2 - case GL_UNSIGNED_SHORT_4_4_4_4: 2 - case GL_UNSIGNED_SHORT_5_5_5_1: 2 - case GL_UNSIGNED_INT_2_10_10_10_REV: 4 - case GL_UNSIGNED_INT_10F_11F_11F_REV: 4 - case GL_UNSIGNED_INT_5_9_9_9_REV: 4 - case GL_UNSIGNED_INT_24_8: 4 - case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: 8 - default: 0 // TODO: What should we do in this case? - } -} - - -sub SizedFormatInfo GetSizedFormatInfo(GLenum sf) { - // Give the constant name for clarity - sRGB := true - linear := false - return switch (sf) { - // Uncompressed colour formats - @if(Extension.GL_EXT_texture_storage) - case GL_LUMINANCE8_ALPHA8_EXT: SizedFormatInfo(sf, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE) - @if(Extension.GL_EXT_texture_storage) - case GL_LUMINANCE8_EXT: SizedFormatInfo(sf, GL_LUMINANCE, GL_UNSIGNED_BYTE) - @if(Extension.GL_EXT_texture_storage) - case GL_ALPHA8_EXT: SizedFormatInfo(sf, GL_ALPHA, GL_UNSIGNED_BYTE) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_float) - case GL_LUMINANCE_ALPHA32F_EXT: SizedFormatInfo(sf, GL_LUMINANCE_ALPHA, GL_FLOAT) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_float) - case GL_LUMINANCE32F_EXT: SizedFormatInfo(sf, GL_LUMINANCE, GL_FLOAT ) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_float) - case GL_ALPHA32F_EXT: SizedFormatInfo(sf, GL_ALPHA, GL_FLOAT) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_half_float) - case GL_LUMINANCE_ALPHA16F_EXT: SizedFormatInfo(sf, GL_LUMINANCE_ALPHA, GL_HALF_FLOAT) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_half_float) - case GL_LUMINANCE16F_EXT: SizedFormatInfo(sf, GL_LUMINANCE, GL_HALF_FLOAT ) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_half_float) - case GL_ALPHA16F_EXT: SizedFormatInfo(sf, GL_ALPHA, GL_HALF_FLOAT) - @if(Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_format_BGRA8888) - case GL_BGRA8_EXT: SizedFormatInfo(sf, GL_BGRA, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_R11F_G11F_B10F: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_R16: SizedFormatInfo(sf, GL_RED, GL_UNSIGNED_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg && Extension.GL_OES_texture_half_float)) - case GL_R16F: SizedFormatInfo(sf, GL_RED, GL_HALF_FLOAT) - @if(Version.GLES30) - case GL_R16I: SizedFormatInfo(sf, GL_RED_INTEGER, GL_SHORT) - @if(Version.GLES30) - case GL_R16UI: SizedFormatInfo(sf, GL_RED_INTEGER, GL_UNSIGNED_SHORT) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_R16_SNORM: SizedFormatInfo(sf, GL_RED, GL_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg && Extension.GL_OES_texture_float)) - case GL_R32F: SizedFormatInfo(sf, GL_RED, GL_FLOAT) - @if(Version.GLES30) - case GL_R32I: SizedFormatInfo(sf, GL_RED_INTEGER, GL_INT) - @if(Version.GLES30) - case GL_R32UI: SizedFormatInfo(sf, GL_RED_INTEGER, GL_UNSIGNED_INT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg)) - case GL_R8: SizedFormatInfo(sf, GL_RED, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_R8I: SizedFormatInfo(sf, GL_RED_INTEGER, GL_BYTE) - @if(Version.GLES30) - case GL_R8UI: SizedFormatInfo(sf, GL_RED_INTEGER, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_R8_SNORM: SizedFormatInfo(sf, GL_RED, GL_BYTE) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RG16: SizedFormatInfo(sf, GL_RG, GL_UNSIGNED_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg && Extension.GL_OES_texture_half_float)) - case GL_RG16F: SizedFormatInfo(sf, GL_RG, GL_HALF_FLOAT) - @if(Version.GLES30) - case GL_RG16I: SizedFormatInfo(sf, GL_RG_INTEGER, GL_SHORT) - @if(Version.GLES30) - case GL_RG16UI: SizedFormatInfo(sf, GL_RG_INTEGER, GL_UNSIGNED_SHORT) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RG16_SNORM: SizedFormatInfo(sf, GL_RG, GL_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg && Extension.GL_OES_texture_float)) - case GL_RG32F: SizedFormatInfo(sf, GL_RG, GL_FLOAT) - @if(Version.GLES30) - case GL_RG32I: SizedFormatInfo(sf, GL_RG_INTEGER, GL_INT) - @if(Version.GLES30) - case GL_RG32UI: SizedFormatInfo(sf, GL_RG_INTEGER, GL_UNSIGNED_INT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_rg)) - case GL_RG8: SizedFormatInfo(sf, GL_RG, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RG8I: SizedFormatInfo(sf, GL_RG_INTEGER, GL_BYTE) - @if(Version.GLES30) - case GL_RG8UI: SizedFormatInfo(sf, GL_RG_INTEGER, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RG8_SNORM: SizedFormatInfo(sf, GL_RG, GL_BYTE) - @if(Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_type_2_10_10_10_REV) - case GL_RGB10: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_INT_2_10_10_10_REV) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_EXT_texture_type_2_10_10_10_REV)) - case GL_RGB10_A2: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV) - @if(Version.GLES30) - case GL_RGB10_A2UI: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RGB16: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_half_float)) - case GL_RGB16F: SizedFormatInfo(sf, GL_RGB, GL_HALF_FLOAT) - @if(Version.GLES30) - case GL_RGB16I: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_SHORT) - @if(Version.GLES30) - case GL_RGB16UI: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_UNSIGNED_SHORT) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RGB16_SNORM: SizedFormatInfo(sf, GL_RGB, GL_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_float)) - case GL_RGB32F: SizedFormatInfo(sf, GL_RGB, GL_FLOAT) - @if(Version.GLES30) - case GL_RGB32I: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_INT) - @if(Version.GLES30) - case GL_RGB32UI: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_UNSIGNED_INT) - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_RGB565: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_SHORT_5_6_5) - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_RGB5_A1: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1) - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_RGB8: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RGB8I: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_BYTE) - @if(Version.GLES30) - case GL_RGB8UI: SizedFormatInfo(sf, GL_RGB_INTEGER, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RGB8_SNORM: SizedFormatInfo(sf, GL_RGB, GL_BYTE) - @if(Version.GLES30) - case GL_RGB9_E5: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RGBA16: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_half_float)) - case GL_RGBA16F: SizedFormatInfo(sf, GL_RGBA, GL_HALF_FLOAT) - @if(Version.GLES30) - case GL_RGBA16I: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_SHORT) - @if(Version.GLES30) - case GL_RGBA16UI: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT) - @if(Version.GLES31 || Extension.GL_EXT_texture_norm16) - case GL_RGBA16_SNORM: SizedFormatInfo(sf, GL_RGBA, GL_SHORT) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_texture_float)) - case GL_RGBA32F: SizedFormatInfo(sf, GL_RGBA, GL_FLOAT) - @if(Version.GLES30) - case GL_RGBA32I: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_INT) - @if(Version.GLES30) - case GL_RGBA32UI: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_UNSIGNED_INT) - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_RGBA4: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4) - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_RGBA8: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RGBA8I: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_BYTE) - @if(Version.GLES30) - case GL_RGBA8UI: SizedFormatInfo(sf, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE) - @if(Version.GLES30) - case GL_RGBA8_SNORM: SizedFormatInfo(sf, GL_RGBA, GL_BYTE) - @if(Version.GLES30) - case GL_SRGB8: SizedFormatInfo(sf, GL_RGB, GL_UNSIGNED_BYTE, sRGB) - @if(Version.GLES30) - case GL_SRGB8_ALPHA8: SizedFormatInfo(sf, GL_RGBA, GL_UNSIGNED_BYTE, sRGB) - // Uncompressed depth/stencil formats - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_packed_depth_stencil)) - case GL_DEPTH24_STENCIL8: SizedFormatInfo(sf, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8) - @if(Version.GLES30) - case GL_DEPTH32F_STENCIL8: SizedFormatInfo(sf, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV) - @if(Version.GLES30 || (Extension.GL_EXT_texture_storage && Extension.GL_OES_depth_texture)) - case GL_DEPTH_COMPONENT16: SizedFormatInfo(sf, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT) - @if(Version.GLES30) - case GL_DEPTH_COMPONENT24: SizedFormatInfo(sf, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT) - @if(Extension.GL_EXT_texture_storage && Extension.GL_OES_depth_texture) - case GL_DEPTH_COMPONENT32: SizedFormatInfo(sf, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT) - @if(Version.GLES30) - case GL_DEPTH_COMPONENT32F: SizedFormatInfo(sf, GL_DEPTH_COMPONENT, GL_FLOAT) - @if(Version.GLES32) - case GL_STENCIL_INDEX8: SizedFormatInfo(sf, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE) - // Compressed formats - @if(Version.GLES30) - case GL_COMPRESSED_R11_EAC: SizedFormatInfo(sf, GL_RED, GL_NONE, linear, EAC, 4, 4, 8) - @if(Version.GLES30) - case GL_COMPRESSED_RG11_EAC: SizedFormatInfo(sf, GL_RG, GL_NONE, linear, EAC, 4, 4, 16) - @if(Version.GLES30) - case GL_COMPRESSED_RGB8_ETC2: SizedFormatInfo(sf, GL_RGB, GL_NONE, linear, ETC2, 4, 4, 8) - @if(Version.GLES30) - case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ETC2, 4, 4, 8) - @if(Version.GLES30) - case GL_COMPRESSED_RGBA8_ETC2_EAC: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ETC2, 4, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_10x10: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 10, 10, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_10x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 10, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_10x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 10, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_10x8: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 10, 8, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_12x10: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 12, 10, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_12x12: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 12, 12, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_4x4: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 4, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_5x4: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 5, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_5x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 5, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_6x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 6, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_6x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 6, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_8x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 8, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_8x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 8, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_RGBA_ASTC_8x8: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ASTC, 8, 8, 16) - @if(Version.GLES30) - case GL_COMPRESSED_SIGNED_R11_EAC: SizedFormatInfo(sf, GL_RED, GL_NONE, linear, EAC, 4, 4, 8) - @if(Version.GLES30) - case GL_COMPRESSED_SIGNED_RG11_EAC: SizedFormatInfo(sf, GL_RG, GL_NONE, linear, EAC, 4, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 10, 10, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 10, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 10, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 10, 8, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 12, 10, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 12, 12, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 4, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 5, 4, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 5, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 6, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 6, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 8, 5, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 8, 6, 16) - @if(Version.GLES32) - case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ASTC, 8, 8, 16) - @if(Version.GLES30) - case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ETC2, 4, 4, 16) - @if(Version.GLES30) - case GL_COMPRESSED_SRGB8_ETC2: SizedFormatInfo(sf, GL_RGB, GL_NONE, sRGB, ETC2, 4, 4, 8) - @if(Version.GLES30) - case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: SizedFormatInfo(sf, GL_RGBA, GL_NONE, sRGB, ETC2, 4, 4, 8) - @if(Extension.GL_OES_compressed_ETC1_RGB8_texture) - case GL_ETC1_RGB8_OES: SizedFormatInfo(sf, GL_RGB, GL_NONE, linear, ETC1, 4, 4, 8) - @if(Extension.GL_EXT_texture_compression_s3tc) - case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: SizedFormatInfo(sf, GL_RGB, GL_NONE, linear, S3TC, 4, 4, 8) - @if(Extension.GL_EXT_texture_compression_s3tc) - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, S3TC, 4, 4, 8) - @if(Extension.GL_EXT_texture_compression_s3tc) - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, S3TC, 4, 4, 16) - @if(Extension.GL_EXT_texture_compression_s3tc) - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, S3TC, 4, 4, 16) - @if(Extension.GL_AMD_compressed_ATC_texture) - case GL_ATC_RGB_AMD: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ATC, 4, 4, 8) - @if(Extension.GL_AMD_compressed_ATC_texture) - case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ATC, 4, 4, 16) - @if(Extension.GL_AMD_compressed_ATC_texture) - case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: SizedFormatInfo(sf, GL_RGBA, GL_NONE, linear, ATC, 4, 4, 16) - default: - SizedFormatInfo(GL_NONE) - } -} - -// GLES 2.0 omits sized internal format from commands and uses (format, type) tuple instead. -// We need to check that the tuple is valid and convert it to sized format for internal use. -sub GLenum GetSizedFormatFromTuple(GLenum unsizedFormat, GLenum type) { - return switch unsizedFormat { - @if(Extension.GL_EXT_texture_format_BGRA8888) - case GL_BGRA_EXT: switch type { - case GL_UNSIGNED_BYTE: GL_BGRA8_EXT - default: GL_NONE - } - @if(Extension.GL_EXT_texture_rg) - case GL_RED_EXT: switch type { - case GL_UNSIGNED_BYTE: GL_R8 - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_R16F - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_R32F - default: GL_NONE - } - @if(Extension.GL_EXT_texture_rg) - case GL_RG_EXT: switch type { - case GL_UNSIGNED_BYTE: GL_RG8 - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_RG16F - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_RG32F - default: GL_NONE - } - case GL_RGB: switch type { - case GL_UNSIGNED_BYTE: GL_RGB8 - case GL_UNSIGNED_SHORT_5_6_5: GL_RGB565 - @if(Extension.GL_EXT_texture_type_2_10_10_10_REV) - case GL_UNSIGNED_INT_2_10_10_10_REV: GL_RGB10 - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_RGB16F - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_RGB32F - default: GL_NONE - } - case GL_RGBA: switch type { - case GL_UNSIGNED_BYTE: GL_RGBA8 - case GL_UNSIGNED_SHORT_4_4_4_4: GL_RGBA4 - case GL_UNSIGNED_SHORT_5_5_5_1: GL_RGB5_A1 - @if(Extension.GL_EXT_texture_type_2_10_10_10_REV) - case GL_UNSIGNED_INT_2_10_10_10_REV: GL_RGB10_A2 - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_RGBA16F - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_RGBA32F - default: GL_NONE - } - @if(Extension.GL_OES_depth_texture) - case GL_DEPTH_COMPONENT: switch type { - case GL_UNSIGNED_SHORT: GL_DEPTH_COMPONENT16 - case GL_UNSIGNED_INT: GL_DEPTH_COMPONENT24 - default: GL_NONE - } - @if(Extension.GL_OES_packed_depth_stencil) - case GL_DEPTH_STENCIL: switch type { - case GL_UNSIGNED_INT_24_8: GL_DEPTH24_STENCIL8 - default: GL_NONE - } - case GL_LUMINANCE_ALPHA: switch type { - case GL_UNSIGNED_BYTE: GL_LUMINANCE8_ALPHA8_EXT - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_LUMINANCE_ALPHA16F_EXT - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_LUMINANCE_ALPHA32F_EXT - default: GL_NONE - } - case GL_LUMINANCE: switch type { - case GL_UNSIGNED_BYTE: GL_LUMINANCE8_EXT - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_LUMINANCE16F_EXT - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_LUMINANCE32F_EXT - default: GL_NONE - } - case GL_ALPHA: switch type { - case GL_UNSIGNED_BYTE: GL_ALPHA8_EXT - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT, GL_HALF_FLOAT_OES: GL_ALPHA16F_EXT - @if(Extension.GL_OES_texture_float) - case GL_FLOAT: GL_ALPHA32F_EXT - default: GL_NONE - } - default: GL_NONE - } -} - -sub void CheckTextureDataType(GLenum type) { - switch (type) { - @if(Version.GLES20) - case GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_5_6_5: { } - @if(Extension.GL_OES_texture_half_float) - case GL_HALF_FLOAT_OES: { } - @if(Version.GLES30 || Extension.GL_OES_texture_float) - case GL_FLOAT: {} - @if(Version.GLES30 || Extension.GL_EXT_texture_type_2_10_10_10_REV) - case GL_UNSIGNED_INT_2_10_10_10_REV: {} - @if(Version.GLES30 || Extension.GL_OES_depth_texture) - case GL_UNSIGNED_SHORT, GL_UNSIGNED_INT: {} - @if(Version.GLES30 || Extension.GL_OES_packed_depth_stencil) - case GL_UNSIGNED_INT_24_8: {} - @if(Version.GLES30) - case GL_BYTE, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, GL_HALF_FLOAT, GL_INT, GL_SHORT, - GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV: { } - default: { glErrorInvalidEnum(type) } - } -} diff --git a/gapis/api/gles/api/other.api b/gapis/api/gles/api/other.api deleted file mode 100644 index a7241e5744..0000000000 --- a/gapis/api/gles/api/other.api +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -sub void SetCapability(GLenum capability, bool isIndexed, GLuint index, GLboolean enabled) { - ctx := GetContext() - switch (capability) { - @if(Version.GLES20) - case GL_BLEND: { - // TODO: Remove the temporary variables once we fix bug 28858106 - if isIndexed { - blend := ctx.Pixel.Blend[as!DrawBufferIndex(index)] - blend.Enabled = enabled - ctx.Pixel.Blend[as!DrawBufferIndex(index)] = blend - } else { - for i in 0 .. as!DrawBufferIndex(len(ctx.Pixel.Blend)) { - blend := ctx.Pixel.Blend[i] - blend.Enabled = enabled - ctx.Pixel.Blend[i] = blend - } - } - } - @if(Version.GLES20) - case GL_CULL_FACE: { - ctx.Rasterization.CullFace = enabled - } - @if(Version.GLES20) - case GL_DEPTH_TEST: { - ctx.Pixel.Depth.Test = enabled - } - @if(Version.GLES20) - case GL_DITHER: { - ctx.Pixel.Dither = enabled - } - @if(Version.GLES20) - case GL_POLYGON_OFFSET_FILL: { - ctx.Rasterization.PolygonOffsetFill = enabled - } - @if(Version.GLES20) - case GL_SAMPLE_ALPHA_TO_COVERAGE: { - ctx.Rasterization.SampleAlphaToCoverage = enabled - } - @if(Version.GLES20) - case GL_SAMPLE_COVERAGE: { - ctx.Rasterization.SampleCoverage = enabled - } - @if(Version.GLES20) - case GL_SCISSOR_TEST: { - ctx.Pixel.Scissor.Test = enabled - } - @if(Version.GLES20) - case GL_STENCIL_TEST: { - ctx.Pixel.Stencil.Test = enabled - } - @if(Version.GLES30) - case GL_PRIMITIVE_RESTART_FIXED_INDEX: { - ctx.Vertex.PrimitiveRestartFixedIndex = enabled - } - @if(Version.GLES30) - case GL_RASTERIZER_DISCARD: { - ctx.Rasterization.RasterizerDiscard = enabled - } - @if(Version.GLES31) - case GL_SAMPLE_MASK: { - ctx.Rasterization.SampleMask = enabled - } - @if(Version.GLES32) - case GL_SAMPLE_SHADING: { - ctx.Rasterization.SampleShading = enabled - } - @if(Version.GLES32) - case GL_DEBUG_OUTPUT: { - ctx.Other.Debug.Output = enabled - } - @if(Version.GLES32) - case GL_DEBUG_OUTPUT_SYNCHRONOUS: { - ctx.Other.Debug.OutputSynchronous = enabled - } - @if(Extension.GL_QCOM_alpha_test) - case GL_ALPHA_TEST_QCOM: { - // TODO: Set state. - } - @if(Extension.GL_EXT_sRGB_write_control) - case GL_FRAMEBUFFER_SRGB_EXT: { - ctx.Pixel.FramebufferSrgb = enabled - } - @if(Extension.GL_EXT_clip_cull_distance) - case GL_CLIP_DISTANCE0_EXT, GL_CLIP_DISTANCE1_EXT, - GL_CLIP_DISTANCE2_EXT, GL_CLIP_DISTANCE3_EXT, - GL_CLIP_DISTANCE4_EXT, GL_CLIP_DISTANCE5_EXT, - GL_CLIP_DISTANCE6_EXT, GL_CLIP_DISTANCE7_EXT: { - // TODO - } - default: { - glErrorInvalidEnum(capability) - } - } -} - -sub GLboolean GetCapability(GLenum capability, GLuint index) { - ctx := GetContext() - // TODO: Add back the version checks. - switch (capability) { - @if(Version.GLES20) - case GL_BLEND: { - i := as!DrawBufferIndex(index) - if !(i in ctx.Pixel.Blend) { - glErrorInvalidValue!DrawBufferIndex(i) - } - } - @if(Version.GLES20) - case GL_CULL_FACE, - GL_DEPTH_TEST, - GL_DITHER, - GL_POLYGON_OFFSET_FILL, - GL_SAMPLE_ALPHA_TO_COVERAGE, - GL_SAMPLE_COVERAGE, - GL_SCISSOR_TEST, - GL_STENCIL_TEST: { - CheckEQ!GLuint(index, 0) - } - @if(Version.GLES30) - case GL_PRIMITIVE_RESTART_FIXED_INDEX, - GL_RASTERIZER_DISCARD: { - CheckEQ!GLuint(index, 0) - } - @if(Version.GLES31) - case GL_SAMPLE_MASK: { - CheckEQ!GLuint(index, 0) - } - @if(Version.GLES32) - case GL_SAMPLE_SHADING: { - CheckEQ!GLuint(index, 0) - } - @if(Version.GLES32) - case GL_DEBUG_OUTPUT, GL_DEBUG_OUTPUT_SYNCHRONOUS: { - CheckEQ!GLuint(index, 0) - } - default: { - // glErrorInvalidEnum(capability) - } - } - - return switch (capability) { - @if(Version.GLES20) - case GL_BLEND: { - ctx.Pixel.Blend[as!DrawBufferIndex(index)].Enabled - } - @if(Version.GLES20) - case GL_CULL_FACE: { - ctx.Rasterization.CullFace - } - @if(Version.GLES20) - case GL_DEPTH_TEST: { - ctx.Pixel.Depth.Test - } - @if(Version.GLES20) - case GL_DITHER: { - ctx.Pixel.Dither - } - @if(Version.GLES20) - case GL_POLYGON_OFFSET_FILL: { - ctx.Rasterization.PolygonOffsetFill - } - @if(Version.GLES20) - case GL_SAMPLE_ALPHA_TO_COVERAGE: { - ctx.Rasterization.SampleAlphaToCoverage - } - @if(Version.GLES20) - case GL_SAMPLE_COVERAGE: { - ctx.Rasterization.SampleCoverage - } - @if(Version.GLES20) - case GL_SCISSOR_TEST: { - ctx.Pixel.Scissor.Test - } - @if(Version.GLES20) - case GL_STENCIL_TEST: { - ctx.Pixel.Stencil.Test - } - @if(Version.GLES30) - case GL_PRIMITIVE_RESTART_FIXED_INDEX: { - ctx.Vertex.PrimitiveRestartFixedIndex - } - @if(Version.GLES30) - case GL_RASTERIZER_DISCARD: { - ctx.Rasterization.RasterizerDiscard - } - @if(Version.GLES31) - case GL_SAMPLE_MASK: { - ctx.Rasterization.SampleMask - } - @if(Version.GLES32) - case GL_SAMPLE_SHADING: { - ctx.Rasterization.SampleShading - } - @if(Version.GLES32) - case GL_DEBUG_OUTPUT: { - ctx.Other.Debug.Output - } - @if(Version.GLES32) - case GL_DEBUG_OUTPUT_SYNCHRONOUS: { - ctx.Other.Debug.OutputSynchronous - } - @if(Extension.GL_QCOM_alpha_test) - case GL_ALPHA_TEST_QCOM: { - GL_FALSE // TODO: Get state. - } - @if(Extension.GL_EXT_sRGB_write_control) - case GL_FRAMEBUFFER_SRGB_EXT: { - ctx.Pixel.FramebufferSrgb - } - default: { - // glErrorInvalidEnum(capability) - GL_FALSE - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDisable.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDisable.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDisable.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDisable.xhtml", Version.GLES32) -cmd void glDisable(GLenum capability) { - SetCapability(capability, /* isIndexed */ false, 0, /* enabled */ GL_FALSE) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glEnable.xhtml", Version.GLES32) -cmd void glDisablei(GLenum capability, GLuint index) { - Disablei(capability, index) -} - -sub void Disablei(GLenum capability, GLuint index) { - SetCapability(capability, /* isIndexed */ true, index, /* enabled */ GL_FALSE) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glEnable.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glEnable.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glEnable.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glEnable.xhtml", Version.GLES32) -cmd void glEnable(GLenum capability) { - SetCapability(capability, /* isIndexed */ false, 0, /* enabled */ GL_TRUE) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glEnable.xhtml", Version.GLES32) -cmd void glEnablei(GLenum capability, GLuint index) { - Enablei(capability, index) -} - -sub void Enablei(GLenum capability, GLuint index) { - SetCapability(capability, /* isIndexed */ true, index, /* enabled */ GL_TRUE) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFinish.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFinish.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFinish.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFinish.xhtml", Version.GLES32) -cmd void glFinish() { - -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFlush.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFlush.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFlush.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFlush.xhtml", Version.GLES32) -cmd void glFlush() { - -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetError.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetError.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetError.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetError.xhtml", Version.GLES32) -cmd GLenum glGetError() { - - return ? -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetGraphicsResetStatus.xhtml", Version.GLES32) -cmd GLenum glGetGraphicsResetStatus() { - GetGraphicsResetStatus() - return ? -} - -sub void GetGraphicsResetStatus() { - // TODO -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glHint.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glHint.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glHint.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glHint.xhtml", Version.GLES32) -cmd void glHint(GLenum target, GLenum mode) { - switch (mode) { - case GL_DONT_CARE, GL_FASTEST, GL_NICEST: { - // version 2.0 - } - default: { - glErrorInvalidEnum(mode) - } - } - ctx := GetContext() - switch (target) { - @if(Version.GLES20) - case GL_GENERATE_MIPMAP_HINT: { - ctx.Other.GenerateMipmapHint = mode - } - @if(Version.GLES30) - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: { - ctx.Other.FragmentShaderDerivativeHint = mode - } - default: { - glErrorInvalidEnum(target) - } - } - -} diff --git a/gapis/api/gles/api/programs_and_shaders.api b/gapis/api/gles/api/programs_and_shaders.api deleted file mode 100644 index 8dd0d7fd70..0000000000 --- a/gapis/api/gles/api/programs_and_shaders.api +++ /dev/null @@ -1,2457 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -@resource -class Shader { - @unused ShaderId ID - - // Table 21.19: Shader Object State - GLenum Type - @unused bool CompileStatus = false - @unused string InfoLog - string Source - bool DeleteStatus - @unused string Label - s32 AttachCount - - @hidden ref!CompileShaderExtra CompileExtra // Describes last compile command -} - -// Extra describing shader compilation including both the inputs and outputs. -// We need to store copy of compile-time inputs for mid-execution capture, -// because changing the source code does not change the compiled shader code. -@internal -class CompileShaderExtra { - ShaderId ID - - // Outputs - bool CompileStatus - string InfoLog - - // Inputs - string Source - ref!BinaryExtra Binary // Takes precedence over Source if set -} - -@post_fence -extern ref!CompileShaderExtra GetCompileShaderExtra(ref!Context ctx, ref!Shader p, ref!BinaryExtra binary) - -sub void ApplyCompileShaderExtra(ref!Shader s, ref!CompileShaderExtra i) { - if i != null { - assert(s != null) - s.CompileExtra = i - s.CompileStatus = i.CompileStatus - s.InfoLog = i.InfoLog - } -} - -@internal -class BinaryExtra { - u8[] Data // Binary blob - GLenum Format // Vendor-specific format - GLsizei Count // Number of binaries stored in the blob - GLsizei Index // Index of the binary that we are referencing -} - -@internal -@resource -class Program { - @unused ProgramId ID - map!(GLenum, ref!Shader) Shaders - ref!ActiveProgramResources ActiveResources - map!(UniformLocation, Uniform) UniformLocations - GLboolean LinkStatus - bool ValidateStatus - @unused string InfoLog - ref!ShaderLayoutQualifiers ShaderLayout - @unused map!(string, AttributeLocation) AttributeBindings - map!(u32, string) TransformFeedbackVaryings - GLenum TransformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS - bool Separable = false - bool BinaryRetrievableHint = false - bool DeleteStatus - @unused string Label - s32 UseCount - - @hidden ref!LinkProgramExtra LinkExtra // Describes last link command - @hidden ref!LinkProgramExtra SuccessfulLinkExtra // Describes last successful link command - @hidden ref!ValidateProgramExtra ValidateExtra // Describes last validate command -} - -// Extra describing program link including both the inputs and outputs. -// We need to store copy of compile-time inputs for mid-execution capture, -// because changing the inputs does not change the compiled program code. -@internal -class LinkProgramExtra { - ProgramId ID - - // Outputs - GLboolean LinkStatus - string InfoLog - ref!ActiveProgramResources ActiveResources - ref!ShaderLayoutQualifiers ShaderLayout - - // Inputs - map!(GLenum, ref!CompileShaderExtra) Shaders - ref!BinaryExtra Binary // Takes precedence over Shaders if set - map!(string, AttributeLocation) AttributeBindings - map!(u32, string) TransformFeedbackVaryings - GLenum TransformFeedbackBufferMode - bool Separable - bool BinaryRetrievableHint -} - -@post_fence -extern ref!LinkProgramExtra GetLinkProgramExtra(ref!Context ctx, ref!Program p, ref!BinaryExtra binary) - -sub void ApplyLinkProgramExtra(ref!Program p, ref!LinkProgramExtra i) { - if i != null { - assert(p != null) - if i.LinkStatus == GL_TRUE { - // We need to keep track of the last successful link, - // since it remains in effect at any binding points. - p.SuccessfulLinkExtra = i - } - p.LinkExtra = i - p.LinkStatus = i.LinkStatus - p.InfoLog = i.InfoLog - p.ActiveResources = i.ActiveResources - p.ShaderLayout = i.ShaderLayout - - // Memorize the exact state of shaders at link time. - // Use the reference object from our state rather than the cloned copy. - // This saves a little spaces and avoids MEC complaining about the clone. - p.LinkExtra.Shaders = null - for _, k, v in p.Shaders { - p.LinkExtra.Shaders[k] = v.CompileExtra - } - - // Set uniform values to default (zeroed) - p.UniformLocations = null - if i.LinkStatus == GL_TRUE { - for _, uniformIndex, uniform in i.ActiveResources.DefaultUniformBlock { - elementInfo := GetUniformTypeInfo(uniform.Type) - elementSize := elementInfo.primitiveSize * elementInfo.vectorSize * elementInfo.vectorCount - values := make!u8(elementSize * as!u32(uniform.ArraySize)) - // Each element of the array is assigned a location by compiler. - // The location acts as a handle. Locations do not have to be consecutive. - for _, elementIndex, loc in uniform.Locations { - if (loc != -1) { - assert(elementIndex < as!u32(uniform.ArraySize)) - offset := elementIndex * elementSize - p.UniformLocations[as!UniformLocation(loc)] = Uniform( - Type: uniform.Type, - Value: values[offset:offset + elementSize], - Values: values[offset:len(values)], - UniformIndex: uniformIndex - ) - } - } - uniform.Value = values - } - } - } -} - -@internal -class Uniform { - @unused GLenum Type - @internal u8[] Value - @hidden @internal u8[] Values // Includes this uniform and any following array-elements - UniformIndex UniformIndex // Reference back to ProgramResource (not location) -} - -@internal -class ValidateProgramExtra { - ProgramId ID - bool ValidateStatus - string InfoLog -} - -@post_fence -extern ref!ValidateProgramExtra GetValidateProgramExtra(ref!Context ctx, ref!Program p) - -sub void ApplyValidateProgramExtra(ref!Program p, ref!ValidateProgramExtra i) { - if i != null { - p.ValidateStatus = i.ValidateStatus - p.InfoLog = i.InfoLog - } -} - -@internal -class Pipeline { - PipelineId ID - - // Table 21.20: Program Pipeline Object State - ref!Program ActiveProgram - ref!Program VertexShader - ref!Program TessControlShader - ref!Program TessEvaluationShader - ref!Program GeometryShader - ref!Program FragmentShader - ref!Program ComputeShader - bool ValidateStatus - string InfoLog - string Label - - @hidden ref!ValidateProgramPipelineExtra ValidateExtra // Describes last validate command -} - -@internal -class ValidateProgramPipelineExtra { - PipelineId ID - bool ValidateStatus - string InfoLog -} - -@post_fence -extern ref!ValidateProgramPipelineExtra GetValidateProgramPipelineExtra(ref!Context ctx, ref!Pipeline p) - -sub void ApplyValidateProgramPipelineExtra(ref!Pipeline p, ref!ValidateProgramPipelineExtra i) { - if i != null { - p.ValidateStatus = i.ValidateStatus - p.InfoLog = i.InfoLog - } -} - -@internal -class ActiveProgramResources { - @unused map!(u32, ref!ProgramResource) ProgramInputs - @unused map!(u32, ref!ProgramResource) ProgramOutputs - @unused map!(u32, ref!ProgramResource) Uniforms - @unused map!(UniformIndex, ref!ProgramResource) DefaultUniformBlock - @unused map!(u32, ref!ProgramResourceBlock) UniformBlocks - @unused map!(u32, ref!ProgramResourceBlock) AtomicCounterBuffers - @unused map!(u32, ref!ProgramResource) BufferVariables - @unused map!(u32, ref!ProgramResourceBlock) ShaderStorageBlocks - @unused map!(u32, ref!ProgramResource) TransformFeedbackVaryings -} - -@internal -class ProgramResourceBlock { - @unused string Name - @unused GLint Binding - @unused GLint DataSize - @unused ref!ProgramResourceUses ReferencedBy // May be null if unknown (older GL versions) - @unused map!(u32, ref!ProgramResource) Resources -} - -@internal -class ProgramResource { - @unused string Name - @unused GLenum Type - @unused u8[] Value - @unused GLint ArraySize = 1 // Number of active array elements (can be less than declared) - @unused map!(u32,GLint) Locations // Location of array elements (can be non-consecutive) - @unused @hidden GLint BlockIndex = -1 // Hidden as it is implied by the owning container - @unused @hidden GLint AtomicCounterBufferIndex = -1 // Hidden as it is implied by the owning container - @unused @hidden bool IsPerPatch // Hidden to reduce noise - - @unused ref!ProgramResourceUses ReferencedBy // May be null if unknown or not applicable - @unused ref!ProgramResourceLayout Layout // May be null if unknown or not applicable -} - -@internal -class ProgramResourceUses { - @unused bool VertexShader - @unused bool TessControlShader - @unused bool TessEvaluationShader - @unused bool GeometryShader - @unused bool FragmentShader - @unused bool ComputeShader -} - -@internal -class ProgramResourceLayout { - @unused GLint Offset = -1 - @unused GLint ArrayStride = -1 - @unused GLint MatrixStride = -1 - @unused bool IsRowMajor - @unused GLint TopLevelArraySize = 0 - @unused GLint TopLevelArrayStride = 0 -} - -@internal -class ShaderLayoutQualifiers { - @unused GLuint GeometryVerticesOut = 0 - @unused GLenum GeometryInputType = GL_TRIANGLES - @unused GLenum GeometryOutputType = GL_TRIANGLE_STRIP - @unused GLuint GeometryShaderInvocations = 1 - - @unused GLuint TessControlOutputVertices = 0 - @unused GLenum TessGenMode = GL_QUADS - @unused GLenum TessGenSpacing = GL_EQUAL - @unused GLenum TessGenVertexOrder = GL_CCW - @unused bool TessGenPointMode = false - - @unused GLuint[3] ComputeWorkGroupSize -} - -sub ref!Pipeline GetOrCreatePipelineOrError(PipelineId id) { - ctx := GetContext() - if ctx.Objects.Pipelines[id] == null { - if ctx.Objects.GeneratedNames.Pipelines[id] { - ctx.Objects.Pipelines[id] = new!Pipeline(ID: id) - } else { - glErrorInvalidOperation_ObjectDoesNotExist!PipelineId(id) - } - } - return ctx.Objects.Pipelines[id] -} - -sub string readString(GLsizei length, const GLchar* buffer, bool consider_zero_length_nt) { - chars := as!(const char*)(buffer) - return switch buffer != null { - case true: { - // Negative length implies null-terminated string - switch (length < 0) || (consider_zero_length_nt && length == 0) { - case true: as!string(chars) - case false: as!string(chars[0:length]) - } - } - case false: as!string(null) - } -} - -sub void writeString(GLsizei buffer_size, - GLsizei* buffer_bytes_written, - GLchar* buffer) { - if (buffer != null) && (buffer_size > 0) { - if buffer_bytes_written != null { - length := as!GLsizei(?) - buffer_bytes_written[0] = length // Excluding null-terminator - write(buffer[0:length + 1]) // Including null-terminator - } else { - write(buffer[0:buffer_size]) - } - } -} - -sub ref!Shader GetShaderOrError(ShaderId shader) { - ctx := GetContext() - s := ctx.Objects.Shaders[shader] - if s == null { - if !(as!ProgramId(shader) in ctx.Objects.Programs) { glErrorInvalidObjectName!ShaderId(shader) } - glErrorInvalidOperation() - } - return s -} - -sub ref!Program GetProgramOrError(ProgramId program) { - ctx := GetContext() - p := ctx.Objects.Programs[program] - if p == null { - if !(as!ShaderId(program) in ctx.Objects.Shaders) { glErrorInvalidValue!ProgramId(program) } - glErrorInvalidOperation() - } - return p -} - -sub void AdjustShaderAttachCount(ref!Shader s, s32 delta) { - ctx := GetContext() - if s != null { - s.AttachCount += delta - assert(s.AttachCount >= 0) - // Delete if it was marked for deletion and it is no longer attached anywhere - if s.DeleteStatus && (s.AttachCount == 0) { - delete(ctx.Objects.Shaders, s.ID) - } - } -} - -sub void AdjustProgramUseCount(ref!Program p, s32 delta) { - ctx := GetContext() - if p != null { - p.UseCount += delta - assert(p.UseCount >= 0) - // Delete if it was marked for deletion and it is no longer used anywhere - if p.DeleteStatus && (p.UseCount == 0) { - for _ , _ , s in p.Shaders { - AdjustShaderAttachCount(s, -1) - } - delete(ctx.Objects.Programs, p.ID) - } - } -} - -// Returns the slice to the uniform's value. It can be used to read/write the value. -// If the uniform is an array, it includes the "overflow" until the end of array. -// It handles locations witch are in mid-array and non-consecutive array locations. -// Matrices in this slice should be always stored in default (column major) order. -@internal sub T[] ProgramUniformValue!T(ref!Program p, UniformLocation loc, GLenum type) { - if p == null { glErrorInvalidOperation() } - if !(loc in p.UniformLocations) { glErrorInvalidOperation() } - // TODO: Check that the type is compatible with the type declared in the shader. - values := as!T[](p.UniformLocations[loc].Values) - if len(values) == 0 { glErrorInvalidOperation() } - return values -} - -sub void SetProgramUniform!T(ProgramId p, UniformLocation loc, T value, GLenum type) { - if loc != -1 { - ProgramUniformValue!T(GetProgramOrError(p), loc, type)[0] = value - } -} - -sub void SetProgramUniformv!T(ProgramId p, UniformLocation loc, T[] values, GLenum type) { - if loc != -1 { - copy(ProgramUniformValue!T(GetProgramOrError(p), loc, type), values) - } -} - -sub void SetProgramUniformMatrixv!T(ProgramId p, UniformLocation loc, GLboolean t, T[] values, GLenum type) { - // TODO: transpose values if the flag is set - if loc != -1 { - copy(ProgramUniformValue!T(GetProgramOrError(p), loc, type), values) - } -} - -sub void SetUniform!T(UniformLocation loc, T value, GLenum type) { - if loc != -1 { - ProgramUniformValue!T(GetContext().Bound.Program, loc, type)[0] = value - } -} - -sub void SetUniformv!T(UniformLocation loc, T[] values, GLenum type) { - if loc != -1 { - copy(ProgramUniformValue!T(GetContext().Bound.Program, loc, type), values) - } -} - -sub void SetUniformMatrixv!T(UniformLocation loc, GLboolean t, T[] values, GLenum type) { - // TODO: transpose values if the flag is set - if loc != -1 { - copy(ProgramUniformValue!T(GetContext().Bound.Program, loc, type), values) - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glActiveShaderProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glActiveShaderProgram.xhtml", Version.GLES32) -cmd void glActiveShaderProgram(PipelineId pipeline, ProgramId program) { - pipe := GetOrCreatePipelineOrError(pipeline) - if program == 0 { - pipe.ActiveProgram = null - } else { - pipe.ActiveProgram = GetProgramOrError(program) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glAttachShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glAttachShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glAttachShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glAttachShader.xhtml", Version.GLES32) -cmd void glAttachShader(ProgramId program, ShaderId shader) { - - s := GetShaderOrError(shader) - p := GetProgramOrError(program) - if s.Type in p.Shaders { glErrorInvalidOperation() } // shader already attached - p.Shaders[s.Type] = s - AdjustShaderAttachCount(s, +1) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindAttribLocation.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindAttribLocation.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindAttribLocation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindAttribLocation.xhtml", Version.GLES32) -cmd void glBindAttribLocation(ProgramId program, AttributeLocation location, const GLchar* name) { - n := as!string(as!char*(name)) - if (len(n) > 2) && (as!string(as!char*(name)[0:3]) == "gl_") { glErrorInvalidOperation() } - p := GetProgramOrError(program) - CheckAttributeLocation(location) - p.AttributeBindings[n] = location -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindProgramPipeline.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindProgramPipeline.xhtml", Version.GLES32) -cmd void glBindProgramPipeline(PipelineId pipeline) { - ctx := GetContext() - if pipeline == 0 { - ctx.Bound.Pipeline = null - } else { - ctx.Bound.Pipeline = GetOrCreatePipelineOrError(pipeline) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCompileShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCompileShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCompileShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCompileShader.xhtml", Version.GLES32) -cmd void glCompileShader(ShaderId shader) { - ctx := GetContext() - s := GetShaderOrError(shader) - _ = s.Source - ApplyCompileShaderExtra(s, GetCompileShaderExtra(ctx, s, null)) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCreateProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCreateProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCreateProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCreateProgram.xhtml", Version.GLES32) -cmd ProgramId glCreateProgram() { - ctx := GetContext() - id := ? - ctx.Objects.Programs[id] = new!Program(ID: id) - return id -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCreateShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCreateShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCreateShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCreateShader.xhtml", Version.GLES32) -cmd ShaderId glCreateShader(GLenum type) { - switch (type) { - case GL_FRAGMENT_SHADER, GL_VERTEX_SHADER: { - // version 2.0 - } - @if(Version.GLES31) - case GL_COMPUTE_SHADER: { - } - @if(Version.GLES32) - case GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER: { - } - default: { - glErrorInvalidEnum(type) - } - } - - ctx := GetContext() - id := ? - ctx.Objects.Shaders[id] = new!Shader(ID: id, Type: type) - return id -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCreateShaderProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCreateShaderProgram.xhtml", Version.GLES32) -cmd ProgramId glCreateShaderProgramv(GLenum type, GLsizei count, const GLchar* const* strings) { - switch (type) { - case GL_COMPUTE_SHADER, GL_FRAGMENT_SHADER, GL_VERTEX_SHADER: { - // version 3.1 - } - @if(Version.GLES32) - case GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER: { - } - default: { - glErrorInvalidEnum(type) - } - } - sources := strings[0:count] - for i in (0 .. count) { - _ = as!string(as!char*(sources[i])) - } - ctx := GetContext() - id := ? - ctx.Objects.Programs[id] = new!Program(ID: id, Separable: true) - // TODO: Program link info - return id -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteProgram.xhtml", Version.GLES32) -cmd void glDeleteProgram(ProgramId program) { - if program != 0 { - p := GetProgramOrError(program) - p.DeleteStatus = true - AdjustProgramUseCount(p, 0) // Do not change the count, just check if it can be deleted now. - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteProgramPipelines.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteProgramPipelines.xhtml", Version.GLES32) -cmd void glDeleteProgramPipelines(GLsizei n, const PipelineId* pipelines) { - DeleteProgramPipelines(n, pipelines) -} - -sub void DeleteProgramPipelines(GLsizei count, const PipelineId* pipelines) { - CheckCountGE!GLsizei(count, 0) - ids := pipelines[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := ids[i] - if id != 0 { - delete(ctx.Objects.Pipelines, id) - delete(ctx.Objects.GeneratedNames.Pipelines, id) - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteShader.xhtml", Version.GLES32) -cmd void glDeleteShader(ShaderId shader) { - if shader != 0 { - s := GetShaderOrError(shader) - s.DeleteStatus = true - AdjustShaderAttachCount(s, 0) // Do not change the count, just check if it can be deleted now. - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDetachShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDetachShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDetachShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDetachShader.xhtml", Version.GLES32) -cmd void glDetachShader(ProgramId program, ShaderId shader) { - - s := GetShaderOrError(shader) - p := GetProgramOrError(program) - - if (!(s.Type in p.Shaders)) || (p.Shaders[s.Type] != s) { glErrorInvalidOperation() } - delete(p.Shaders, s.Type) - AdjustShaderAttachCount(s, -1) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDispatchCompute.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDispatchCompute.xhtml", Version.GLES32) -cmd void glDispatchCompute(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z) { - // TODO -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDispatchComputeIndirect.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDispatchComputeIndirect.xhtml", Version.GLES32) -cmd void glDispatchComputeIndirect(GLintptr indirect) { - // TODO -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenProgramPipelines.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenProgramPipelines.xhtml", Version.GLES32) -cmd void glGenProgramPipelines(GLsizei count, PipelineId* pipelines) { - GenProgramPipelines(count, pipelines) -} - -sub void GenProgramPipelines(GLsizei count, PipelineId* pipelines) { - CheckCountGE!GLsizei(count, 0) - t := pipelines[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!PipelineId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Pipelines[id] = true - t[i] = id - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetActiveAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetActiveAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetActiveAttrib.xhtml", Version.GLES32) -cmd void glGetActiveAttrib(ProgramId program, - AttributeIndex index, - GLsizei buffer_size, - GLsizei* buffer_bytes_written, - GLint* vector_count, - GLenum* type, - GLchar* name) { - - CheckSizeGE!GLsizei(buffer_size, 0) - - p := GetProgramOrError(program) - if !(as!u32(index) in p.ActiveResources.ProgramInputs) { glErrorInvalidValue!AttributeIndex(index) } - - writeString(buffer_size, buffer_bytes_written, name) - - vector_count[0] = as!GLint(?) - type[0] = as!GLenum(?) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetActiveUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetActiveUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetActiveUniform.xhtml", Version.GLES32) -cmd void glGetActiveUniform(ProgramId program, - UniformIndex index, - GLsizei buffer_size, - GLsizei* buffer_bytes_written, - GLint* vector_count, - GLenum* type, - GLchar* name) { - - p := GetProgramOrError(program) - CheckSizeGE!GLsizei(buffer_size, 0) - if !(as!u32(index) in p.ActiveResources.Uniforms) { glErrorInvalidValue!UniformIndex(index) } - - writeString(buffer_size, buffer_bytes_written, name) - - vector_count[0] = as!GLint(?) - type[0] = as!GLenum(?) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveUniformBlockName.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetActiveUniformBlockName.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetActiveUniformBlockName.xhtml", Version.GLES32) -cmd void glGetActiveUniformBlockName(ProgramId program, - UniformBlockIndex uniform_block_index, - GLsizei buffer_size, - GLsizei* buffer_bytes_written, - GLchar* name) { - - writeString(buffer_size, buffer_bytes_written, name) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveUniformBlockiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetActiveUniformBlockiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetActiveUniformBlockiv.xhtml", Version.GLES32) -cmd void glGetActiveUniformBlockiv(ProgramId program, - UniformBlockIndex uniform_block_index, - GLenum parameter_name, - GLint* parameters) { - switch (parameter_name) { - case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, - GL_UNIFORM_BLOCK_BINDING, GL_UNIFORM_BLOCK_DATA_SIZE, GL_UNIFORM_BLOCK_NAME_LENGTH, - GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, - GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: { - // version 3.0 - } - default: { - glErrorInvalidEnum(parameter_name) - } - } - - parameters[0] = ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetActiveUniformsiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetActiveUniformsiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetActiveUniformsiv.xhtml", Version.GLES32) -cmd void glGetActiveUniformsiv(ProgramId program, - GLsizei uniform_count, - const UniformIndex* uniform_indices, - GLenum parameter_name, - GLint* parameters) { - switch (parameter_name) { - case GL_UNIFORM_ARRAY_STRIDE, GL_UNIFORM_BLOCK_INDEX, GL_UNIFORM_IS_ROW_MAJOR, - GL_UNIFORM_MATRIX_STRIDE, GL_UNIFORM_NAME_LENGTH, GL_UNIFORM_OFFSET, GL_UNIFORM_SIZE, - GL_UNIFORM_TYPE: { - // version 3.0 - } - default: { - glErrorInvalidEnum(parameter_name) - } - } - - read(uniform_indices[0:uniform_count]) - write(parameters[0:uniform_count]) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetAttachedShaders.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetAttachedShaders.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetAttachedShaders.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetAttachedShaders.xhtml", Version.GLES32) -cmd void glGetAttachedShaders(ProgramId program, - GLsizei buffer_length, - GLsizei* shaders_length_written, - ShaderId* shaders) { - - p := GetProgramOrError(program) - CheckGE!GLsizei(buffer_length, 0) - l := min!s32(as!s32(buffer_length), len(p.Shaders)) - if shaders_length_written != null { - shaders_length_written[0] = as!GLsizei(l) - } - - s := shaders[0:l] - for i , _ , v in p.Shaders { - if i < l { - s[i] = v.ID - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetAttribLocation.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetAttribLocation.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetAttribLocation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetAttribLocation.xhtml", Version.GLES32) -cmd GLint glGetAttribLocation(ProgramId program, const GLchar* name) { - _ = as!string(as!char*(name)) - // The HTML and PDF give different error codes. This matches the PDF. - _ = GetProgramOrError(program) - return ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetFragDataLocation.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetFragDataLocation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetFragDataLocation.xhtml", Version.GLES32) -cmd GLint glGetFragDataLocation(ProgramId program, const GLchar* name) { - _ = as!string(as!char*(name)) - _ = GetProgramOrError(program) - return ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetProgramBinary.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramBinary.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramBinary.xhtml", Version.GLES32) -cmd void glGetProgramBinary(ProgramId program, - GLsizei bufSize, - GLsizei* length, - GLenum* binaryFormat, - void* binary) { - GetProgramBinary(program, bufSize, length, binaryFormat, binary) -} - -sub void GetProgramBinary(ProgramId program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary) { - _ = program // TODO: Not needed? Remove from signature. - if length != null { - l := as!GLsizei(?) - length[0] = l - write(binary[0:l]) - } else { - write(binary[0:bufSize]) - } - binaryFormat[0] = ? -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetProgramInfoLog.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetProgramInfoLog.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramInfoLog.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramInfoLog.xhtml", Version.GLES32) -cmd void glGetProgramInfoLog(ProgramId program, - GLsizei buffer_length, - GLsizei* string_length_written, - GLchar* info) { - _ = GetProgramOrError(program) - CheckGE!GLsizei(buffer_length, 0) - writeString(buffer_length, string_length_written, info) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramInterface.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramInterface.xhtml", Version.GLES32) -cmd void glGetProgramInterfaceiv(ProgramId program, - GLenum programInterface, - GLenum pname, - GLint* params) { - switch (programInterface) { - case GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT, - GL_SHADER_STORAGE_BLOCK, GL_TRANSFORM_FEEDBACK_BUFFER, GL_TRANSFORM_FEEDBACK_VARYING, - GL_UNIFORM, GL_UNIFORM_BLOCK: { - // version 3.1 - } - default: { - glErrorInvalidEnum(programInterface) - } - } - switch (pname) { - case GL_ACTIVE_RESOURCES, GL_MAX_NAME_LENGTH, GL_MAX_NUM_ACTIVE_VARIABLES: { - // version 3.1 - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - params[0] = ? -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramPipelineInfoLog.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramPipelineInfoLog.xhtml", Version.GLES32) -cmd void glGetProgramPipelineInfoLog(PipelineId pipeline, - GLsizei bufSize, - GLsizei* length, - GLchar* infoLog) { - writeString(bufSize, length, infoLog) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramPipeline.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramPipeline.xhtml", Version.GLES32) -cmd void glGetProgramPipelineiv(PipelineId pipeline, GLenum pname, GLint* params) { - switch (pname) { - case GL_ACTIVE_PROGRAM, GL_COMPUTE_SHADER, GL_FRAGMENT_SHADER, GL_INFO_LOG_LENGTH, - GL_VALIDATE_STATUS, GL_VERTEX_SHADER: { - // version 3.1 - } - @if(Version.GLES32) - case GL_GEOMETRY_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER: { - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - params[0] = ? -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramResourceIndex.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramResourceIndex.xhtml", Version.GLES32) -cmd GLuint glGetProgramResourceIndex(ProgramId program, - GLenum programInterface, - const GLchar* name) { - _ = as!string(as!char*(name)) - switch (programInterface) { - case GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT, GL_SHADER_STORAGE_BLOCK, - GL_TRANSFORM_FEEDBACK_VARYING, GL_UNIFORM, GL_UNIFORM_BLOCK: { - // version 3.1 - } - default: { - glErrorInvalidEnum(programInterface) - } - } - // TODO - return ? -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramResourceLocation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramResourceLocation.xhtml", Version.GLES32) -cmd GLint glGetProgramResourceLocation(ProgramId program, - GLenum programInterface, - const GLchar* name) { - _ = as!string(as!char*(name)) - switch (programInterface) { - case GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT, GL_TRANSFORM_FEEDBACK_BUFFER, GL_UNIFORM: { - // version 3.1 - } - default: { - glErrorInvalidEnum(programInterface) - } - } - // TODO - return ? -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramResourceName.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramResourceName.xhtml", Version.GLES32) -cmd void glGetProgramResourceName(ProgramId program, - GLenum programInterface, - GLuint index, - GLsizei bufSize, - GLsizei* length, - GLchar* name) { - switch (programInterface) { - case GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT, GL_SHADER_STORAGE_BLOCK, - GL_TRANSFORM_FEEDBACK_VARYING, GL_UNIFORM, GL_UNIFORM_BLOCK: { - // version 3.1 - } - default: { - glErrorInvalidEnum(programInterface) - } - } - writeString(bufSize, length, name) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramResource.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramResource.xhtml", Version.GLES32) -cmd void glGetProgramResourceiv(ProgramId program, - GLenum programInterface, - GLuint index, - GLsizei propCount, - const GLenum* props, - GLsizei bufSize, - GLsizei* length, - GLint* params) { - switch (programInterface) { - case GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT, GL_PROGRAM_OUTPUT, - GL_SHADER_STORAGE_BLOCK, GL_TRANSFORM_FEEDBACK_BUFFER, GL_TRANSFORM_FEEDBACK_VARYING, - GL_UNIFORM, GL_UNIFORM_BLOCK: { - // version 3.1 - } - default: { - glErrorInvalidEnum(programInterface) - } - } - // TODO - read(props[0:propCount]) - if length != null { - l := as!GLsizei(?) - length[0] = l - write(params[0:l]) - } else { - write(params[0:bufSize]) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetProgramiv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetProgramiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetProgramiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetProgramiv.xhtml", Version.GLES32) -cmd void glGetProgramiv(ProgramId program, GLenum parameter, GLint* value) { - switch (parameter) { - case GL_ACTIVE_ATTRIBUTES, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, GL_ACTIVE_UNIFORMS, - GL_ACTIVE_UNIFORM_MAX_LENGTH, GL_ATTACHED_SHADERS, GL_DELETE_STATUS, GL_INFO_LOG_LENGTH, - GL_LINK_STATUS, GL_VALIDATE_STATUS: { - // version 2.0 - } - @if(Version.GLES30) - case GL_ACTIVE_UNIFORM_BLOCKS, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, - GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, - GL_TRANSFORM_FEEDBACK_VARYINGS, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: { - } - @if(Version.GLES30) - case GL_PROGRAM_BINARY_LENGTH: { - // TODO: Missing from online man pages. - } - @if(Version.GLES31) - case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, GL_COMPUTE_WORK_GROUP_SIZE, GL_PROGRAM_SEPARABLE: { - } - @if(Version.GLES32) - case GL_GEOMETRY_INPUT_TYPE, GL_GEOMETRY_OUTPUT_TYPE, - GL_GEOMETRY_VERTICES_OUT, GL_GEOMETRY_SHADER_INVOCATIONS, - GL_TESS_CONTROL_OUTPUT_VERTICES, GL_TESS_GEN_MODE, GL_TESS_GEN_POINT_MODE, - GL_TESS_GEN_SPACING, GL_TESS_GEN_VERTEX_ORDER: { - } - default: { - glErrorInvalidEnum(parameter) - } - } - _ = GetProgramOrError(program) - - value[0] = ? -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderInfoLog.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderInfoLog.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetShaderInfoLog.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetShaderInfoLog.xhtml", Version.GLES32) -cmd void glGetShaderInfoLog(ShaderId shader, - GLsizei buffer_length, - GLsizei* string_length_written, - GLchar* info) { - _ = GetShaderOrError(shader) - CheckGE!GLsizei(buffer_length, 0) - writeString(buffer_length, string_length_written, info) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderPrecisionFormat.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderPrecisionFormat.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetShaderPrecisionFormat.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetShaderPrecisionFormat.xhtml", Version.GLES32) -cmd void glGetShaderPrecisionFormat(GLenum shader_type, - GLenum precision_type, - GLint* range, - GLint* precision) { - switch (shader_type) { - case GL_FRAGMENT_SHADER, GL_VERTEX_SHADER: { - // version 2.0 - } - default: { - glErrorInvalidEnum(shader_type) - } - } - switch (precision_type) { - case GL_HIGH_FLOAT, GL_HIGH_INT, GL_LOW_FLOAT, GL_LOW_INT, GL_MEDIUM_FLOAT, GL_MEDIUM_INT: { - // version 2.0 - } - default: { - glErrorInvalidEnum(precision_type) - } - } - - write(range[0:2]) - precision[0] = ? -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderSource.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderSource.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetShaderSource.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetShaderSource.xhtml", Version.GLES32) -cmd void glGetShaderSource(ShaderId shader, - GLsizei buffer_length, - GLsizei* string_length_written, - GLchar* source) { - _ = GetShaderOrError(shader) - CheckGE!GLsizei(buffer_length, 0) - // TODO: Handle properly. Mind the null-terminator. - writeString(buffer_length, string_length_written, source) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetShaderiv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetShaderiv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetShaderiv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetShaderiv.xhtml", Version.GLES32) -cmd void glGetShaderiv(ShaderId shader, GLenum parameter, GLint* value) { - switch (parameter) { - case GL_COMPILE_STATUS, GL_DELETE_STATUS, GL_INFO_LOG_LENGTH, GL_SHADER_SOURCE_LENGTH, - GL_SHADER_TYPE: { - // version 2.0 - } - default: { - glErrorInvalidEnum(parameter) - } - } - - s := GetShaderOrError(shader) - value[0] = switch (parameter) { - case GL_SHADER_TYPE: as!GLint(s.Type) - case GL_DELETE_STATUS: switch (s.DeleteStatus) { case true: 1 case false: 0 } - case GL_COMPILE_STATUS: switch (s.CompileStatus) { case true: 1 case false: 0 } - case GL_INFO_LOG_LENGTH: as!GLint(len(s.InfoLog)) - case GL_SHADER_SOURCE_LENGTH: as!GLint(len(s.Source)) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniformBlockIndex.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniformBlockIndex.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniformBlockIndex.xhtml", Version.GLES32) -cmd UniformBlockIndex glGetUniformBlockIndex(ProgramId program, const GLchar* uniformBlockName) { - _ = as!string(as!char*(uniformBlockName)) - // TODO - return ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniformIndices.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniformIndices.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniformIndices.xhtml", Version.GLES32) -cmd void glGetUniformIndices(ProgramId program, - GLsizei uniformCount, - const GLchar* const* uniformNames, - UniformIndex* uniformIndices) { - names := uniformNames[0:uniformCount] - for i in (0 .. uniformCount) { - _ = as!string(as!char*(names[i])) - } - write(uniformIndices[0:uniformCount]) - // TODO -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetUniformLocation.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniformLocation.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniformLocation.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniformLocation.xhtml", Version.GLES32) -cmd UniformLocation glGetUniformLocation(ProgramId program, const GLchar* name) { - _ = as!string(as!char*(name)) - _ = GetProgramOrError(program) - return ? -} - -sub void GetUniformv!T(ProgramId program, UniformLocation location, T values) { - _ = GetProgramOrError(program) - // TODO: Determine size based on uniform type. - _ = program // TODO - _ = location // TODO - write(values[0:16]) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetUniformfv(ProgramId program, UniformLocation location, GLfloat* values) { - GetUniformv!GLfloat*(program, location, values) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetUniformiv(ProgramId program, UniformLocation location, GLint* values) { - GetUniformv!GLint*(program, location, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetUniformuiv(ProgramId program, UniformLocation location, GLuint* values) { - GetUniformv!GLuint*(program, location, values) -} - -sub void GetnUniformfv!T(ProgramId program, - UniformLocation location, - GLsizei bufSize, // bytes - T values) { - _ = program // TODO: Use or lose. - _ = location // TODO: Use or lose. - write(as!char*(values)[0:bufSize]) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetnUniformfv(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLfloat* values) { - GetnUniformfv!GLfloat*(program, location, bufSize, values) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetnUniformiv(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLint* values) { - GetnUniformiv(program, location, bufSize, values) -} - -sub void GetnUniformiv(ProgramId program, UniformLocation location, GLsizei bufSize, GLint* values) { - GetnUniformfv!GLint*(program, location, bufSize, values) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetUniform.xhtml", Version.GLES32) -cmd void glGetnUniformuiv(ProgramId program, - UniformLocation location, - GLsizei bufSize, - GLuint* values) { - GetnUniformuiv(program, location, bufSize, values) -} - -sub void GetnUniformuiv(ProgramId program, UniformLocation location, GLsizei bufSize, GLuint* values) { - GetnUniformfv!GLuint*(program, location, bufSize, values) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsProgram.xhtml", Version.GLES32) -cmd GLboolean glIsProgram(ProgramId program) { - ctx := GetContext() - return toGLboolean(program in ctx.Objects.Programs) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsProgramPipeline.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsProgramPipeline.xhtml", Version.GLES32) -cmd GLboolean glIsProgramPipeline(PipelineId pipeline) { - ctx := GetContext() - return toGLboolean(pipeline in ctx.Objects.Pipelines) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsShader.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsShader.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsShader.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsShader.xhtml", Version.GLES32) -cmd GLboolean glIsShader(ShaderId shader) { - ctx := GetContext() - return toGLboolean(shader in ctx.Objects.Shaders) -} - -@if(Version.GLES20) -@custom -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glLinkProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glLinkProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glLinkProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glLinkProgram.xhtml", Version.GLES32) -cmd void glLinkProgram(ProgramId program) { - p := GetProgramOrError(program) - for _, _, attributeLocation in p.AttributeBindings { - _ = attributeLocation - } - ctx := GetContext() - ApplyLinkProgramExtra(p, GetLinkProgramExtra(ctx, p, null)) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glMemoryBarrier.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glMemoryBarrier.xhtml", Version.GLES32) -cmd void glMemoryBarrier(GLbitfield barriers) { - supportsBits(barriers, GL_ALL_BARRIER_BITS | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) - if (GL_ALL_BARRIER_BITS in barriers) { - } - if (GL_ATOMIC_COUNTER_BARRIER_BIT in barriers) { - } - if (GL_BUFFER_UPDATE_BARRIER_BIT in barriers) { - } - if (GL_COMMAND_BARRIER_BIT in barriers) { - } - if (GL_ELEMENT_ARRAY_BARRIER_BIT in barriers) { - } - if (GL_FRAMEBUFFER_BARRIER_BIT in barriers) { - } - if (GL_PIXEL_BUFFER_BARRIER_BIT in barriers) { - } - if (GL_SHADER_IMAGE_ACCESS_BARRIER_BIT in barriers) { - } - if (GL_SHADER_STORAGE_BARRIER_BIT in barriers) { - } - if (GL_TEXTURE_FETCH_BARRIER_BIT in barriers) { - } - if (GL_TEXTURE_UPDATE_BARRIER_BIT in barriers) { - } - if (GL_TRANSFORM_FEEDBACK_BARRIER_BIT in barriers) { - } - if (GL_UNIFORM_BARRIER_BIT in barriers) { - } - if (GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT in barriers) { - } - // TODO -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glMemoryBarrier.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glMemoryBarrier.xhtml", Version.GLES32) -cmd void glMemoryBarrierByRegion(GLbitfield barriers) { - supportsBits(barriers, GL_ALL_BARRIER_BITS | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT | GL_TRANSFORM_FEEDBACK_BARRIER_BIT | GL_UNIFORM_BARRIER_BIT | GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) - if (GL_ALL_BARRIER_BITS in barriers) { - } - if (GL_ATOMIC_COUNTER_BARRIER_BIT in barriers) { - } - if (GL_BUFFER_UPDATE_BARRIER_BIT in barriers) { - } - if (GL_COMMAND_BARRIER_BIT in barriers) { - } - if (GL_ELEMENT_ARRAY_BARRIER_BIT in barriers) { - } - if (GL_FRAMEBUFFER_BARRIER_BIT in barriers) { - } - if (GL_PIXEL_BUFFER_BARRIER_BIT in barriers) { - } - if (GL_SHADER_IMAGE_ACCESS_BARRIER_BIT in barriers) { - } - if (GL_SHADER_STORAGE_BARRIER_BIT in barriers) { - } - if (GL_TEXTURE_FETCH_BARRIER_BIT in barriers) { - } - if (GL_TEXTURE_UPDATE_BARRIER_BIT in barriers) { - } - if (GL_TRANSFORM_FEEDBACK_BARRIER_BIT in barriers) { - } - if (GL_UNIFORM_BARRIER_BIT in barriers) { - } - if (GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT in barriers) { - } - // TODO -} - -@if(Version.GLES30) -@custom -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glProgramBinary.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramBinary.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramBinary.xhtml", Version.GLES32) -cmd void glProgramBinary(ProgramId program, - GLenum binaryFormat, - const void* binary, - GLsizei length) { - ProgramBinary(program, binaryFormat, binary, length) -} - -sub void ProgramBinary(ProgramId program, GLenum format, const void* binary, GLsizei length) { - ctx := GetContext() - p := GetProgramOrError(program) - data := clone(as!u8[](binary[0:length])) - switch (format) { - case GL_Z400_BINARY_AMD: { } - default: { - glErrorInvalidEnum(format) - } - } - b := new!BinaryExtra(Data: data, Format: format, Count: 1) - ApplyLinkProgramExtra(p, GetLinkProgramExtra(ctx, p, b)) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glProgramParameteri.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramParameteri.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramParameteri.xhtml", Version.GLES32) -cmd void glProgramParameteri(ProgramId program, GLenum pname, GLint value) { - ProgramParameteri(program, pname, value) -} - -sub void ProgramParameteri(ProgramId program, GLenum pname, GLint value) { - p := GetProgramOrError(program) - switch (pname) { - @if(Version.GLES30) - case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: { - p.BinaryRetrievableHint = as!bool(value) - } - @if(Version.GLES31) - case GL_PROGRAM_SEPARABLE: { - p.Separable = as!bool(value) - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1f(ProgramId program, UniformLocation location, GLfloat value0) { - ProgramUniform1f(program, location, value0) -} - -sub void ProgramUniform1f(ProgramId program, UniformLocation location, GLfloat value0) { - v := value0 - SetProgramUniform!GLfloat(program, location, v, GL_FLOAT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1fv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* values) { - ProgramUniform1fv(program, location, count, values) -} - -sub void ProgramUniform1fv(ProgramId program, UniformLocation location, GLsizei count, const GLfloat* values) { - v := values[0:count] - SetProgramUniformv!GLfloat(program, location, v, GL_FLOAT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1i(ProgramId program, UniformLocation location, GLint value0) { - ProgramUniform1i(program, location, value0) -} - -sub void ProgramUniform1i(ProgramId program, UniformLocation location, GLint value0) { - v := value0 - SetProgramUniform!GLint(program, location, v, GL_INT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1iv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* values) { - ProgramUniform1iv(program, location, count, values) -} - -sub void ProgramUniform1iv(ProgramId program, UniformLocation location, GLsizei count, const GLint* values) { - v := values[0:count] - SetProgramUniformv!GLint(program, location, v, GL_INT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1ui(ProgramId program, UniformLocation location, GLuint value0) { - ProgramUniform1ui(program, location, value0) -} - -sub void ProgramUniform1ui(ProgramId program, UniformLocation location, GLuint value0) { - v := value0 - SetProgramUniform!GLuint(program, location, v, GL_UNSIGNED_INT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform1uiv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* values) { - ProgramUniform1uiv(program, location, count, values) -} - -sub void ProgramUniform1uiv(ProgramId program, UniformLocation location, GLsizei count, const GLuint* values) { - v := values[0:count] - SetProgramUniformv!GLuint(program, location, v, GL_UNSIGNED_INT) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2f(ProgramId program, UniformLocation location, GLfloat value0, GLfloat value1) { - ProgramUniform2f(program, location, value0, value1) -} - -sub void ProgramUniform2f(ProgramId program, UniformLocation location, GLfloat value0, GLfloat value1) { - v := Vec2f(value0, value1) - SetProgramUniform!Vec2f(program, location, v, GL_FLOAT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2fv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* values) { - ProgramUniform2fv(program, location, count, values) -} - -sub void ProgramUniform2fv(ProgramId program, UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec2f*(values)[0:count] - SetProgramUniformv!Vec2f(program, location, v, GL_FLOAT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2i(ProgramId program, UniformLocation location, GLint value0, GLint value1) { - ProgramUniform2i(program, location, value0, value1) -} - -sub void ProgramUniform2i(ProgramId program, UniformLocation location, GLint value0, GLint value1) { - v := Vec2i(value0, value1) - SetProgramUniform!Vec2i(program, location, v, GL_INT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2iv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* values) { - ProgramUniform2iv(program, location, count, values) -} - -sub void ProgramUniform2iv(ProgramId program, UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec2i*(values)[0:count] - SetProgramUniformv!Vec2i(program, location, v, GL_INT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2ui(ProgramId program, UniformLocation location, GLuint value0, GLuint value1) { - ProgramUniform2ui(program, location, value0, value1) -} - -sub void ProgramUniform2ui(ProgramId program, UniformLocation location, GLuint value0, GLuint value1) { - v := Vec2u(value0, value1) - SetProgramUniform!Vec2u(program, location, v, GL_UNSIGNED_INT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform2uiv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* values) { - ProgramUniform2uiv(program, location, count, values) -} - -sub void ProgramUniform2uiv(ProgramId program, UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec2u*(values)[0:count] - SetProgramUniformv!Vec2u(program, location, v, GL_UNSIGNED_INT_VEC2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3f(ProgramId program, - UniformLocation location, - GLfloat value0, - GLfloat value1, - GLfloat value2) { - ProgramUniform3f(program, location, value0, value1, value2) -} - -sub void ProgramUniform3f(ProgramId program, UniformLocation location, GLfloat value0, GLfloat value1, GLfloat value2) { - v := Vec3f(value0, value1, value2) - SetProgramUniform!Vec3f(program, location, v, GL_FLOAT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3fv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* values) { - ProgramUniform3fv(program, location, count, values) -} - -sub void ProgramUniform3fv(ProgramId program, UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec3f*(values)[0:count] - SetProgramUniformv!Vec3f(program, location, v, GL_FLOAT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3i(ProgramId program, - UniformLocation location, - GLint value0, - GLint value1, - GLint value2) { - ProgramUniform3i(program, location, value0, value1, value2) -} - -sub void ProgramUniform3i(ProgramId program, UniformLocation location, GLint value0, GLint value1, GLint value2) { - v := Vec3i(value0, value1, value2) - SetProgramUniform!Vec3i(program, location, v, GL_INT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3iv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* values) { - ProgramUniform3iv(program, location, count, values) -} - -sub void ProgramUniform3iv(ProgramId program, UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec3i*(values)[0:count] - SetProgramUniformv!Vec3i(program, location, v, GL_INT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3ui(ProgramId program, - UniformLocation location, - GLuint value0, - GLuint value1, - GLuint value2) { - ProgramUniform3ui(program, location, value0, value1, value2) -} - -sub void ProgramUniform3ui(ProgramId program, UniformLocation location, GLuint value0, GLuint value1, GLuint value2) { - v := Vec3u(value0, value1, value2) - SetProgramUniform!Vec3u(program, location, v, GL_UNSIGNED_INT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform3uiv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* values) { - ProgramUniform3uiv(program, location, count, values) -} - -sub void ProgramUniform3uiv(ProgramId program, UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec3u*(values)[0:count] - SetProgramUniformv!Vec3u(program, location, v, GL_UNSIGNED_INT_VEC3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4f(ProgramId program, - UniformLocation location, - GLfloat value0, - GLfloat value1, - GLfloat value2, - GLfloat value3) { - ProgramUniform4f(program, location, value0, value1, value2, value3) -} - -sub void ProgramUniform4f(ProgramId program, UniformLocation location, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3) { - v := Vec4f(value0, value1, value2, value3) - SetProgramUniform!Vec4f(program, location, v, GL_FLOAT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4fv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLfloat* values) { - ProgramUniform4fv(program, location, count, values) -} - -sub void ProgramUniform4fv(ProgramId program, UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec4f*(values)[0:count] - SetProgramUniformv!Vec4f(program, location, v, GL_FLOAT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4i(ProgramId program, - UniformLocation location, - GLint value0, - GLint value1, - GLint value2, - GLint value3) { - ProgramUniform4i(program, location, value0, value1, value2, value3) -} - -sub void ProgramUniform4i(ProgramId program, UniformLocation location, GLint value0, GLint value1, GLint value2, GLint value3) { - v := Vec4i(value0, value1, value2, value3) - SetProgramUniform!Vec4i(program, location, v, GL_INT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4iv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLint* values) { - ProgramUniform4iv(program, location, count, values) -} - -sub void ProgramUniform4iv(ProgramId program, UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec4i*(values)[0:count] - SetProgramUniformv!Vec4i(program, location, v, GL_INT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4ui(ProgramId program, - UniformLocation location, - GLuint value0, - GLuint value1, - GLuint value2, - GLuint value3) { - ProgramUniform4ui(program, location, value0, value1, value2, value3) -} - -sub void ProgramUniform4ui(ProgramId program, UniformLocation location, GLuint value0, GLuint value1, GLuint value2, GLuint value3) { - v := Vec4u(value0, value1, value2, value3) - SetProgramUniform!Vec4u(program, location, v, GL_UNSIGNED_INT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniform4uiv(ProgramId program, - UniformLocation location, - GLsizei count, - const GLuint* values) { - ProgramUniform4uiv(program, location, count, values) -} - -sub void ProgramUniform4uiv(ProgramId program, UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec4u*(values)[0:count] - SetProgramUniformv!Vec4u(program, location, v, GL_UNSIGNED_INT_VEC4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix2fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix2fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix2fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat2f*(values)[0:count] - SetProgramUniformMatrixv!Mat2f(program, location, transpose, v, GL_FLOAT_MAT2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix2x3fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix2x3fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix2x3fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat2x3f*(values)[0:count] - SetProgramUniformMatrixv!Mat2x3f(program, location, transpose, v, GL_FLOAT_MAT2x3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix2x4fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix2x4fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix2x4fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat2x4f*(values)[0:count] - SetProgramUniformMatrixv!Mat2x4f(program, location, transpose, v, GL_FLOAT_MAT2x4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix3fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix3fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix3fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat3f*(values)[0:count] - SetProgramUniformMatrixv!Mat3f(program, location, transpose, v, GL_FLOAT_MAT3) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix3x2fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix3x2fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix3x2fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat3x2f*(values)[0:count] - SetProgramUniformMatrixv!Mat3x2f(program, location, transpose, v, GL_FLOAT_MAT3x2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix3x4fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix3x4fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix3x4fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat3x4f*(values)[0:count] - SetProgramUniformMatrixv!Mat3x4f(program, location, transpose, v, GL_FLOAT_MAT3x4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix4fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix4fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix4fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat4f*(values)[0:count] - SetProgramUniformMatrixv!Mat4f(program, location, transpose, v, GL_FLOAT_MAT4) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix4x2fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix4x2fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix4x2fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat4x2f*(values)[0:count] - SetProgramUniformMatrixv!Mat4x2f(program, location, transpose, v, GL_FLOAT_MAT4x2) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glProgramUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glProgramUniform.xhtml", Version.GLES32) -cmd void glProgramUniformMatrix4x3fv(ProgramId program, - UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - ProgramUniformMatrix4x3fv(program, location, count, transpose, values) -} - -sub void ProgramUniformMatrix4x3fv(ProgramId program, UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat4x3f*(values)[0:count] - SetProgramUniformMatrixv!Mat4x3f(program, location, transpose, v, GL_FLOAT_MAT4x3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glReleaseShaderCompiler.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glReleaseShaderCompiler.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glReleaseShaderCompiler.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glReleaseShaderCompiler.xhtml", Version.GLES32) -cmd void glReleaseShaderCompiler() { - -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glShaderBinary.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glShaderBinary.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glShaderBinary.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glShaderBinary.xhtml", Version.GLES32) -cmd void glShaderBinary(GLsizei count, - const ShaderId* shaders, - GLenum binary_format, - const void* binary, - GLsizei binary_size) { - ctx := GetContext() - t := shaders[0:count] - for i in (0 .. count) { - _ := GetShaderOrError(t[i]) // Error check only. - } - data := clone(as!u8[](binary[0:binary_size])) - switch (binary_format) { - default: { - glErrorInvalidEnum(binary_format) - } - } - fence // TODO: Automatic placement failed. - for i in (0 .. count) { - s := GetShaderOrError(t[i]) - b := new!BinaryExtra( - Data: data, - Format: binary_format, - Count: count, - Index: i, - ) - ApplyCompileShaderExtra(s, GetCompileShaderExtra(ctx, s, b)) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glShaderSource.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glShaderSource.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glShaderSource.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glShaderSource.xhtml", Version.GLES32) -cmd void glShaderSource(ShaderId shader, - GLsizei count, - const GLchar* const* source, - const GLint* length) { - CheckCountGE!GLsizei(count, 0) - - sources := source[0:count] - s := GetShaderOrError(shader) - s.Source = as!string(null) - if length == null { - for i in (0 .. count) { - str := as!string(as!char*(sources[i])) - s.Source += str - } - } else { - lengths := length[0:count] - for i in (0 .. count) { - str := switch lengths[i] < 0 { - case true: as!string(as!char*(sources[i])) - case false: as!string(as!char*(sources[i])[0:lengths[i]]) - } - s.Source += str - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1f(UniformLocation location, GLfloat value) { - v := value - SetUniform!GLfloat(location, v, GL_FLOAT) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1fv(UniformLocation location, GLsizei count, const GLfloat* values) { - v := values[0:count] - SetUniformv!GLfloat(location, v, GL_FLOAT) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1i(UniformLocation location, GLint value) { - v := value - SetUniform!GLint(location, v, GL_INT) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1iv(UniformLocation location, GLsizei count, const GLint* values) { - v := values[0:count] - SetUniformv!GLint(location, v, GL_INT) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1ui(UniformLocation location, GLuint value0) { - v := value0 - SetUniform!GLuint(location, v, GL_UNSIGNED_INT) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform1uiv(UniformLocation location, GLsizei count, const GLuint* values) { - v := values[0:count] - SetUniformv!GLuint(location, v, GL_UNSIGNED_INT) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2f(UniformLocation location, GLfloat value0, GLfloat value1) { - v := Vec2f(value0, value1) - SetUniform!Vec2f(location, v, GL_FLOAT_VEC2) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2fv(UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec2f*(values)[0:count] - SetUniformv!Vec2f(location, v, GL_FLOAT_VEC2) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2i(UniformLocation location, GLint value0, GLint value1) { - v := Vec2i(value0, value1) - SetUniform!Vec2i(location, v, GL_INT_VEC2) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2iv(UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec2i*(values)[0:count] - SetUniformv!Vec2i(location, v, GL_INT_VEC2) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2ui(UniformLocation location, GLuint value0, GLuint value1) { - v := Vec2u(value0, value1) - SetUniform!Vec2u(location, v, GL_UNSIGNED_INT_VEC2) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform2uiv(UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec2u*(values)[0:count] - SetUniformv!Vec2u(location, v, GL_UNSIGNED_INT_VEC2) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3f(UniformLocation location, GLfloat value0, GLfloat value1, GLfloat value2) { - v := Vec3f(value0, value1, value2) - SetUniform!Vec3f(location, v, GL_FLOAT_VEC3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3fv(UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec3f*(values)[0:count] - SetUniformv!Vec3f(location, v, GL_FLOAT_VEC3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3i(UniformLocation location, GLint value0, GLint value1, GLint value2) { - v := Vec3i(value0, value1, value2) - SetUniform!Vec3i(location, v, GL_INT_VEC3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3iv(UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec3i*(values)[0:count] - SetUniformv!Vec3i(location, v, GL_INT_VEC3) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3ui(UniformLocation location, GLuint value0, GLuint value1, GLuint value2) { - v := Vec3u(value0, value1, value2) - SetUniform!Vec3u(location, v, GL_UNSIGNED_INT_VEC3) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform3uiv(UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec3u*(values)[0:count] - SetUniformv!Vec3u(location, v, GL_UNSIGNED_INT_VEC3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4f(UniformLocation location, - GLfloat value0, - GLfloat value1, - GLfloat value2, - GLfloat value3) { - v := Vec4f(value0, value1, value2, value3) - SetUniform!Vec4f(location, v, GL_FLOAT_VEC4) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4fv(UniformLocation location, GLsizei count, const GLfloat* values) { - v := as!Vec4f*(values)[0:count] - SetUniformv!Vec4f(location, v, GL_FLOAT_VEC4) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4i(UniformLocation location, - GLint value0, - GLint value1, - GLint value2, - GLint value3) { - v := Vec4i(value0, value1, value2, value3) - SetUniform!Vec4i(location, v, GL_INT_VEC4) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4iv(UniformLocation location, GLsizei count, const GLint* values) { - v := as!Vec4i*(values)[0:count] - SetUniformv!Vec4i(location, v, GL_INT_VEC4) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4ui(UniformLocation location, GLuint value0, GLuint value1, GLuint value2, GLuint value3) { - v := Vec4u(value0, value1, value2, value3) - SetUniform!Vec4u(location, v, GL_UNSIGNED_INT_VEC4) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniform4uiv(UniformLocation location, GLsizei count, const GLuint* values) { - v := as!Vec4u*(values)[0:count] - SetUniformv!Vec4u(location, v, GL_UNSIGNED_INT_VEC4) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniformBlockBinding.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniformBlockBinding.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniformBlockBinding.xhtml", Version.GLES32) -cmd void glUniformBlockBinding(ProgramId program, - UniformBlockIndex uniform_block_index, - GLuint uniform_block_binding) { - ctx := GetContext() - p := GetProgramOrError(program) - ub := p.ActiveResources.UniformBlocks[as!u32(uniform_block_index)] - if ub == null { glErrorInvalidValue!UniformBlockIndex(uniform_block_index) } - CheckLT!GLuint(uniform_block_binding, as!GLuint(ctx.Constants.MaxUniformBufferBindings)) - ub.Binding = as!GLint(uniform_block_binding) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix2fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - v := as!Mat2f*(values)[0:count] - SetUniformMatrixv!Mat2f(location, transpose, v, GL_FLOAT_MAT2) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix2x3fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix2x3fv(location, count, transpose, values) -} - -sub void UniformMatrix2x3fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat2x3f*(values)[0:count] - SetUniformMatrixv!Mat2x3f(location, transpose, v, GL_FLOAT_MAT2x3) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix2x4fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix2x4fv(location, count, transpose, values) -} - -sub void UniformMatrix2x4fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat2x4f*(values)[0:count] - SetUniformMatrixv!Mat2x4f(location, transpose, v, GL_FLOAT_MAT2x4) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix3fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - v := as!Mat3f*(values)[0:count] - SetUniformMatrixv!Mat3f(location, transpose, v, GL_FLOAT_MAT3) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix3x2fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix3x2fv(location, count, transpose, values) -} - -sub void UniformMatrix3x2fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat3x2f*(values)[0:count] - SetUniformMatrixv!Mat3x2f(location, transpose, v, GL_FLOAT_MAT3x2) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix3x4fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix3x4fv(location, count, transpose, values) -} - -sub void UniformMatrix3x4fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat3x4f*(values)[0:count] - SetUniformMatrixv!Mat3x4f(location, transpose, v, GL_FLOAT_MAT3x4) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUniform.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix4fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - v := as!Mat4f*(values)[0:count] - SetUniformMatrixv!Mat4f(location, transpose, v, GL_FLOAT_MAT4) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix4x2fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix4x2fv(location, count, transpose, values) -} - -sub void UniformMatrix4x2fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat4x2f*(values)[0:count] - SetUniformMatrixv!Mat4x2f(location, transpose, v, GL_FLOAT_MAT4x2) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUniform.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUniform.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUniform.xhtml", Version.GLES32) -cmd void glUniformMatrix4x3fv(UniformLocation location, - GLsizei count, - GLboolean transpose, - const GLfloat* values) { - UniformMatrix4x3fv(location, count, transpose, values) -} - -sub void UniformMatrix4x3fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat* values) { - v := as!Mat4x3f*(values)[0:count] - SetUniformMatrixv!Mat4x3f(location, transpose, v, GL_FLOAT_MAT4x3) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glUseProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glUseProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUseProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUseProgram.xhtml", Version.GLES32) -cmd void glUseProgram(ProgramId program) { - ctx := GetContext() - // TODO: Invalid op if transform feedback is active. - if program == 0 { - AdjustProgramUseCount(ctx.Bound.Program, -1) - ctx.Bound.Program = null - } else { - p := GetProgramOrError(program) - if p.LinkStatus == GL_FALSE { glErrorInvalidOperation() } - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(ctx.Bound.Program, -1) - ctx.Bound.Program = p - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glUseProgramStages.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glUseProgramStages.xhtml", Version.GLES32) -cmd void glUseProgramStages(PipelineId pipeline, GLbitfield stages, ProgramId program) { - pipe := GetOrCreatePipelineOrError(pipeline) - supportsBits(stages, GL_ALL_SHADER_BITS | GL_COMPUTE_SHADER_BIT | GL_FRAGMENT_SHADER_BIT | GL_VERTEX_SHADER_BIT) - if program == 0 { - SetProgramStates(pipe, stages, null) - } else { - p := GetProgramOrError(program) - if p.LinkStatus == GL_FALSE { glErrorInvalidOperation() } - if !p.LinkExtra.Separable { glErrorInvalidOperation() } - SetProgramStates(pipe, stages, p) - } -} - -sub void SetProgramStates(ref!Pipeline pipe, GLbitfield stages, ref!Program p) { - if (GL_COMPUTE_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.ComputeShader, -1) - pipe.ComputeShader = p - } - if (GL_FRAGMENT_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.FragmentShader, -1) - pipe.FragmentShader = p - } - if (GL_VERTEX_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.VertexShader, -1) - pipe.VertexShader = p - } - if (GL_TESS_CONTROL_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.TessControlShader, -1) - pipe.TessControlShader = p - } - if (GL_TESS_EVALUATION_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.TessEvaluationShader, -1) - pipe.TessEvaluationShader = p - } - if (GL_GEOMETRY_SHADER_BIT in stages) { - AdjustProgramUseCount(p, +1) - AdjustProgramUseCount(pipe.GeometryShader, -1) - pipe.GeometryShader = p - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glValidateProgram.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glValidateProgram.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glValidateProgram.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glValidateProgram.xhtml", Version.GLES32) -cmd void glValidateProgram(ProgramId program) { - ctx := GetContext() - p := GetProgramOrError(program) - ApplyValidateProgramExtra(p, GetValidateProgramExtra(ctx, p)) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glValidateProgramPipeline.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glValidateProgramPipeline.xhtml", Version.GLES32) -cmd void glValidateProgramPipeline(PipelineId pipeline) { - ctx := GetContext() - pipe := GetOrCreatePipelineOrError(pipeline) - ApplyValidateProgramPipelineExtra(pipe, GetValidateProgramPipelineExtra(ctx, pipe)) -} - diff --git a/gapis/api/gles/api/rasterization.api b/gapis/api/gles/api/rasterization.api deleted file mode 100644 index c0c7f37388..0000000000 --- a/gapis/api/gles/api/rasterization.api +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class RasterizationState { - // Table 21.6: Transformation State - Rect Viewport // TODO: initialize - Vec2f DepthRange = Vec2f(0, 1) - BoundingBox PrimitiveBoundingBox - - // Table 21.7: Rasterization - GLboolean RasterizerDiscard = GL_FALSE - GLfloat LineWidth = 1.0 - GLboolean CullFace = GL_FALSE - GLenum CullFaceMode = GL_BACK - GLenum FrontFace = GL_CCW - GLfloat PolygonOffsetFactor = 0 - GLfloat PolygonOffsetUnits = 0 - GLboolean PolygonOffsetFill = GL_FALSE - - // Table 21.8: Multisampling - GLboolean SampleAlphaToCoverage = GL_FALSE - GLboolean SampleCoverage = GL_FALSE - GLfloat SampleCoverageValue = 1 - GLboolean SampleCoverageInvert = GL_FALSE - GLboolean SampleShading = GL_FALSE - GLfloat MinSampleShadingValue = 0 - GLboolean SampleMask = GL_FALSE - @unused map!(GLuint, GLbitfield) SampleMaskValue -} - -@internal -class BoundingBox { - @unused Vec4f Min = Vec4f(-1, -1, -1, 1) // SPEC: Man pages say w is -1 - @unused Vec4f Max = Vec4f(1, 1, 1, 1) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCullFace.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCullFace.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCullFace.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCullFace.xhtml", Version.GLES32) -cmd void glCullFace(GLenum mode) { - switch (mode) { - case GL_BACK, GL_FRONT, GL_FRONT_AND_BACK: { - // version 2.0 - } - default: { - glErrorInvalidEnum(mode) - } - } - - ctx := GetContext() - ctx.Rasterization.CullFaceMode = mode -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDepthRangef.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDepthRangef.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDepthRangef.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDepthRangef.xhtml", Version.GLES32) -cmd void glDepthRangef(GLfloat near, GLfloat far) { - - ctx := GetContext() - ctx.Rasterization.DepthRange = Vec2f(near, far) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glFrontFace.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFrontFace.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFrontFace.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFrontFace.xhtml", Version.GLES32) -cmd void glFrontFace(GLenum orientation) { - switch (orientation) { - case GL_CCW, GL_CW: { - // version 2.0 - } - default: { - glErrorInvalidEnum(orientation) - } - } - - ctx := GetContext() - ctx.Rasterization.FrontFace = orientation -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetMultisamplefv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetMultisamplefv.xhtml", Version.GLES32) -cmd void glGetMultisamplefv(GLenum pname, GLuint index, GLfloat* val) { - switch (pname) { - case GL_SAMPLE_POSITION: { - // version 3.1 - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - read(val[0:2]) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glLineWidth.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glLineWidth.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glLineWidth.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glLineWidth.xhtml", Version.GLES32) -cmd void glLineWidth(GLfloat width) { - if width <= 0.0 { glErrorInvalidValue!GLfloat(width) } - ctx := GetContext() - ctx.Rasterization.LineWidth = width -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glMinSampleShading.xhtml", Version.GLES32) -cmd void glMinSampleShading(GLfloat value) { - MinSampleShading(value) -} - -sub void MinSampleShading(GLfloat value) { - ctx := GetContext() - ctx.Rasterization.MinSampleShadingValue = value -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glPolygonOffset.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glPolygonOffset.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glPolygonOffset.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPolygonOffset.xhtml", Version.GLES32) -cmd void glPolygonOffset(GLfloat scale_factor, GLfloat units) { - - ctx := GetContext() - ctx.Rasterization.PolygonOffsetUnits = units - ctx.Rasterization.PolygonOffsetFactor = scale_factor -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glViewport.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glViewport.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glViewport.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glViewport.xhtml", Version.GLES32) -cmd void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - CheckSizeGE!GLsizei(width, 0) - CheckSizeGE!GLsizei(height, 0) - ctx := GetContext() - ctx.Rasterization.Viewport = Rect(x, y, width, height) -} diff --git a/gapis/api/gles/api/state_queries.api b/gapis/api/gles/api/state_queries.api deleted file mode 100644 index 42d47a0fef..0000000000 --- a/gapis/api/gles/api/state_queries.api +++ /dev/null @@ -1,1495 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -sub ID GetID!(ID,OBJ)(ref!OBJ o) { - return switch o != null { - case true: as!ID(o.ID) - case false: as!ID(0) - } -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetBooleani_v(GLenum param, GLuint index, GLboolean* values) { - GetStateVariable!GLboolean(param, true, index, values) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetBooleanv(GLenum param, GLboolean* values) { - GetStateVariable!GLboolean(param, false, 0, values) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetFloatv(GLenum param, GLfloat* values) { - GetStateVariable!GLfloat(param, false, 0, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetInteger64i_v(GLenum param, GLuint index, GLint64* values) { - GetStateVariable!GLint64(param, true, index, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetInteger64v(GLenum param, GLint64* values) { - GetInteger64v(param, values) -} - -sub void GetInteger64v(GLenum param, GLint64* values) { - GetStateVariable!GLint64(param, false, 0, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetIntegeri_v(GLenum param, GLuint index, GLint* values) { - GetStateVariable!GLint(param, true, index, values) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGet.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGet.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGet.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGet.xhtml", Version.GLES32) -cmd void glGetIntegerv(GLenum param, GLint* values) { - GetStateVariable!GLint(param, false, 0, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetInternalformativ.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetInternalformativ.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetInternalformativ.xhtml", Version.GLES32) -cmd void glGetInternalformativ(GLenum target, - GLenum internalformat, - GLenum pname, - GLsizei bufSize, - GLint* params) { - switch (target) { - case GL_RENDERBUFFER: { - // version 3.0 - } - @if(Version.GLES31) - case GL_TEXTURE_2D_MULTISAMPLE: { - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { - } - default: { - glErrorInvalidEnum(target) - } - } - switch (internalformat) { - case GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, - GL_DEPTH_COMPONENT32F, GL_R11F_G11F_B10F, GL_R16F, GL_R16I, GL_R16UI, GL_R32F, GL_R32I, - GL_R32UI, GL_R8, GL_R8I, GL_R8UI, GL_R8_SNORM, GL_RG16F, GL_RG16I, GL_RG16UI, GL_RG32F, - GL_RG32I, GL_RG32UI, GL_RG8, GL_RG8I, GL_RG8UI, GL_RG8_SNORM, GL_RGB10_A2, GL_RGB10_A2UI, - GL_RGB16F, GL_RGB16I, GL_RGB16UI, GL_RGB32F, GL_RGB32I, GL_RGB32UI, GL_RGB565, GL_RGB5_A1, - GL_RGB8, GL_RGB8I, GL_RGB8UI, GL_RGB8_SNORM, GL_RGB9_E5, GL_RGBA16F, GL_RGBA16I, - GL_RGBA16UI, GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, GL_RGBA4, GL_RGBA8, GL_RGBA8I, - GL_RGBA8UI, GL_RGBA8_SNORM, GL_SRGB8, GL_SRGB8_ALPHA8: { - // version 3.0 - } - @if(Version.GLES32) - case GL_STENCIL_INDEX8: { - } - default: { - glErrorInvalidEnum(internalformat) - } - } - switch (pname) { - case GL_NUM_SAMPLE_COUNTS, GL_SAMPLES: { - // version 3.0 - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetString.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetString.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetString.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetString.xhtml", Version.GLES32) -cmd const GLubyte* glGetString(GLenum param) { - switch (param) { - case GL_EXTENSIONS, GL_RENDERER, GL_SHADING_LANGUAGE_VERSION, GL_VENDOR, GL_VERSION: { - // version 2.0 - } - default: { - glErrorInvalidEnum(param) - } - } - - ret := as!(const GLubyte*)(?) - _ = as!string(as!(char*)(ret)) // Make sure we observe the string. - return ret -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetString.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetString.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetString.xhtml", Version.GLES32) -cmd const GLubyte* glGetStringi(GLenum name, GLuint index) { - switch (name) { - case GL_EXTENSIONS: { - // version 3.0 - } - default: { - glErrorInvalidEnum(name) - } - } - - ret := as!(const GLubyte*)(?) - _ = as!string(as!(char*)(ret)) // Make sure we observe the string. - return ret -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsEnabled.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsEnabled.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsEnabled.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsEnabled.xhtml", Version.GLES32) -cmd GLboolean glIsEnabled(GLenum capability) { - return GetCapability(capability, 0) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsEnabled.xhtml", Version.GLES32) -cmd GLboolean glIsEnabledi(GLenum capability, GLuint index) { - return IsEnabledi(capability, index) -} - -sub GLboolean IsEnabledi(GLenum capability, GLuint index) { - return GetCapability(capability, index) -} - -sub ref!BlendState getBlendStateOrInvalidValue(ref!Context ctx, DrawBufferIndex index) { - if !(index in ctx.Pixel.Blend) { - glErrorInvalidValue!DrawBufferIndex(index) - } - return ctx.Pixel.Blend[index] -} - -sub void GetStateVariable!T(GLenum name, bool isIndexed, GLuint index, T* v) { - ctx := GetContext() - switch (name) { - @if(Version.GLES20) - case GL_ACTIVE_TEXTURE: { - v[0] = GetID!(T,TextureUnit)(ctx.Bound.TextureUnit) - } - @if(Version.GLES20) - case GL_ALIASED_LINE_WIDTH_RANGE: { - s := v[0:2] - s[0] = as!T(ctx.Constants.AliasedLineWidthRange[0]) - s[1] = as!T(ctx.Constants.AliasedLineWidthRange[1]) - } - @if(Version.GLES20) - case GL_ALIASED_POINT_SIZE_RANGE: { - s := v[0:2] - s[0] = as!T(ctx.Constants.AliasedPointSizeRange[0]) - s[1] = as!T(ctx.Constants.AliasedPointSizeRange[1]) - } - @if(Version.GLES20) - case GL_ALPHA_BITS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_ARRAY_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.ArrayBuffer) - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER_BINDING: { - if isIndexed { - v[0] = GetID!(T,Buffer)(ctx.Bound.AtomicCounterBuffers[index].Binding) - } else { - v[0] = GetID!(T,Buffer)(ctx.Bound.AtomicCounterBuffer) - } - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER_SIZE: { - if isIndexed { - v[0] = as!T(ctx.Bound.AtomicCounterBuffers[index].Size) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_ATOMIC_COUNTER_BUFFER_START: { - if isIndexed { - v[0] = as!T(ctx.Bound.AtomicCounterBuffers[index].Start) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_BLEND: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).Enabled) - } - @if(Version.GLES20) - case GL_BLEND_COLOR: { - s := v[0:4] - s[0] = as!T(ctx.Pixel.BlendColor.Red) - s[1] = as!T(ctx.Pixel.BlendColor.Green) - s[2] = as!T(ctx.Pixel.BlendColor.Blue) - s[3] = as!T(ctx.Pixel.BlendColor.Alpha) - } - @if(Version.GLES20) - case GL_BLEND_DST_ALPHA: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).DstAlpha) - } - @if(Version.GLES20) - case GL_BLEND_DST_RGB: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).DstRgb) - } - @if(Version.GLES20) - case GL_BLEND_EQUATION_ALPHA: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).EquationAlpha) - } - @if(Version.GLES20) - case GL_BLEND_EQUATION_RGB: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).EquationRgb) - } - @if(Version.GLES20) - case GL_BLEND_SRC_ALPHA: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).SrcAlpha) - } - @if(Version.GLES20) - case GL_BLEND_SRC_RGB: { - // SPEC: Man page does not mention indexing. - v[0] = as!T(getBlendStateOrInvalidValue(ctx, as!DrawBufferIndex(index)).SrcRgb) - } - @if(Version.GLES20) - case GL_BLUE_BITS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_COLOR_CLEAR_VALUE: { - s := v[0:4] - s[0] = as!T(ctx.Pixel.ColorClearValue[0]) - s[1] = as!T(ctx.Pixel.ColorClearValue[1]) - s[2] = as!T(ctx.Pixel.ColorClearValue[2]) - s[3] = as!T(ctx.Pixel.ColorClearValue[3]) - } - @if(Version.GLES20) - case GL_COLOR_WRITEMASK: { - s := v[0:4] - i := as!DrawBufferIndex(index) // SPEC: Man page does not mention indexing. - s[0] = as!T(ctx.Pixel.ColorWritemask[i].R) - s[1] = as!T(ctx.Pixel.ColorWritemask[i].G) - s[2] = as!T(ctx.Pixel.ColorWritemask[i].B) - s[3] = as!T(ctx.Pixel.ColorWritemask[i].A) - } - @if(Version.GLES20) - case GL_COMPRESSED_TEXTURE_FORMATS: { - s := v[0:len(ctx.Constants.CompressedTextureFormats)] - for _ , i , f in ctx.Constants.CompressedTextureFormats { - s[i] = as!T(f) - } - } - @if(Version.GLES32) - case GL_CONTEXT_FLAGS: { - v[0] = as!T(ctx.Constants.ContextFlags) - } - @if(Version.GLES32) - case GL_CONTEXT_ROBUST_ACCESS: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_COPY_READ_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.CopyReadBuffer) - } - @if(Version.GLES30) - case GL_COPY_WRITE_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.CopyWriteBuffer) - } - @if(Version.GLES20) - case GL_CULL_FACE: { - v[0] = as!T(ctx.Rasterization.CullFace) - } - @if(Version.GLES20) - case GL_CULL_FACE_MODE: { - v[0] = as!T(ctx.Rasterization.CullFaceMode) - } - @if(Version.GLES20) - case GL_CURRENT_PROGRAM: { - v[0] = GetID!(T,Program)(ctx.Bound.Program) - } - @if(Version.GLES32) - case GL_DEBUG_GROUP_STACK_DEPTH: { - write(v[0:1]) - } - @if(Version.GLES32) - case GL_DEBUG_LOGGED_MESSAGES: { - write(v[0:1]) - } - @if(Version.GLES32) - case GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_DEPTH_BITS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_DEPTH_CLEAR_VALUE: { - v[0] = as!T(ctx.Pixel.DepthClearValue) - } - @if(Version.GLES20) - case GL_DEPTH_FUNC: { - v[0] = as!T(ctx.Pixel.Depth.Func) - } - @if(Version.GLES20) - case GL_DEPTH_RANGE: { - s := v[0:2] - s[0] = as!T(ctx.Rasterization.DepthRange[0]) - s[1] = as!T(ctx.Rasterization.DepthRange[1]) - } - @if(Version.GLES20) - case GL_DEPTH_TEST: { - v[0] = as!T(ctx.Pixel.Depth.Test) - } - @if(Version.GLES20) - case GL_DEPTH_WRITEMASK: { - v[0] = as!T(ctx.Pixel.DepthWritemask) - } - @if(Version.GLES31) - case GL_DISPATCH_INDIRECT_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.DispatchIndirectBuffer) - } - @if(Version.GLES20) - case GL_DITHER: { - v[0] = as!T(ctx.Pixel.Dither) - } - @if(Version.GLES30) - case GL_DRAW_BUFFER: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_DRAW_BUFFER0, GL_DRAW_BUFFER1, GL_DRAW_BUFFER2, GL_DRAW_BUFFER3, - GL_DRAW_BUFFER4, GL_DRAW_BUFFER5, GL_DRAW_BUFFER6, GL_DRAW_BUFFER7, - GL_DRAW_BUFFER8, GL_DRAW_BUFFER9, GL_DRAW_BUFFER10, GL_DRAW_BUFFER11, - GL_DRAW_BUFFER12, GL_DRAW_BUFFER13, GL_DRAW_BUFFER14, GL_DRAW_BUFFER15: { - framebuffer := GetBoundFramebufferOrErrorInvalidEnum(GL_DRAW_FRAMEBUFFER) - v[0] = as!T(framebuffer.DrawBuffer[as!GLint(name - GL_DRAW_BUFFER0)]) - } - @if(Version.GLES20) - case GL_DRAW_FRAMEBUFFER_BINDING: { - v[0] = GetID!(T,Framebuffer)(ctx.Bound.DrawFramebuffer) - } - @if(Version.GLES20) - case GL_ELEMENT_ARRAY_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.VertexArray.ElementArrayBuffer) - } - @if(Version.GLES32) - case GL_FRAGMENT_INTERPOLATION_OFFSET_BITS: { - v[0] = as!T(ctx.Constants.FragmentInterpolationOffsetBits) - } - @if(Version.GLES30) - case GL_FRAGMENT_SHADER_DERIVATIVE_HINT: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_FRONT_FACE: { - v[0] = as!T(ctx.Rasterization.FrontFace) - } - @if(Version.GLES20) - case GL_GENERATE_MIPMAP_HINT: { - v[0] = as!T(ctx.Other.GenerateMipmapHint) - } - @if(Version.GLES20) - case GL_GREEN_BITS: { - write(v[0:1]) - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_NAME: { - if isIndexed { - v[0] = GetID!(T,Texture)(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Texture) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_LEVEL: { - if isIndexed { - v[0] = as!T(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Level) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_LAYERED: { - if isIndexed { - v[0] = as!T(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Layered) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_LAYER: { - if isIndexed { - v[0] = as!T(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Layer) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_ACCESS: { - if isIndexed { - v[0] = as!T(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Access) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_IMAGE_BINDING_FORMAT: { - if isIndexed { - v[0] = as!T(ctx.Objects.ImageUnits[as!ImageUnitId(index)].Format) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_IMPLEMENTATION_COLOR_READ_FORMAT: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_IMPLEMENTATION_COLOR_READ_TYPE: { - write(v[0:1]) - } - @if(Version.GLES32) - case GL_LAYER_PROVOKING_VERTEX: { - v[0] = as!T(ctx.Constants.LayerProvokingVertex) - } - @if(Version.GLES20) - case GL_LINE_WIDTH: { - v[0] = as!T(ctx.Rasterization.LineWidth) - } - @if(Version.GLES32) - case GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED: { - v[0] = as!T(ctx.Constants.PrimitiveRestartForPatchesSupported) - } - @if(Version.GLES30) - case GL_MAJOR_VERSION: { - v[0] = as!T(ctx.Constants.MajorVersion) - } - @if(Version.GLES30) - case GL_MAX_3D_TEXTURE_SIZE: { - v[0] = as!T(ctx.Constants.Max3dTextureSize) - } - @if(Version.GLES30) - case GL_MAX_ARRAY_TEXTURE_LAYERS: { - v[0] = as!T(ctx.Constants.MaxArrayTextureLayers) - } - @if(Version.GLES31) - case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: { - v[0] = as!T(ctx.Constants.MaxAtomicCounterBufferBindings) - } - @if(Version.GLES31) - case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE: { - v[0] = as!T(ctx.Constants.MaxAtomicCounterBufferSize) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxCombinedAtomicCounterBuffers) - } - @if(Version.GLES30) - case GL_MAX_COLOR_ATTACHMENTS: { - v[0] = as!T(ctx.Constants.MaxColorAttachments) - } - @if(Version.GLES31) - case GL_MAX_COLOR_TEXTURE_SAMPLES: { - v[0] = as!T(ctx.Constants.MaxColorTextureSamples) - } - @if(Version.GLES31) - case GL_MAX_DEPTH_TEXTURE_SAMPLES: { - v[0] = as!T(ctx.Constants.MaxDepthTextureSamples) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxCombinedAtomicCounters) - } - @if(Version.GLES31) - case GL_MAX_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxImageUnits) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedComputeUniformComponents) - } - @if(Version.GLES30) - case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedFragmentUniformComponents) - } - @if(Version.GLES32) - case GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedGeometryUniformComponents) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxCombinedShaderStorageBlocks) - } - @if(Version.GLES32) - case GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedTessControlUniformComponents) - } - @if(Version.GLES32) - case GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedTessEvaluationUniformComponents) - } - @if(Version.GLES20) - case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxCombinedTextureImageUnits) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES: { - v[0] = as!T(ctx.Constants.MaxCombinedShaderOutputResources) - } - @if(Version.GLES30) - case GL_MAX_COMBINED_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxCombinedUniformBlocks) - } - @if(Version.GLES30) - case GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxCombinedVertexUniformComponents) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxComputeAtomicCounterBuffers) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxComputeAtomicCounters) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxComputeImageUniforms) - } - @if(Version.GLES31) - case GL_MAX_COMBINED_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxCombinedImageUniforms) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxComputeShaderStorageBlocks) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxComputeTextureImageUnits) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: { - v[0] = as!T(ctx.Constants.MaxComputeSharedMemorySize) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxComputeUniformBlocks) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxComputeUniformComponents) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_WORK_GROUP_COUNT: { - if isIndexed { - v[0] = as!T(ctx.Constants.MaxComputeWorkGroupCount[index]) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: { - v[0] = as!T(ctx.Constants.MaxComputeWorkGroupInvocations) - } - @if(Version.GLES31) - case GL_MAX_COMPUTE_WORK_GROUP_SIZE: { - if isIndexed { - v[0] = as!T(ctx.Constants.MaxComputeWorkGroupSize[index]) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_MAX_CUBE_MAP_TEXTURE_SIZE: { - v[0] = as!T(ctx.Constants.MaxCubeMapTextureSize) - } - @if(Version.GLES32) - case GL_MAX_DEBUG_GROUP_STACK_DEPTH: { - v[0] = as!T(ctx.Constants.MaxDebugGroupStackDepth) - } - @if(Version.GLES32) - case GL_MAX_DEBUG_LOGGED_MESSAGES: { - v[0] = as!T(ctx.Constants.MaxDebugLoggedMessages) - } - @if(Version.GLES32) - case GL_MAX_DEBUG_MESSAGE_LENGTH: { - v[0] = as!T(ctx.Constants.MaxDebugMessageLength) - } - @if(Version.GLES30) - case GL_MAX_DRAW_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxDrawBuffers) - } - @if(Version.GLES30) - case GL_MAX_ELEMENT_INDEX: { - v[0] = as!T(ctx.Constants.MaxElementIndex) - } - @if(Version.GLES30) - case GL_MAX_ELEMENTS_INDICES: { - v[0] = as!T(ctx.Constants.MaxElementsIndices) - } - @if(Version.GLES30) - case GL_MAX_ELEMENTS_VERTICES: { - v[0] = as!T(ctx.Constants.MaxElementsVertices) - } - @if(Version.GLES31) - case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxFragmentAtomicCounterBuffers) - } - @if(Version.GLES31) - case GL_MAX_FRAGMENT_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxFragmentAtomicCounters) - } - @if(Version.GLES31) - case GL_MAX_FRAGMENT_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxFragmentImageUniforms) - } - @if(Version.GLES30) - case GL_MAX_FRAGMENT_INPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxFragmentInputComponents) - } - @if(Version.GLES32) - case GL_MAX_FRAGMENT_INTERPOLATION_OFFSET: { - v[0] = as!T(ctx.Constants.MaxFragmentInterpolationOffset) - } - @if(Version.GLES31) - case GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxFragmentShaderStorageBlocks) - } - @if(Version.GLES31) - case GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET: { - v[0] = as!T(ctx.Constants.MinProgramTextureGatherOffset) - } - @if(Version.GLES31) - case GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET: { - v[0] = as!T(ctx.Constants.MaxProgramTextureGatherOffset) - } - @if(Version.GLES30) - case GL_MAX_FRAGMENT_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxFragmentUniformBlocks) - } - @if(Version.GLES30) - case GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxFragmentUniformComponents) - } - @if(Version.GLES20) - case GL_MAX_FRAGMENT_UNIFORM_VECTORS: { - v[0] = as!T(ctx.Constants.MaxFragmentUniformVectors) - } - @if(Version.GLES31) - case GL_MAX_FRAMEBUFFER_HEIGHT: { - v[0] = as!T(ctx.Constants.MaxFramebufferHeight) - } - @if(Version.GLES32) - case GL_MAX_FRAMEBUFFER_LAYERS: { - v[0] = as!T(ctx.Constants.MaxFramebufferLayers) - } - @if(Version.GLES31) - case GL_MAX_FRAMEBUFFER_SAMPLES: { - v[0] = as!T(ctx.Constants.MaxFramebufferSamples) - } - @if(Version.GLES31) - case GL_MAX_FRAMEBUFFER_WIDTH: { - v[0] = as!T(ctx.Constants.MaxFramebufferWidth) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxGeometryAtomicCounterBuffers) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxGeometryAtomicCounters) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxGeometryImageUniforms) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_INPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxGeometryInputComponents) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxGeometryOutputComponents) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_OUTPUT_VERTICES: { - v[0] = as!T(ctx.Constants.MaxGeometryOutputVertices) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_SHADER_INVOCATIONS: { - v[0] = as!T(ctx.Constants.MaxGeometryShaderInvocations) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxGeometryShaderStorageBlocks) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxGeometryTextureImageUnits) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxGeometryTotalOutputComponents) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxGeometryUniformBlocks) - } - @if(Version.GLES32) - case GL_MAX_GEOMETRY_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxGeometryUniformComponents) - } - @if(Version.GLES31) - case GL_MAX_INTEGER_SAMPLES: { - v[0] = as!T(ctx.Constants.MaxIntegerSamples) - } - @if(Version.GLES32) - case GL_MAX_LABEL_LENGTH: { - v[0] = as!T(ctx.Constants.MaxLabelLength) - } - @if(Version.GLES30) - case GL_MAX_PROGRAM_TEXEL_OFFSET: { - v[0] = as!T(ctx.Constants.MaxProgramTexelOffset) - } - @if(Version.GLES20) - case GL_MAX_RENDERBUFFER_SIZE: { - v[0] = as!T(ctx.Constants.MaxRenderbufferSize) - } - @if(Version.GLES31) - case GL_MAX_SAMPLE_MASK_WORDS: { - v[0] = as!T(ctx.Constants.MaxSampleMaskWords) - } - @if(Version.GLES30) - case GL_MAX_SAMPLES: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_MAX_SERVER_WAIT_TIMEOUT: { - v[0] = as!T(ctx.Constants.MaxServerWaitTimeout) - } - @if(Version.GLES31) - case GL_MAX_SHADER_STORAGE_BLOCK_SIZE: { - v[0] = as!T(ctx.Constants.MaxShaderStorageBlockSize) - } - @if(Version.GLES31) - case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: { - v[0] = as!T(ctx.Constants.MaxShaderStorageBufferBindings) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxTessControlAtomicCounterBuffers) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxTessControlAtomicCounters) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxTessControlImageUniforms) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_INPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessControlInputComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessControlOutputComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxTessControlShaderStorageBlocks) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxTessControlTextureImageUnits) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessControlTotalOutputComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxTessControlUniformBlocks) - } - @if(Version.GLES32) - case GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessControlUniformComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationAtomicCounterBuffers) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationAtomicCounters) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationImageUniforms) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationInputComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationOutputComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationShaderStorageBlocks) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationTextureImageUnits) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationUniformBlocks) - } - @if(Version.GLES32) - case GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessEvaluationUniformComponents) - } - @if(Version.GLES32) - case GL_MAX_TESS_GEN_LEVEL: { - v[0] = as!T(ctx.Constants.MaxTessGenLevel) - } - @if(Version.GLES32) - case GL_MAX_PATCH_VERTICES: { - v[0] = as!T(ctx.Constants.MaxPatchVertices) - } - @if(Version.GLES32) - case GL_MAX_TESS_PATCH_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTessPatchComponents) - } - @if(Version.GLES32) - case GL_MAX_TEXTURE_BUFFER_SIZE: { - v[0] = as!T(ctx.Constants.MaxTextureBufferSize) - } - @if(Version.GLES20) - case GL_MAX_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxTextureImageUnits) - } - @if(Version.GLES30) - case GL_MAX_TEXTURE_LOD_BIAS: { - v[0] = as!T(ctx.Constants.MaxTextureLodBias) - } - @if(Version.GLES20) - case GL_MAX_TEXTURE_SIZE: { - v[0] = as!T(ctx.Constants.MaxTextureSize) - } - @if(Version.GLES30) - case GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTransformFeedbackInterleavedComponents) - } - @if(Version.GLES30) - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: { - v[0] = as!T(ctx.Constants.MaxTransformFeedbackSeparateAttribs) - } - @if(Version.GLES30) - case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxTransformFeedbackSeparateComponents) - } - @if(Version.GLES30) - case GL_MAX_UNIFORM_BLOCK_SIZE: { - v[0] = as!T(ctx.Constants.MaxUniformBlockSize) - } - @if(Version.GLES30) - case GL_MAX_UNIFORM_BUFFER_BINDINGS: { - v[0] = as!T(ctx.Constants.MaxUniformBufferBindings) - } - @if(Version.GLES31) - case GL_MAX_UNIFORM_LOCATIONS: { - v[0] = as!T(ctx.Constants.MaxUniformLocations) - } - @if(Version.GLES30) - case GL_MAX_VARYING_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxVaryingComponents) - } - @if(Version.GLES20) - case GL_MAX_VARYING_VECTORS: { - v[0] = as!T(ctx.Constants.MaxVaryingVectors) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_ATOMIC_COUNTERS: { - v[0] = as!T(ctx.Constants.MaxVertexAtomicCounters) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS: { - v[0] = as!T(ctx.Constants.MaxVertexAtomicCounterBuffers) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_ATTRIB_BINDINGS: { - v[0] = as!T(ctx.Constants.MaxVertexAttribBindings) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_ATTRIB_STRIDE: { - v[0] = as!T(ctx.Constants.MaxVertexAttribStride) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET: { - v[0] = as!T(ctx.Constants.MaxVertexAttribRelativeOffset) - } - @if(Version.GLES20) - case GL_MAX_VERTEX_ATTRIBS: { - v[0] = as!T(ctx.Constants.MaxVertexAttribs) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_IMAGE_UNIFORMS: { - v[0] = as!T(ctx.Constants.MaxVertexImageUniforms) - } - @if(Version.GLES30) - case GL_MAX_VERTEX_OUTPUT_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxVertexOutputComponents) - } - @if(Version.GLES31) - case GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxVertexShaderStorageBlocks) - } - @if(Version.GLES20) - case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: { - v[0] = as!T(ctx.Constants.MaxVertexTextureImageUnits) - } - @if(Version.GLES30) - case GL_MAX_VERTEX_UNIFORM_BLOCKS: { - v[0] = as!T(ctx.Constants.MaxVertexUniformBlocks) - } - @if(Version.GLES30) - case GL_MAX_VERTEX_UNIFORM_COMPONENTS: { - v[0] = as!T(ctx.Constants.MaxVertexUniformComponents) - } - @if(Version.GLES20) - case GL_MAX_VERTEX_UNIFORM_VECTORS: { - v[0] = as!T(ctx.Constants.MaxVertexUniformVectors) - } - @if(Extension.GL_OVR_multiview) - case GL_MAX_VIEWS_OVR: { - v[0] = as!T(ctx.Constants.MaxViewsExt) - } - @if(Version.GLES20) - case GL_MAX_VIEWPORT_DIMS: { - s := v[0:2] - s[0] = as!T(ctx.Constants.MaxViewportDims[0]) - s[1] = as!T(ctx.Constants.MaxViewportDims[1]) - } - @if(Version.GLES32) - case GL_MIN_FRAGMENT_INTERPOLATION_OFFSET: { - v[0] = as!T(ctx.Constants.MinFragmentInterpolationOffset) - } - @if(Version.GLES30) - case GL_MIN_PROGRAM_TEXEL_OFFSET: { - v[0] = as!T(ctx.Constants.MinProgramTexelOffset) - } - @if(Version.GLES32) - case GL_MIN_SAMPLE_SHADING_VALUE: { - v[0] = as!T(ctx.Rasterization.MinSampleShadingValue) - } - @if(Version.GLES30) - case GL_MINOR_VERSION: { - v[0] = as!T(ctx.Constants.MinorVersion) - } - @if(Version.GLES32) - case GL_MULTISAMPLE_LINE_WIDTH_RANGE: { - s := v[0:2] - s[0] = as!T(ctx.Constants.MultisampleLineWidthRange[0]) - s[1] = as!T(ctx.Constants.MultisampleLineWidthRange[1]) - } - @if(Version.GLES32) - case GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY: { - v[0] = as!T(ctx.Constants.MultisampleLineWidthGranularity) - } - @if(Version.GLES20) - case GL_NUM_COMPRESSED_TEXTURE_FORMATS: { - v[0] = as!T(len(ctx.Constants.CompressedTextureFormats)) - } - @if(Version.GLES30) - case GL_NUM_EXTENSIONS: { - v[0] = as!T(len(ctx.Constants.Extensions)) - } - @if(Version.GLES30) - case GL_NUM_PROGRAM_BINARY_FORMATS: { - v[0] = as!T(len(ctx.Constants.ProgramBinaryFormats)) - } - @if(Version.GLES20) - case GL_NUM_SHADER_BINARY_FORMATS: { - v[0] = as!T(len(ctx.Constants.ShaderBinaryFormats)) - } - @if(Version.GLES20) - case GL_PACK_ALIGNMENT: { - v[0] = as!T(ctx.Other.Pack.Alignment) - } - @if(Version.GLES30) - case GL_PACK_IMAGE_HEIGHT: { - v[0] = as!T(ctx.Other.Pack.ImageHeight) - } - @if(Version.GLES30) - case GL_PACK_ROW_LENGTH: { - v[0] = as!T(ctx.Other.Pack.RowLength) - } - @if(Version.GLES30) - case GL_PACK_SKIP_IMAGES: { - v[0] = as!T(ctx.Other.Pack.SkipImages) - } - @if(Version.GLES30) - case GL_PACK_SKIP_PIXELS: { - v[0] = as!T(ctx.Other.Pack.SkipPixels) - } - @if(Version.GLES30) - case GL_PACK_SKIP_ROWS: { - v[0] = as!T(ctx.Other.Pack.SkipRows) - } - @if(Version.GLES32) - case GL_PATCH_VERTICES: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_PIXEL_PACK_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.PixelPackBuffer) - } - @if(Version.GLES30) - case GL_PIXEL_UNPACK_BUFFER_BINDING: { - v[0] = GetID!(T,Buffer)(ctx.Bound.PixelUnpackBuffer) - } - @if(Version.GLES20) - case GL_POLYGON_OFFSET_FACTOR: { - v[0] = as!T(ctx.Rasterization.PolygonOffsetFactor) - } - @if(Version.GLES20) - case GL_POLYGON_OFFSET_FILL: { - v[0] = as!T(ctx.Rasterization.PolygonOffsetFill) - } - @if(Version.GLES20) - case GL_POLYGON_OFFSET_UNITS: { - v[0] = as!T(ctx.Rasterization.PolygonOffsetUnits) - } - @if(Version.GLES32) - case GL_PRIMITIVE_BOUNDING_BOX: { - write(v[0:8]) - } - @if(Version.GLES30) - case GL_PRIMITIVE_RESTART_FIXED_INDEX: { - v[0] = as!T(ctx.Vertex.PrimitiveRestartFixedIndex) - } - @if(Version.GLES30) - case GL_PROGRAM_BINARY_FORMATS: { - s := v[0:len(ctx.Constants.ProgramBinaryFormats)] - for _ , i , f in ctx.Constants.ProgramBinaryFormats { - s[i] = as!T(f) - } - } - @if(Version.GLES31) - case GL_PROGRAM_PIPELINE_BINDING: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_RASTERIZER_DISCARD: { - v[0] = as!T(ctx.Rasterization.RasterizerDiscard) - } - @if(Version.GLES20) - case GL_READ_BUFFER: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_READ_FRAMEBUFFER_BINDING: { - v[0] = GetID!(T,Framebuffer)(ctx.Bound.ReadFramebuffer) - } - @if(Version.GLES20) - case GL_RED_BITS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_RENDERBUFFER_BINDING: { - v[0] = GetID!(T,Renderbuffer)(ctx.Bound.Renderbuffer) - } - @if(Version.GLES32 || Extension.GL_EXT_robustness) - case GL_RESET_NOTIFICATION_STRATEGY: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_SAMPLE_ALPHA_TO_COVERAGE: { - v[0] = as!T(ctx.Rasterization.SampleAlphaToCoverage) - } - @if(Version.GLES20) - case GL_SAMPLE_BUFFERS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_SAMPLE_COVERAGE: { - v[0] = as!T(ctx.Rasterization.SampleCoverage) - } - @if(Version.GLES20) - case GL_SAMPLE_COVERAGE_INVERT: { - v[0] = as!T(ctx.Rasterization.SampleCoverageInvert) - } - @if(Version.GLES20) - case GL_SAMPLE_COVERAGE_VALUE: { - v[0] = as!T(ctx.Rasterization.SampleCoverageValue) - } - @if(Version.GLES32) - case GL_SAMPLE_SHADING: { - write(v[0:1]) - } - @if(Version.GLES30) - case GL_SAMPLER_BINDING: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_SAMPLES: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_SCISSOR_BOX: { - s := v[0:4] - s[0] = as!T(ctx.Pixel.Scissor.Box.X) - s[1] = as!T(ctx.Pixel.Scissor.Box.Y) - s[2] = as!T(ctx.Pixel.Scissor.Box.Width) - s[3] = as!T(ctx.Pixel.Scissor.Box.Height) - } - @if(Version.GLES20) - case GL_SCISSOR_TEST: { - v[0] = as!T(ctx.Pixel.Scissor.Test) - } - @if(Version.GLES20) - case GL_SHADER_BINARY_FORMATS: { - s := v[0:len(ctx.Constants.ShaderBinaryFormats)] - for _ , i , f in ctx.Constants.ShaderBinaryFormats { - s[i] = as!T(f) - } - } - @if(Version.GLES20) - case GL_SHADER_COMPILER: { - v[0] = as!T(ctx.Constants.ShaderCompiler) - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER_BINDING: { - if isIndexed { - v[0] = GetID!(T,Buffer)(ctx.Bound.ShaderStorageBuffers[index].Binding) - } else { - v[0] = GetID!(T,Buffer)(ctx.Bound.ShaderStorageBuffer) - } - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: { - v[0] = as!T(ctx.Constants.ShaderStorageBufferOffsetAlignment) - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER_SIZE: { - if isIndexed { - v[0] = as!T(ctx.Bound.ShaderStorageBuffers[index].Size) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_SHADER_STORAGE_BUFFER_START: { - if isIndexed { - v[0] = as!T(ctx.Bound.ShaderStorageBuffers[index].Start) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_STENCIL_BACK_FAIL: { - v[0] = as!T(ctx.Pixel.Stencil.BackFail) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_FUNC: { - v[0] = as!T(ctx.Pixel.Stencil.BackFunc) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_PASS_DEPTH_FAIL: { - v[0] = as!T(ctx.Pixel.Stencil.BackPassDepthFail) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_PASS_DEPTH_PASS: { - v[0] = as!T(ctx.Pixel.Stencil.BackPassDepthPass) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_REF: { - v[0] = as!T(ctx.Pixel.Stencil.BackRef) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_VALUE_MASK: { - v[0] = as!T(ctx.Pixel.Stencil.BackValueMask) - } - @if(Version.GLES20) - case GL_STENCIL_BACK_WRITEMASK: { - v[0] = as!T(ctx.Pixel.StencilBackWritemask) - } - @if(Version.GLES20) - case GL_STENCIL_BITS: { - write(v[0:1]) - } - @if(Version.GLES20) - case GL_STENCIL_CLEAR_VALUE: { - v[0] = as!T(ctx.Pixel.StencilClearValue) - } - @if(Version.GLES20) - case GL_STENCIL_FAIL: { - v[0] = as!T(ctx.Pixel.Stencil.Fail) - } - @if(Version.GLES20) - case GL_STENCIL_FUNC: { - v[0] = as!T(ctx.Pixel.Stencil.Func) - } - @if(Version.GLES20) - case GL_STENCIL_PASS_DEPTH_FAIL: { - v[0] = as!T(ctx.Pixel.Stencil.PassDepthFail) - } - @if(Version.GLES20) - case GL_STENCIL_PASS_DEPTH_PASS: { - v[0] = as!T(ctx.Pixel.Stencil.PassDepthPass) - } - @if(Version.GLES20) - case GL_STENCIL_REF: { - v[0] = as!T(ctx.Pixel.Stencil.Ref) - } - @if(Version.GLES20) - case GL_STENCIL_TEST: { - v[0] = as!T(ctx.Pixel.Stencil.Test) - } - @if(Version.GLES20) - case GL_STENCIL_VALUE_MASK: { - v[0] = as!T(ctx.Pixel.Stencil.ValueMask) - } - @if(Version.GLES20) - case GL_STENCIL_WRITEMASK: { - v[0] = as!T(ctx.Pixel.StencilWritemask) - } - @if(Version.GLES20) - case GL_SUBPIXEL_BITS: { - v[0] = as!T(ctx.Constants.SubpixelBits) - } - @if(Version.GLES20) - case GL_TEXTURE_BINDING_2D: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.Binding2d) - } - @if(Version.GLES20) - case GL_TEXTURE_BINDING_EXTERNAL_OES: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.BindingExternalOes) - } - @if(Version.GLES30) - case GL_TEXTURE_BINDING_2D_ARRAY: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.Binding2dArray) - } - @if(Version.GLES31) - case GL_TEXTURE_BINDING_2D_MULTISAMPLE: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.Binding2dMultisample) - } - @if(Version.GLES32) - case GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.Binding2dMultisampleArray) - } - @if(Version.GLES30) - case GL_TEXTURE_BINDING_3D: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.Binding3d) - } - @if(Version.GLES32) - case GL_TEXTURE_BINDING_BUFFER: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.BindingBuffer) - } - @if(Version.GLES20) - case GL_TEXTURE_BINDING_CUBE_MAP: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.BindingCubeMap) - } - @if(Version.GLES32) - case GL_TEXTURE_BINDING_CUBE_MAP_ARRAY: { - v[0] = GetID!(T,Texture)(ctx.Bound.TextureUnit.BindingCubeMapArray) - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER_BINDING: { - write(v[0:1]) - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT: { - v[0] = as!T(ctx.Constants.TextureBufferOffsetAlignment) - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_ACTIVE: { - v[0] = as!T(ctx.Bound.TransformFeedback.Active) - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BINDING: { - v[0] = GetID!(T,TransformFeedback)(ctx.Bound.TransformFeedback) - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: { - if isIndexed { - v[0] = GetID!(T,Buffer)(ctx.Bound.TransformFeedback.Buffers[index].Binding) - } else { - v[0] = GetID!(T,Buffer)(ctx.Bound.TransformFeedbackBuffer) - } - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: { - if isIndexed { - v[0] = as!T(ctx.Bound.TransformFeedback.Buffers[index].Size) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_BUFFER_START: { - if isIndexed { - v[0] = as!T(ctx.Bound.TransformFeedback.Buffers[index].Start) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES30) - case GL_TRANSFORM_FEEDBACK_PAUSED: { - v[0] = as!T(ctx.Bound.TransformFeedback.Paused) - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER_BINDING: { - if isIndexed { - v[0] = GetID!(T,Buffer)(ctx.Bound.UniformBuffers[index].Binding) - } else { - v[0] = GetID!(T,Buffer)(ctx.Bound.UniformBuffer) - } - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: { - v[0] = as!T(ctx.Constants.UniformBufferOffsetAlignment) - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER_SIZE: { - if isIndexed { - v[0] = as!T(ctx.Bound.UniformBuffers[index].Size) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES30) - case GL_UNIFORM_BUFFER_START: { - if isIndexed { - v[0] = as!T(ctx.Bound.UniformBuffers[index].Start) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_UNPACK_ALIGNMENT: { - v[0] = as!T(ctx.Other.Unpack.Alignment) - } - @if(Version.GLES30) - case GL_UNPACK_IMAGE_HEIGHT: { - v[0] = as!T(ctx.Other.Unpack.ImageHeight) - } - @if(Version.GLES30) - case GL_UNPACK_ROW_LENGTH: { - v[0] = as!T(ctx.Other.Unpack.RowLength) - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_IMAGES: { - v[0] = as!T(ctx.Other.Unpack.SkipImages) - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_PIXELS: { - v[0] = as!T(ctx.Other.Unpack.SkipPixels) - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_ROWS: { - v[0] = as!T(ctx.Other.Unpack.SkipRows) - } - @if(Version.GLES30) - case GL_VERTEX_ARRAY_BINDING: { - v[0] = GetID!(T,VertexArray)(ctx.Bound.VertexArray) - } - @if(Version.GLES31) - case GL_VERTEX_BINDING_DIVISOR: { - if isIndexed { - i := as!VertexBufferBindingIndex(index) - v[0] = as!T(ctx.Bound.VertexArray.VertexBufferBindings[i].Divisor) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_VERTEX_BINDING_OFFSET: { - if isIndexed { - i := as!VertexBufferBindingIndex(index) - v[0] = as!T(ctx.Bound.VertexArray.VertexBufferBindings[i].Offset) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES31) - case GL_VERTEX_BINDING_STRIDE: { - if isIndexed { - i := as!VertexBufferBindingIndex(index) - v[0] = as!T(ctx.Bound.VertexArray.VertexBufferBindings[i].Stride) - } else { - glErrorInvalidEnum(name) - } - } - @if(Version.GLES20) - case GL_VIEWPORT: { - s := v[0:4] - s[0] = as!T(ctx.Rasterization.Viewport.X) - s[1] = as!T(ctx.Rasterization.Viewport.Y) - s[2] = as!T(ctx.Rasterization.Viewport.Width) - s[3] = as!T(ctx.Rasterization.Viewport.Height) - } - @if(Extension.GL_EXT_texture_filter_anisotropic) - case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: { - v[0] = as!T(ctx.Constants.MaxTextureMaxAnisotropyExt) - } - @if(Extension.GL_EXT_disjoint_timer_query) - case GL_GPU_DISJOINT_EXT: { - write(v[0:1]) - } - @if(Extension.GL_EXT_clip_cull_distance) - case GL_MAX_CLIP_DISTANCES_EXT, GL_MAX_CULL_DISTANCES_EXT, GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES_EXT: { - write(v[0:1]) - } - default: { - glErrorInvalidEnum(name) - } - } -} - diff --git a/gapis/api/gles/api/synchronization.api b/gapis/api/gles/api/synchronization.api deleted file mode 100644 index 57b0a8e1b2..0000000000 --- a/gapis/api/gles/api/synchronization.api +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class SyncObject { - GLsync ID - -// Table 21.37: Sync (state per sync object) - GLenum Type = GL_SYNC_FENCE -// GLenum SyncStatus = GL_UNSIGNALED - GLenum Condition = GL_SYNC_GPU_COMMANDS_COMPLETE - GLbitfield Flags - - string Label -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glClientWaitSync.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glClientWaitSync.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glClientWaitSync.xhtml", Version.GLES32) -cmd GLenum glClientWaitSync(GLsync sync, GLbitfield syncFlags, GLuint64 timeout) { - ClientWaitSync(sync, syncFlags, timeout) - return ? -} - -sub void ClientWaitSync(GLsync sync, GLbitfield syncFlags, GLuint64 timeout) { - supportsBits(syncFlags, GL_SYNC_FLUSH_COMMANDS_BIT) - ctx := GetContext() - if !(sync in ctx.Objects.SyncObjects) { glErrorInvalidObjectName!GLsync(sync) } - if (GL_SYNC_FLUSH_COMMANDS_BIT in syncFlags) { - } - _ = timeout // TODO -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteSync.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteSync.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteSync.xhtml", Version.GLES32) -cmd void glDeleteSync(GLsync sync) { - DeleteSync(sync) -} - -sub void DeleteSync(GLsync sync) { - if sync != null { - ctx := GetContext() - if !(sync in ctx.Objects.SyncObjects) { glErrorInvalidValue!GLsync(sync) } - delete(ctx.Objects.SyncObjects, sync) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glFenceSync.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glFenceSync.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glFenceSync.xhtml", Version.GLES32) -cmd GLsync glFenceSync(GLenum condition, GLbitfield syncFlags) { - sync := as!GLsync(?) - FenceSync(condition, syncFlags, sync) - return sync -} - -sub void FenceSync(GLenum condition, GLbitfield syncFlags, GLsync sync) { - if condition != GL_SYNC_GPU_COMMANDS_COMPLETE { glErrorInvalidEnum(condition) } - CheckEQ!GLbitfield(syncFlags, as!GLbitfield(0)) - ctx := GetContext() - if (sync != null) { - ctx.Objects.SyncObjects[sync] = new!SyncObject( - ID: sync, - Type: GL_SYNC_FENCE, - Condition: condition, - Flags: syncFlags) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetSynciv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetSynciv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetSynciv.xhtml", Version.GLES32) -cmd void glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { - GetSynciv(sync, pname, bufSize, length, values) -} - -sub void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { - _ = sync // TODO: Use or lose. - switch (pname) { - case GL_OBJECT_TYPE, GL_SYNC_CONDITION, GL_SYNC_FLAGS, GL_SYNC_STATUS: { - // version 3.0 - if (values != null) && (bufSize > 0) { - values[0] = ? - if length != null { - length[0] = 1 - } - } - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsSync.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsSync.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsSync.xhtml", Version.GLES32) -cmd GLboolean glIsSync(GLsync sync) { - return IsSync(sync) -} - -sub GLboolean IsSync(GLsync sync) { - ctx := GetContext() - return toGLboolean(sync in ctx.Objects.SyncObjects) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glWaitSync.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glWaitSync.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glWaitSync.xhtml", Version.GLES32) -cmd void glWaitSync(GLsync sync, GLbitfield syncFlags, GLuint64 timeout) { - WaitSync(sync, syncFlags, timeout) -} - -sub void WaitSync(GLsync sync, GLbitfield syncFlags, GLuint64 timeout) { - ctx := GetContext() - if !(sync in ctx.Objects.SyncObjects) { - glErrorInvalidOperation_ObjectDoesNotExist!GLsync(sync) - } - CheckEQ!GLuint64(timeout, 0xFFFFFFFFFFFFFFFF) // GL_TIMEOUT_IGNORED - CheckEQ!GLbitfield(syncFlags, as!GLbitfield(0)) -} diff --git a/gapis/api/gles/api/textures_and_samplers.api b/gapis/api/gles/api/textures_and_samplers.api deleted file mode 100644 index 43eda5905c..0000000000 --- a/gapis/api/gles/api/textures_and_samplers.api +++ /dev/null @@ -1,2021 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class TextureUnit { - TextureUnitId ID - - // Table 21.9: Textures (selector; state per texture unit) - ref!Texture Binding2d = null - ref!Texture Binding3d = null - ref!Texture Binding2dArray = null - ref!Texture BindingBuffer = null - ref!Texture BindingCubeMap = null - ref!Texture BindingCubeMapArray = null - ref!Texture Binding2dMultisample = null - ref!Texture Binding2dMultisampleArray = null - ref!Texture BindingExternalOes = null // OES_EGL_image_external - ref!Sampler SamplerBinding = null -} - -sub ref!TextureUnit NewTextureUnit(TextureUnitId id) { - ctx := GetContext() - return new!TextureUnit( - ID: id, - Binding2d: ctx.Objects.Default.Texture2d, - Binding2dArray: ctx.Objects.Default.Texture2dArray, - Binding2dMultisample: ctx.Objects.Default.Texture2dMultisample, - Binding2dMultisampleArray: ctx.Objects.Default.Texture2dMultisampleArray, - Binding3d: ctx.Objects.Default.Texture3d, - BindingBuffer: ctx.Objects.Default.TextureBuffer, - BindingCubeMap: ctx.Objects.Default.TextureCubeMap, - BindingCubeMapArray: ctx.Objects.Default.TextureCubeMapArray, - BindingExternalOes: ctx.Objects.Default.TextureExternalOes, - ) -} - -@internal -@resource -class Texture { - TextureId ID - - GLenum Kind - ref!Image Image // Alias for Levels[0].Layers[0] - map!(GLint, Level) Levels - TextureBufferBinding Buffer - - // Table 21.10: Textures (state per texture object) - GLenum SwizzleR = GL_RED - GLenum SwizzleG = GL_GREEN - GLenum SwizzleB = GL_BLUE - GLenum SwizzleA = GL_ALPHA - @unused Vec4f BorderColor = Vec4f(0.0, 0.0, 0.0, 0.0) - @unused Vec4i BorderColorI = Vec4i(0, 0, 0, 0) // TODO: Set - GLenum MinFilter = GL_NEAREST_MIPMAP_LINEAR - GLenum MagFilter = GL_LINEAR - GLenum WrapS = GL_REPEAT - GLenum WrapT = GL_REPEAT - GLenum WrapR = GL_REPEAT - GLfloat MinLod = -1000 - GLfloat MaxLod = 1000 - GLint BaseLevel = 0 - GLint MaxLevel = 1000 - GLenum DepthStencilTextureMode = GL_DEPTH_COMPONENT - GLenum CompareMode = GL_NONE - GLenum CompareFunc = GL_LEQUAL - GLboolean ImmutableFormat = GL_FALSE - @unused GLuint ImmutableLevels = 0 - @unused string Label - - // EXT_texture_filter_anisotropic - GLfloat MaxAnisotropy = 1.0 - - // EXT_texture_sRGB_decode - GLenum DecodeSRGB = GL_DECODE_EXT - - // GL_OES_EGL_image - // EGL image which is used as storage for this texture. - // TODO: Standard glTex* methods which define new storage should clear this. - @unused ref!EGLImage EGLImage -} - -@internal -class TextureBufferBinding { - ref!Buffer Binding - GLenum InternalFormat = GL_R8 - GLintptr Offset - GLsizeiptr Size -} - -@internal -class Level { - // Note on layers: Why not remove this and add Depth to image? - // GL allows binding differently sized images to cubemap faces. - // (although drawing with such strange cubemap is not allowed) - map!(GLint, ref!Image) Layers -} - -@internal -class Image { - GLsizei Width - GLsizei Height - GLsizei Samples - GLboolean FixedSampleLocations = GL_TRUE - // GPU format of the texture including bit-sizes of the channels. - // This is unrelated to the format of the data passed to the API. - @unused GLenum SizedFormat - - @internal @spy_disabled u8[] Data - // Tuple of (format, type) describing the Data field above. - // This describes the format of the data the user passed in, - // not the format of the data stored on the GPU (sizedFormat). - // TODO: We should use the GPU format, but that needs conversions. - // One of the following: - // (GL_NONE, GL_NONE) - No data was uploaded yet. - // (unsizedFormat, ty) - Uncompressed data. - // (sizedFormat, GL_NONE) - Compressed data. - @unused GLenum DataFormat - @unused GLenum DataType - - // The internal format as specified by the application. It may be - // the same as SizedFormat, if the application requested a sized - // format, but may be unsized and different from SizedFormat, or - // GL_NONE for compressed textures and non texture images. - @unused GLenum InternalFormat -} - -@internal -class Sampler { - SamplerId ID - - // Table 21.12: Textures (state per sampler object) - @unused Vec4f BorderColor = Vec4f(0.0, 0.0, 0.0, 0.0) - @unused Vec4i BorderColorI = Vec4i(0, 0, 0, 0) - GLenum MinFilter = GL_NEAREST_MIPMAP_LINEAR - GLenum MagFilter = GL_LINEAR - GLenum WrapS = GL_REPEAT - GLenum WrapT = GL_REPEAT - GLenum WrapR = GL_REPEAT - GLfloat MinLod = -1000 - GLfloat MaxLod = 1000 - GLenum CompareMode = GL_NONE - GLenum CompareFunc = GL_LEQUAL - @unused string Label - - // EXT_texture_filter_anisotropic - GLfloat MaxAnisotropy = 1.0 - - // EXT_texture_sRGB_decode - GLenum DecodeSRGB = GL_DECODE_EXT -} - -@internal -class PixelStorageState { - // Table 21.18: Pixels - GLint ImageHeight = 0 - GLint SkipImages = 0 - GLint RowLength = 0 - GLint SkipRows = 0 - GLint SkipPixels = 0 - GLint Alignment = 4 -} - -@internal -class ImageUnit { - ImageUnitId ID - - // Table 21.33: Image State (state per image unit) - ref!Texture Texture - GLint Level = 0 - GLboolean Layered = GL_FALSE - GLint Layer = 0 - GLenum Access = GL_READ_ONLY - GLenum Format = GL_R32UI -} - -sub ref!Image GetTextureImage(ref!Texture tex, GLint level, GLint layer) { - return switch tex == null { - case true: null - case false: tex.Levels[level].Layers[layer] - } -} - -sub void SetTextureImage(ref!Texture tex, GLint level, GLint layer, ref!Image img) { - assert(tex != null) - tmp := tex.Levels[level] - tmp.Layers[layer] = img - tex.Levels[level] = tmp - if (level == 0) && (layer == 0) { - tex.Image = img - } -} - -// The spec maps cubemap faces to layers 0..5 in the exact order of GLenum values. -sub GLint CubemapFaceToLayer(GLenum target) { - return switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - as!GLint(target) - as!GLint(GL_TEXTURE_CUBE_MAP_POSITIVE_X) - default: - as!GLint(0) - } -} - -sub ref!Texture GetBoundTextureOrErrorInvalidEnum(GLenum target) { - ctx := GetContext() - return GetBoundTextureForUnit(ctx.Bound.TextureUnit, target) -} - -sub ref!Texture GetBoundTextureForUnit(ref!TextureUnit tu, GLenum target) { - return switch (target) { - @if(Version.GLES20) - case GL_TEXTURE_2D: { - tu.Binding2d - } - @if(Version.GLES20) - case GL_TEXTURE_EXTERNAL_OES: { - tu.BindingExternalOes - } - @if(Version.GLES30) - case GL_TEXTURE_2D_ARRAY: { - tu.Binding2dArray - } - @if(Version.GLES31) - case GL_TEXTURE_2D_MULTISAMPLE: { - tu.Binding2dMultisample - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { - tu.Binding2dMultisampleArray - } - @if(Version.GLES30) - case GL_TEXTURE_3D: { - tu.Binding3d - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER: { - tu.BindingBuffer - } - @if(Version.GLES20) - case GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { - tu.BindingCubeMap - } - @if(Version.GLES32) - case GL_TEXTURE_CUBE_MAP_ARRAY: { - tu.BindingCubeMapArray - } - default: { - // TODO: glErrorInvalidEnum(target) - tu.Binding2d - } - } -} - -@ignore_unreachables -sub GLenum GetTextureTargetFromSamplerType(GLenum samplerType) { - return switch (samplerType) { - case GL_INT_SAMPLER_2D, GL_SAMPLER_2D, GL_UNSIGNED_INT_SAMPLER_2D, GL_SAMPLER_2D_SHADOW: - GL_TEXTURE_2D - case GL_INT_SAMPLER_2D_ARRAY, GL_SAMPLER_2D_ARRAY, GL_UNSIGNED_INT_SAMPLER_2D_ARRAY, GL_SAMPLER_2D_ARRAY_SHADOW: - GL_TEXTURE_2D_ARRAY - case GL_INT_SAMPLER_2D_MULTISAMPLE, GL_SAMPLER_2D_MULTISAMPLE, GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: - GL_TEXTURE_2D_MULTISAMPLE - case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_SAMPLER_2D_MULTISAMPLE_ARRAY, GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: - GL_TEXTURE_2D_MULTISAMPLE_ARRAY - case GL_INT_SAMPLER_3D, GL_SAMPLER_3D, GL_UNSIGNED_INT_SAMPLER_3D: - GL_TEXTURE_3D - case GL_INT_SAMPLER_BUFFER, GL_SAMPLER_BUFFER, GL_UNSIGNED_INT_SAMPLER_BUFFER: - GL_TEXTURE_BUFFER - case GL_INT_SAMPLER_CUBE, GL_SAMPLER_CUBE, GL_UNSIGNED_INT_SAMPLER_CUBE, GL_SAMPLER_CUBE_SHADOW: - GL_TEXTURE_CUBE_MAP - case GL_INT_SAMPLER_CUBE_MAP_ARRAY, GL_SAMPLER_CUBE_MAP_ARRAY, GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY, GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: - GL_TEXTURE_CUBE_MAP_ARRAY - case GL_SAMPLER_EXTERNAL_OES: - GL_TEXTURE_EXTERNAL_OES - default: - GL_NONE - } -} - -sub SizedFormatInfo GetSizedFormatInfoOrEnumError(GLenum internalformat) { - info := GetSizedFormatInfo(internalformat) - if info.UnsizedFormat == GL_NONE { - glErrorInvalidEnum(internalformat) - } - return info -} - -@ignore_unreachables -sub SizedFormatInfo GetSizedFormatInfoOrValueError(GLint internalformat) { - info := GetSizedFormatInfo(as!GLenum(internalformat)) - if info.UnsizedFormat == GL_NONE { - glErrorInvalidValue!GLint(internalformat) - } - return info -} - -sub UnsizedFormatInfo GetUnsizedFormatInfoOrEnumError(GLenum format) { - info := GetUnsizedFormatInfo(format) - if info.Count == 0 { - glErrorInvalidEnum(format) - } - return info -} - -@internal -bitfield TexImageFlags { - IsCompressedTexImageCmd = 1, - IsCopyTexImageCmd = 2, - IsTexImageCmd = 4, - IsTexStorageCmd = 8, - HasSubModifier = 16, - Has3DModifier = 32, - HasMultisampleModifier = 64, -} - -// Uber-function to handle all texture image specification commands. -sub void TexImage(TexImageFlags flags, - GLenum target, - // Offsets - GLint loffset, - GLint xoffset, - GLint yoffset, - GLint zoffset, - // Dimensions - GLsizei levels, - GLsizei width, - GLsizei height, - GLsizei depth, - GLint border, - GLsizei samples, - GLboolean fixedsamplelocations, - // Format&data - GLenum sized_format, - GLenum data_format, - GLenum data_type, - GLsizei data_size, - TexturePointer data) { - isCompressedTexImageCmd := IsCompressedTexImageCmd in flags - isCopyTexImageCmd := IsCopyTexImageCmd in flags - isTexImageCmd := IsTexImageCmd in flags - isTexStorageCmd := IsTexStorageCmd in flags - hasSubModifier := HasSubModifier in flags - has3DModifier := Has3DModifier in flags - hasMultisampleModifier := HasMultisampleModifier in flags - - sfBox := Image(SizedFormat: sized_format) - - // Check target - if hasMultisampleModifier { - if has3DModifier { - if target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY { glErrorInvalidEnum(target) } - } else { - if target != GL_TEXTURE_2D_MULTISAMPLE { glErrorInvalidEnum(target) } - } - } else { - if has3DModifier { - switch (target) { - case GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARRAY: { } - default: { glErrorInvalidEnum(target) } - } - } else { - if isTexStorageCmd { - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP: { } - default: { glErrorInvalidEnum(target) } - } - } else { - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z: { } - default: { glErrorInvalidEnum(target) } - } - } - } - } - t := GetBoundTextureOrErrorInvalidEnum(target) - - // Check offsets and sizes - CheckGE!GLint(loffset, 0) - CheckGE!GLint(xoffset, 0) - CheckGE!GLint(yoffset, 0) - CheckGE!GLint(zoffset, 0) - CheckGE!GLsizei(levels, 1) - CheckSizeGE!GLsizei(width, 0) - CheckSizeGE!GLsizei(height, 0) - CheckSizeGE!GLsizei(depth, 0) - CheckEQ!GLint(border, 0) - CheckGE!GLsizei(data_size, 0) - switch target { - case GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { - CheckEQ!GLsizei(width, height) - } - default: { } - } - - // Check the data_format and data_type - if isTexImageCmd { - _ = GetUnsizedFormatInfoOrEnumError(data_format) - CheckTextureDataType(data_type) - } - - // Check the sized_format - if !hasSubModifier { - if isTexImageCmd && as!GLenum(sized_format) == data_format { - sf := GetSizedFormatFromTuple(data_format, data_type) - if sf == GL_NONE { glErrorInvalidOperation() } // Invalid combination of format and type - sfBox.SizedFormat = sf // Legacy - sized format is inferred from data format and type - } else { - sizedFormatInfo := GetSizedFormatInfoOrEnumError(sized_format) - isCompressedFmt := sizedFormatInfo.Compression != Uncompressed - if isCompressedTexImageCmd { - if !isCompressedFmt { glErrorInvalidEnum(sized_format) } // Requires compressed format - } - if isCopyTexImageCmd || isTexImageCmd || hasMultisampleModifier { - if isCompressedFmt { glErrorInvalidEnum(sized_format) } // Requires uncompressed format - } - } - } - - // We need to do all checks before we start modifying state. - cubemap_layer := CubemapFaceToLayer(target) - for l in (0 .. as!GLint(levels)) { - for z in (0 .. as!GLint(depth)) { - if hasSubModifier { - i := GetTextureImage(t, loffset + l, zoffset + z + cubemap_layer) - if (i == null) { glErrorInvalidOperation() } - CheckLE!GLsizei((as!GLsizei(xoffset) + width), i.Width) - CheckLE!GLsizei((as!GLsizei(yoffset) + height), i.Height) - } - } - } - - // TODO(hevrard): check that if t.ImmutableFormat == GL_TRUE, we are - // not trying to attempt to modify the format or dimension of any - // level (see GLES 3.2 spec '8.18 Immutable-Format Texture Images') - - if isTexStorageCmd { - t.ImmutableLevels = as!GLuint(levels) - t.ImmutableFormat = GL_TRUE - // Clean up levels with an empty map (produced via Texture().Levels) - // before setting them again in the subsequent loop - t.Levels = Texture().Levels - } - - ctx := GetContext() - for l in (0 .. as!GLint(levels)) { - // Depth decreases with each level for 3D textures, but not for arrays. - mipDepth := max!GLsizei(1, depth >> as!u32(l)) - for z in (0 .. as!GLint(Select!GLsizei(target == GL_TEXTURE_3D, mipDepth, depth))) { - if !hasSubModifier { - // Initialize the image with the provided parameters - SetTextureImage(t, loffset + l, zoffset + z + cubemap_layer, new!Image( - Width: max!GLsizei(1, width >> as!u32(l)), - Height: max!GLsizei(1, height >> as!u32(l)), - Samples: samples, - FixedSampleLocations: fixedsamplelocations, - SizedFormat: sfBox.SizedFormat, - InternalFormat: sized_format, - DataFormat: data_format, - DataType: data_type)) - } - - // Update the content of the image - img := GetTextureImage(t, loffset + l, zoffset + z + cubemap_layer) - if isTexImageCmd { - src_skip_images := Select!GLint(has3DModifier, ctx.Other.Unpack.SkipImages, 0) + z - UpdateImageData(img, xoffset, yoffset, width, height, - src_skip_images, data_format, data_type, data) - } else if isCompressedTexImageCmd { - if (ctx.Bound.PixelUnpackBuffer == null) && (data != null) { - // TODO: Implement sub-range updates - img.Data = make!u8(data_size) - copy(img.Data, as!u8*(data)[0:data_size]) - img.DataFormat = data_format - } else { - // TODO: Implement copy from unpack buffer - img.Data = make!u8(data_size) - img.DataFormat = data_format - } - } else if isTexStorageCmd { - info := GetSizedFormatInfo(sfBox.SizedFormat) - img.Data = make!u8(uncompressedImageSize(width, height, info.UnsizedFormat, info.DataType)) - img.DataFormat = data_format - } - } - } - - // Dependency reads - _ = ctx.Other.Unpack.Alignment -} - -sub void UpdateImageData(ref!Image dst_image, - GLint dst_xoffset, - GLint dst_yoffset, - GLsizei width, - GLsizei height, - GLint src_skip_images, - GLenum format, - GLenum type, - TexturePointer data) { - ctx := GetContext() - unpack := ctx.Other.Unpack - url := SelectNonZero!GLint(unpack.RowLength, as!GLint(width)) - pixel_size := as!GLint(uncompressedPixelSize(format, type)) - - src_row_size := Align!GLint(url * pixel_size, unpack.Alignment) - src_image_size := SelectNonZero!GLint(unpack.ImageHeight, as!GLint(height)) * src_row_size - src_offset := (unpack.SkipPixels * pixel_size) + - (unpack.SkipRows * src_row_size) + - (src_skip_images * src_image_size) - - dst_row_size := as!GLint(dst_image.Width) * pixel_size - dst_image_size := as!GLint(dst_image.Height) * dst_row_size - dst_offset := (dst_xoffset * pixel_size) + (dst_yoffset * dst_row_size) - - // Initialize the buffer if we have not used the image before or - // if the format changed to one with different size per texel. - // TODO: Do this properly using data conversion. - if len(dst_image.Data) != as!s32(dst_image_size) { - dst_image.Data = make!u8(dst_image_size) - } - dst_image.DataFormat = format - dst_image.DataType = type - - pbo := ctx.Bound.PixelUnpackBuffer - copy_size := as!GLint(width) * pixel_size - for y in (0 .. as!GLint(height)) { - dst := dst_offset + (dst_row_size * y) - if pbo == null { - if data != null { - src := src_offset + (src_row_size * y) - copy(dst_image.Data[dst:dst + copy_size], as!u8*(data)[src:src + copy_size]) - } - } else { - src := as!u64(data) + as!u64(src_offset + (src_row_size * y)) - assert((src + as!u64(copy_size)) <= len(pbo.Data)) - copy(dst_image.Data[dst:dst + copy_size], pbo.Data[src:src + as!u64(copy_size)]) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glActiveTexture.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glActiveTexture.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glActiveTexture.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glActiveTexture.xhtml", Version.GLES32) -cmd void glActiveTexture(GLenum unit) { - // TODO: Tidy this. This switch case is preserved for the snippet system. - switch (unit) { - case GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE10, GL_TEXTURE11, GL_TEXTURE12, GL_TEXTURE13, - GL_TEXTURE14, GL_TEXTURE15, GL_TEXTURE16, GL_TEXTURE17, GL_TEXTURE18, GL_TEXTURE19, - GL_TEXTURE2, GL_TEXTURE20, GL_TEXTURE21, GL_TEXTURE22, GL_TEXTURE23, GL_TEXTURE24, - GL_TEXTURE25, GL_TEXTURE26, GL_TEXTURE27, GL_TEXTURE28, GL_TEXTURE29, GL_TEXTURE3, - GL_TEXTURE30, GL_TEXTURE31, GL_TEXTURE4, GL_TEXTURE5, GL_TEXTURE6, GL_TEXTURE7, - GL_TEXTURE8, GL_TEXTURE9: { - // version 2.0 - } - default: { - // Higher texture numbers are still valid, but they do not have GLenum entries. - } - } - ctx := GetContext() - tu := ctx.Objects.TextureUnits[as!TextureUnitId(unit - GL_TEXTURE0)] - if tu == null { glErrorInvalidEnum(unit) } - ctx.Bound.TextureUnit = tu -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindImageTexture.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindImageTexture.xhtml", Version.GLES32) -cmd void glBindImageTexture(ImageUnitId unit, - TextureId texture, - GLint level, - GLboolean layered, - GLint layer, - GLenum access, - GLenum format) { - switch (access) { - case GL_READ_ONLY, GL_READ_WRITE, GL_WRITE_ONLY: { - // version 3.1 - } - default: { - glErrorInvalidEnum(access) - } - } - switch (format) { - case GL_R32F, GL_R32I, GL_R32UI, GL_RGBA16F, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32F, GL_RGBA32I, - GL_RGBA32UI, GL_RGBA8, GL_RGBA8I, GL_RGBA8UI, GL_RGBA8_SNORM: { - // version 3.1 - } - default: { - glErrorInvalidEnum(format) - } - } - ctx := GetContext() - if texture == 0 { - ctx.Objects.ImageUnits[unit] = new!ImageUnit(ID:unit) - } else { - t := ctx.Objects.Textures[texture] - if t == null { glErrorInvalidOperation_ObjectDoesNotExist!TextureId(texture) } - // TODO: Check that it is immutable - ctx.Objects.ImageUnits[unit] = new!ImageUnit( - ID: unit, - Texture: t, - Level: level, - Layered: layered, - Layer: layer, - Access: access, - Format: format - ) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindSampler.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindSampler.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindSampler.xhtml", Version.GLES32) -cmd void glBindSampler(GLuint index, SamplerId sampler) { - ctx := GetContext() - tu := ctx.Objects.TextureUnits[as!TextureUnitId(index)] - if tu == null { glErrorInvalidValue!GLuint(index) } - tu.SamplerBinding = GetOrCreateSampler(sampler) -} - -sub ref!Sampler GetOrCreateSampler(SamplerId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.Samplers[id] == null) { - if !ctx.Objects.GeneratedNames.Samplers[id] { - glErrorInvalidOperation_ObjectDoesNotExist!SamplerId(id) - } - ctx.Objects.Samplers[id] = new!Sampler(ID: id) - } - return ctx.Objects.Samplers[id] -} - -sub ref!Texture GetOrCreateTexture(GLenum target, TextureId texture, ref!Texture defaultTexture) { - ctx := GetContext() - if (texture != 0) { - // Create the texture if it does not exist already - if (ctx.Objects.Textures[texture] == null) { - if target == GL_TEXTURE_EXTERNAL_OES { - ctx.Objects.Textures[texture] = new!Texture( - ID: texture, - WrapS: GL_CLAMP_TO_EDGE, - WrapT: GL_CLAMP_TO_EDGE, - MinFilter: GL_LINEAR) - } else { - ctx.Objects.Textures[texture] = new!Texture(ID: texture) - } - } - - // Dependency: set GeneratedNames.Textures[texture] only if it has not - // been set previously by glGenTexture() - if !ctx.Objects.GeneratedNames.Textures[texture] { - ctx.Objects.GeneratedNames.Textures[texture] = true - } - - // Set or check the kind of the texture - t := ctx.Objects.Textures[texture] - if t.Kind == as!GLenum(0) { - t.Kind = target - } else { - if t.Kind != target { glErrorInvalidOperation() } - } - } - return Select!ref!Texture(texture != 0, ctx.Objects.Textures[texture], defaultTexture) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindTexture.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindTexture.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindTexture.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindTexture.xhtml", Version.GLES32) -cmd void glBindTexture(GLenum target, TextureId texture) { - ctx := GetContext() - tu := ctx.Bound.TextureUnit - BindTextureForUnit(tu, target, texture) -} - -sub void BindTextureForUnit(ref!TextureUnit tu, GLenum target, TextureId texture) { - ctx := GetContext() - switch (target) { - @if(Version.GLES20) - case GL_TEXTURE_2D: { - tu.Binding2d = GetOrCreateTexture(target, texture, ctx.Objects.Default.Texture2d) - } - @if(Version.GLES20) - case GL_TEXTURE_EXTERNAL_OES: { - tu.BindingExternalOes = GetOrCreateTexture(target, texture, ctx.Objects.Default.TextureExternalOes) - } - @if(Version.GLES30) - case GL_TEXTURE_2D_ARRAY: { - tu.Binding2dArray = GetOrCreateTexture(target, texture, ctx.Objects.Default.Texture2dArray) - } - @if(Version.GLES31) - case GL_TEXTURE_2D_MULTISAMPLE: { - tu.Binding2dMultisample = GetOrCreateTexture(target, texture, ctx.Objects.Default.Texture2dMultisample) - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { - tu.Binding2dMultisampleArray = GetOrCreateTexture(target, texture, ctx.Objects.Default.Texture2dMultisampleArray) - } - @if(Version.GLES30) - case GL_TEXTURE_3D: { - tu.Binding3d = GetOrCreateTexture(target, texture, ctx.Objects.Default.Texture3d) - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER: { - tu.BindingBuffer = GetOrCreateTexture(target, texture, ctx.Objects.Default.TextureBuffer) - } - @if(Version.GLES20) - case GL_TEXTURE_CUBE_MAP: { - tu.BindingCubeMap = GetOrCreateTexture(target, texture, ctx.Objects.Default.TextureCubeMap) - } - @if(Version.GLES32) - case GL_TEXTURE_CUBE_MAP_ARRAY: { - tu.BindingCubeMapArray = GetOrCreateTexture(target, texture, ctx.Objects.Default.TextureCubeMapArray) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCompressedTexImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCompressedTexImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCompressedTexImage2D.xhtml", Version.GLES32) -cmd void glCompressedTexImage2D(GLenum target, - GLint level, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLint border, - GLsizei image_size, - TexturePointer data) { - TexImage(IsCompressedTexImageCmd, target, - level, 0, 0, 0, // Offsets - 1, width, height, 1, border, 0, GL_TRUE, // Dimensions - internalformat, internalformat, GL_NONE, image_size, data) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexImage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCompressedTexImage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCompressedTexImage3D.xhtml", Version.GLES32) -cmd void glCompressedTexImage3D(GLenum target, - GLint level, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLint border, - GLsizei image_size, - TexturePointer data) { - CompressedTexImage3D(target, level, internalformat, width, height, depth, border, image_size, data) -} - -sub void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei image_size, TexturePointer data) { - TexImage(IsCompressedTexImageCmd | Has3DModifier, target, - level, 0, 0, 0, // Offsets - 1, width, height, depth, border, 0, GL_TRUE, // Dimensions - internalformat, internalformat, GL_NONE, image_size, data) // Format&data -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCompressedTexSubImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexSubImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCompressedTexSubImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCompressedTexSubImage2D.xhtml", Version.GLES32) -cmd void glCompressedTexSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLsizei width, - GLsizei height, - GLenum internalformat, - GLsizei image_size, - TexturePointer data) { - TexImage(IsCompressedTexImageCmd | HasSubModifier, target, - level, xoffset, yoffset, 0, // Offsets - 1, width, height, 1, 0, 0, GL_TRUE, // Dimensions - internalformat, internalformat, GL_NONE, image_size, data) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCompressedTexSubImage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCompressedTexSubImage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCompressedTexSubImage3D.xhtml", Version.GLES32) -cmd void glCompressedTexSubImage3D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLenum internalformat, - GLsizei image_size, - TexturePointer data) { - CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, internalformat, image_size, data) -} - -sub void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum internalformat, GLsizei image_size, TexturePointer data) { - TexImage(IsCompressedTexImageCmd | HasSubModifier | Has3DModifier, target, - level, xoffset, yoffset, zoffset, // Offsets - 1, width, height, depth, 0, 0, GL_TRUE, // Dimensions - internalformat, internalformat, GL_NONE, image_size, data) // Format&data -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCopyImageSubData.xhtml", Version.GLES32) -cmd void glCopyImageSubData(SrcImageId srcName, - GLenum srcTarget, - GLint srcLevel, - GLint srcX, - GLint srcY, - GLint srcZ, - DstImageId dstName, - GLenum dstTarget, - GLint dstLevel, - GLint dstX, - GLint dstY, - GLint dstZ, - GLsizei srcWidth, - GLsizei srcHeight, - GLsizei srcDepth) { - CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth) -} - -sub void CopyImageSubData(SrcImageId srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, DstImageId dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) { - switch (srcTarget) { - case GL_RENDERBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_MULTISAMPLE, - GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, - GL_TEXTURE_CUBE_MAP_ARRAY: { - // version 3.2 - } - default: { - glErrorInvalidEnum(srcTarget) - } - } - switch (dstTarget) { - case GL_RENDERBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_MULTISAMPLE, - GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, - GL_TEXTURE_CUBE_MAP_ARRAY: { - // version 3.2 - } - default: { - glErrorInvalidEnum(dstTarget) - } - } - - _ = srcName // TODO - _ = srcLevel // TODO - _ = srcX // TODO - _ = srcY // TODO - _ = srcZ // TODO - _ = dstName // TODO - _ = dstLevel // TODO - _ = dstX // TODO - _ = dstY // TODO - _ = dstZ // TODO - _ = srcWidth // TODO - _ = srcHeight // TODO - _ = srcDepth // TODO -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCopyTexImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCopyTexImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCopyTexImage2D.xhtml", Version.GLES32) -cmd void glCopyTexImage2D(GLenum target, - GLint level, - GLenum internalformat, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLint border) { - TexImage(IsCopyTexImageCmd, target, - level, 0, 0, 0, // Offsets - 1, width, height, 1, border, 0, GL_TRUE, // Dimensions - internalformat, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glCopyTexSubImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCopyTexSubImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCopyTexSubImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCopyTexSubImage2D.xhtml", Version.GLES32) -cmd void glCopyTexSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - TexImage(IsCopyTexImageCmd | HasSubModifier, target, - level, xoffset, yoffset, 0, // Offsets - 1, width, height, 1, 0, 0, GL_TRUE, // Dimensions - GL_NONE, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glCopyTexSubImage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glCopyTexSubImage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glCopyTexSubImage3D.xhtml", Version.GLES32) -cmd void glCopyTexSubImage3D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height) { - CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) -} - -sub void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) { - TexImage(IsCopyTexImageCmd | HasSubModifier | Has3DModifier, target, - level, xoffset, yoffset, zoffset, // Offsets - 1, width, height, 1, 0, 0, GL_TRUE, // Dimensions - GL_NONE, GL_NONE, GL_NONE, 0, null) // Format&data - _ = x // TODO - _ = y // TODO -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteSamplers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteSamplers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteSamplers.xhtml", Version.GLES32) -cmd void glDeleteSamplers(GLsizei count, const SamplerId* samplers) { - CheckCountGE!GLsizei(count, 0) - s := samplers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := s[i] - if id != 0 { - delete(ctx.Objects.Samplers, id) - delete(ctx.Objects.GeneratedNames.Samplers, id) - } - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteTextures.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteTextures.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteTextures.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteTextures.xhtml", Version.GLES32) -cmd void glDeleteTextures(GLsizei count, const TextureId* textures) { - CheckCountGE!GLsizei(count, 0) - ids := textures[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := ids[i] - if id != 0 { - t := ctx.Objects.Textures[id] - if t != null { - for _, _, tu in ctx.Objects.TextureUnits { - bound := GetBoundTextureForUnit(tu, t.Kind) - if bound == t { - BindTextureForUnit(tu, t.Kind, 0) - } - } - } - // TODO: Unbind from bound framebuffer. - delete(ctx.Objects.Textures, id) - delete(ctx.Objects.GeneratedNames.Textures, id) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenSamplers.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenSamplers.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenSamplers.xhtml", Version.GLES32) -cmd void glGenSamplers(GLsizei count, SamplerId* samplers) { - CheckCountGE!GLsizei(count, 0) - s := samplers[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!SamplerId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Samplers[id] = true - s[i] = id - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenTextures.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenTextures.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenTextures.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenTextures.xhtml", Version.GLES32) -cmd void glGenTextures(GLsizei count, TextureId* textures) { - CheckCountGE!GLsizei(count, 0) - t := textures[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!TextureId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.Textures[id] = true - t[i] = id - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGenerateMipmap.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenerateMipmap.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenerateMipmap.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenerateMipmap.xhtml", Version.GLES32) -cmd void glGenerateMipmap(GLenum target) { - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP: { - // version 2.0 - } - @if(Version.GLES30) - case GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D: { - } - @if(Version.GLES32) - case GL_TEXTURE_CUBE_MAP_ARRAY: { - } - default: { - glErrorInvalidEnum(target) - } - } - - texture := GetBoundTextureOrErrorInvalidEnum(target) - // If we have mip-level 0, define all other mip-levels based on it - base := GetTextureImage(texture, 0, 0) - if base != null { - for levelIndex in as!GLint(1) .. as!GLint(31) { - width := base.Width >> as!u32(levelIndex) - height := base.Height >> as!u32(levelIndex) - // Depth decreases with each level for 3D textures, but not for 2D arrays. - is3D := (target == GL_TEXTURE_3D) - depth2D := as!GLint(len(texture.Levels[0].Layers)) - depth3D := depth2D >> as!u32(levelIndex) - depth := Select!GLint(is3D, depth3D, depth2D) - // If any dimension is >0, we need to keep adding levels (but clamp actual size to 1). - // Example 2D: (6,2,4) -> (3,1,4) -> (1,1,4) // depth is fixed to 4 - // Example 3D: (6,2,4) -> (3,1,2) -> (1,1,1) // width is camped to 1 - if ((width > 0) || (height > 0) || (is3D && (depth > 0))) { - for layerIndex in 0 .. max!GLint(1, depth) { - image := new!Image( - Width: max!GLsizei(1, width), - Height: max!GLsizei(1, height), - SizedFormat: base.SizedFormat, - InternalFormat: base.InternalFormat, - DataFormat: base.DataFormat, - DataType: base.DataType) - // Set state first so that the command below knowns image size. - SetTextureImage(texture, levelIndex, layerIndex, image) - newData := ReadGPUTextureData(texture, levelIndex, layerIndex) - if newData == null { - // ReadGPUTextureData is not implemented in gapii - just default initialize the content. - size := uncompressedImageSize(image.Width, image.Height, image.DataFormat, image.DataType) - image.Data = make!u8(size) - } else { - image.Data = newData - } - } - } - } - } -} - -sub void GetSamplerParameterv!T(SamplerId sampler, GLenum pname, T* params) { - s := GetOrCreateSampler(sampler) - switch (pname) { - case GL_TEXTURE_COMPARE_FUNC: params[0] = as!T(s.CompareFunc) - case GL_TEXTURE_COMPARE_MODE: params[0] = as!T(s.CompareMode) - case GL_TEXTURE_MIN_FILTER: params[0] = as!T(s.MinFilter) - case GL_TEXTURE_MAG_FILTER: params[0] = as!T(s.MagFilter) - case GL_TEXTURE_MIN_LOD: params[0] = as!T(s.MinLod) - case GL_TEXTURE_MAX_LOD: params[0] = as!T(s.MaxLod) - case GL_TEXTURE_WRAP_R: params[0] = as!T(s.WrapR) - case GL_TEXTURE_WRAP_S: params[0] = as!T(s.WrapS) - case GL_TEXTURE_WRAP_T: params[0] = as!T(s.WrapT) - @if(Version.GLES32) - case GL_TEXTURE_BORDER_COLOR: { - // TODO: Different behaviour based on the I suffix. - p := params[0:4] - p[0] = as!T(s.BorderColor[0]) - p[1] = as!T(s.BorderColor[1]) - p[2] = as!T(s.BorderColor[2]) - p[3] = as!T(s.BorderColor[3]) - } - @if(Extension.GL_EXT_texture_filter_anisotropic) - case GL_TEXTURE_MAX_ANISOTROPY_EXT: { - params[0] = as!T(s.MaxAnisotropy) - } - @if(Extension.GL_EXT_texture_sRGB_decode) - case GL_TEXTURE_SRGB_DECODE_EXT: { - params[0] = as!T(s.DecodeSRGB) - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetSamplerParameter.xhtml", Version.GLES32) -cmd void glGetSamplerParameterIiv(SamplerId sampler, GLenum pname, GLint* params) { - GetSamplerParameterIiv(sampler, pname, params) -} - -sub void GetSamplerParameterIiv(SamplerId sampler, GLenum pname, GLint* params) { - GetSamplerParameterv!GLint(sampler, pname, params) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetSamplerParameter.xhtml", Version.GLES32) -cmd void glGetSamplerParameterIuiv(SamplerId sampler, GLenum pname, GLuint* params) { - GetSamplerParameterIuiv(sampler, pname, params) -} - -sub void GetSamplerParameterIuiv(SamplerId sampler, GLenum pname, GLuint* params) { - GetSamplerParameterv!GLuint(sampler, pname, params) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetSamplerParameter.xhtml", Version.GLES32) -cmd void glGetSamplerParameterfv(SamplerId sampler, GLenum pname, GLfloat* params) { - GetSamplerParameterv!GLfloat(sampler, pname, params) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetSamplerParameter.xhtml", Version.GLES32) -cmd void glGetSamplerParameteriv(SamplerId sampler, GLenum pname, GLint* params) { - GetSamplerParameterv!GLint(sampler, pname, params) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetTexLevelParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexLevelParameter.xhtml", Version.GLES32) -cmd void glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat* params) { - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_3D, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z: { - // version 3.1 - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BUFFER, GL_TEXTURE_CUBE_MAP_ARRAY: { - } - default: { - glErrorInvalidEnum(target) - } - } - switch (pname) { - case GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_TYPE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_BLUE_TYPE, - GL_TEXTURE_COMPRESSED, GL_TEXTURE_DEPTH, GL_TEXTURE_DEPTH_SIZE, GL_TEXTURE_DEPTH_TYPE, - GL_TEXTURE_FIXED_SAMPLE_LOCATIONS, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_GREEN_TYPE, - GL_TEXTURE_HEIGHT, GL_TEXTURE_INTERNAL_FORMAT, GL_TEXTURE_RED_SIZE, GL_TEXTURE_RED_TYPE, - GL_TEXTURE_SAMPLES, GL_TEXTURE_SHARED_SIZE, GL_TEXTURE_STENCIL_SIZE, GL_TEXTURE_WIDTH: { - // version 3.1 - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER_DATA_STORE_BINDING, GL_TEXTURE_BUFFER_OFFSET, GL_TEXTURE_BUFFER_SIZE: { - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - params[0] = ? -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetTexLevelParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexLevelParameter.xhtml", Version.GLES32) -cmd void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params) { - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_2D_ARRAY, GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_3D, - GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_TEXTURE_CUBE_MAP_POSITIVE_X, - GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z: { - // version 3.1 - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_BUFFER, GL_TEXTURE_CUBE_MAP_ARRAY: { - } - default: { - glErrorInvalidEnum(target) - } - } - switch (pname) { - case GL_TEXTURE_ALPHA_SIZE, GL_TEXTURE_ALPHA_TYPE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_BLUE_TYPE, - GL_TEXTURE_COMPRESSED, GL_TEXTURE_DEPTH, GL_TEXTURE_DEPTH_SIZE, GL_TEXTURE_DEPTH_TYPE, - GL_TEXTURE_FIXED_SAMPLE_LOCATIONS, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_GREEN_TYPE, - GL_TEXTURE_HEIGHT, GL_TEXTURE_INTERNAL_FORMAT, GL_TEXTURE_RED_SIZE, GL_TEXTURE_RED_TYPE, - GL_TEXTURE_SAMPLES, GL_TEXTURE_SHARED_SIZE, GL_TEXTURE_STENCIL_SIZE, GL_TEXTURE_WIDTH: { - // version 3.1 - } - @if(Version.GLES32) - case GL_TEXTURE_BUFFER_DATA_STORE_BINDING, GL_TEXTURE_BUFFER_OFFSET, GL_TEXTURE_BUFFER_SIZE: { - } - default: { - glErrorInvalidEnum(pname) - } - } - // TODO - params[0] = ? -} - -sub void GetTexParameter!T(GLenum target, GLenum parameter, T* params) { - // TODO: Remove and rely on the switch in GetBoundTextureOrErrorInvalidEnum. - switch (target) { - case GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP: { - // version 2.0 - } - @if(Version.GLES30) - case GL_TEXTURE_2D_ARRAY, GL_TEXTURE_3D: { - } - @if(Version.GLES31) - case GL_TEXTURE_2D_MULTISAMPLE: { - } - @if(Version.GLES32) - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY, GL_TEXTURE_CUBE_MAP_ARRAY: { - } - default: { - glErrorInvalidEnum(target) - } - } - t := GetBoundTextureOrErrorInvalidEnum(target) - switch (parameter) { - @if(Version.GLES20) - case GL_TEXTURE_MAG_FILTER: { - params[0] = as!T(t.MagFilter) - } - @if(Version.GLES20) - case GL_TEXTURE_MIN_FILTER: { - params[0] = as!T(t.MinFilter) - } - @if(Version.GLES20) - case GL_TEXTURE_WRAP_S: { - params[0] = as!T(t.WrapS) - } - @if(Version.GLES20) - case GL_TEXTURE_WRAP_T: { - params[0] = as!T(t.WrapT) - } - @if(Version.GLES30) - case GL_TEXTURE_BASE_LEVEL: { - params[0] = as!T(t.BaseLevel) - } - @if(Version.GLES30 || Extension.GL_EXT_shadow_samplers) - case GL_TEXTURE_COMPARE_FUNC: { - params[0] = as!T(t.CompareFunc) - } - @if(Version.GLES30 || Extension.GL_EXT_shadow_samplers) - case GL_TEXTURE_COMPARE_MODE: { - params[0] = as!T(t.CompareMode) - } - @if(Version.GLES30 || Extension.GL_EXT_texture_storage) - case GL_TEXTURE_IMMUTABLE_FORMAT: { - params[0] = as!T(t.ImmutableFormat) - } - @if(Version.GLES30) - case GL_TEXTURE_MAX_LEVEL: { - params[0] = as!T(t.MaxLevel) - } - @if(Version.GLES30) - case GL_TEXTURE_MAX_LOD: { - params[0] = as!T(t.MaxLod) - } - @if(Version.GLES30) - case GL_TEXTURE_MIN_LOD: { - params[0] = as!T(t.MinLod) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_A: { - params[0] = as!T(t.SwizzleA) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_B: { - params[0] = as!T(t.SwizzleB) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_G: { - params[0] = as!T(t.SwizzleG) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_R: { - params[0] = as!T(t.SwizzleR) - } - @if(Version.GLES30) - case GL_TEXTURE_WRAP_R: { - params[0] = as!T(t.WrapR) - } - @if(Version.GLES31) - case GL_DEPTH_STENCIL_TEXTURE_MODE: { - params[0] = as!T(t.DepthStencilTextureMode) - } - @if(Version.GLES31) - case GL_IMAGE_FORMAT_COMPATIBILITY_TYPE: { - params[0] = ? // TODO - } - @if(Version.GLES31) - case GL_TEXTURE_IMMUTABLE_LEVELS: { - params[0] = as!T(t.ImmutableLevels) - } - @if(Version.GLES32) - case GL_TEXTURE_BORDER_COLOR: { - // TODO: Depends on the I suffix - p := params[0:4] - p[0] = as!T(t.BorderColor[0]) - p[1] = as!T(t.BorderColor[1]) - p[2] = as!T(t.BorderColor[2]) - p[3] = as!T(t.BorderColor[3]) - } - @if(Extension.GL_EXT_texture_filter_anisotropic) - case GL_TEXTURE_MAX_ANISOTROPY_EXT: { - params[0] = as!T(t.MaxAnisotropy) - } - @if(Extension.GL_EXT_texture_sRGB_decode) - case GL_TEXTURE_SRGB_DECODE_EXT: { - params[0] = as!T(t.DecodeSRGB) - } - default: { - glErrorInvalidEnum(parameter) - } - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexParameter.xhtml", Version.GLES32) -cmd void glGetTexParameterIiv(GLenum target, GLenum pname, GLint* params) { - GetTexParameterIiv(target, pname, params) -} - -sub void GetTexParameterIiv(GLenum target, GLenum pname, GLint* params) { - GetTexParameter!GLint(target, pname, params) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexParameter.xhtml", Version.GLES32) -cmd void glGetTexParameterIuiv(GLenum target, GLenum pname, GLuint* params) { - GetTexParameterIuiv(target, pname, params) -} - -sub void GetTexParameterIuiv(GLenum target, GLenum pname, GLuint* params) { - GetTexParameter!GLuint(target, pname, params) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexParameter.xhtml", Version.GLES32) -cmd void glGetTexParameterfv(GLenum target, GLenum parameter, GLfloat* values) { - GetTexParameter!GLfloat(target, parameter, values) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTexParameter.xhtml", Version.GLES32) -cmd void glGetTexParameteriv(GLenum target, GLenum parameter, GLint* values) { - GetTexParameter!GLint(target, parameter, values) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsSampler.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsSampler.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsSampler.xhtml", Version.GLES32) -cmd GLboolean glIsSampler(SamplerId sampler) { - - ctx := GetContext() - // This seems to be different to all other glIs* commands. - // Just have generated name seems sufficient to return true. - return toGLboolean(ctx.Objects.GeneratedNames.Samplers[sampler]) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glIsTexture.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsTexture.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsTexture.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsTexture.xhtml", Version.GLES32) -cmd GLboolean glIsTexture(TextureId texture) { - - ctx := GetContext() - return toGLboolean(texture in ctx.Objects.Textures) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glPixelStorei.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glPixelStorei.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPixelStorei.xhtml", Version.GLES32) -cmd void glPixelStorei(GLenum parameter, GLint value) { - CheckGE!GLint(value, 0) - ctx := GetContext() - switch (parameter) { - @if(Version.GLES20) - case GL_PACK_ALIGNMENT: { - if (value != 1) && (value != 2) && (value != 4) && (value != 8) { glErrorInvalidValue!GLint(value) } - ctx.Other.Pack.Alignment = value - } - @if(Version.GLES30) - case GL_PACK_IMAGE_HEIGHT: { - ctx.Other.Pack.ImageHeight = value - } - @if(Version.GLES30) - case GL_PACK_ROW_LENGTH: { - ctx.Other.Pack.RowLength = value - } - @if(Version.GLES30) - case GL_PACK_SKIP_IMAGES: { - ctx.Other.Pack.SkipImages = value - } - @if(Version.GLES30) - case GL_PACK_SKIP_PIXELS: { - ctx.Other.Pack.SkipPixels = value - } - @if(Version.GLES30) - case GL_PACK_SKIP_ROWS: { - ctx.Other.Pack.SkipRows = value - } - @if(Version.GLES20) - case GL_UNPACK_ALIGNMENT: { - if (value != 1) && (value != 2) && (value != 4) && (value != 8) { glErrorInvalidValue!GLint(value) } - ctx.Other.Unpack.Alignment = value - } - @if(Version.GLES30) - case GL_UNPACK_IMAGE_HEIGHT: { - ctx.Other.Unpack.ImageHeight = value - } - @if(Version.GLES30) - case GL_UNPACK_ROW_LENGTH: { - ctx.Other.Unpack.RowLength = value - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_IMAGES: { - ctx.Other.Unpack.SkipImages = value - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_PIXELS: { - ctx.Other.Unpack.SkipPixels = value - } - @if(Version.GLES30) - case GL_UNPACK_SKIP_ROWS: { - ctx.Other.Unpack.SkipRows = value - } - default: { - glErrorInvalidEnum(parameter) - } - } -} - -sub void SamplerParameterv!T(SamplerId sampler, GLenum pname, T params) { - s := GetOrCreateSampler(sampler) - switch (pname) { - case GL_TEXTURE_COMPARE_FUNC: s.CompareFunc = as!GLenum(params[0]) - case GL_TEXTURE_COMPARE_MODE: s.CompareMode = as!GLenum(params[0]) - case GL_TEXTURE_MIN_FILTER: s.MinFilter = as!GLenum(params[0]) - case GL_TEXTURE_MAG_FILTER: s.MagFilter = as!GLenum(params[0]) - case GL_TEXTURE_MIN_LOD: s.MinLod = as!GLfloat(params[0]) - case GL_TEXTURE_MAX_LOD: s.MaxLod = as!GLfloat(params[0]) - case GL_TEXTURE_WRAP_R: s.WrapR = as!GLenum(params[0]) - case GL_TEXTURE_WRAP_S: s.WrapS = as!GLenum(params[0]) - case GL_TEXTURE_WRAP_T: s.WrapT = as!GLenum(params[0]) - @if(Extension.GL_EXT_texture_filter_anisotropic) - case GL_TEXTURE_MAX_ANISOTROPY_EXT: { - // This use case is not explicitly mentioned in the extension (presumably - // because it is written for GLES2, but samplers were introduced in GLES3). - // However, it is used and supported in practice (which is reasonable). - s.MaxAnisotropy = as!GLfloat(params[0]) - } - @if(Extension.GL_EXT_texture_sRGB_decode) - case GL_TEXTURE_SRGB_DECODE_EXT: { - decode := as!GLenum(params[0]) - switch (decode) { - case GL_DECODE_EXT, GL_SKIP_DECODE_EXT: { /* fine */ } - default: { - glErrorInvalidEnum(decode) - } - } - s.DecodeSRGB = decode - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameterIiv(SamplerId sampler, GLenum pname, const GLint* param) { - SamplerParameterIiv(sampler, pname, param) -} - -sub void SamplerParameterIiv(SamplerId sampler, GLenum pname, const GLint* param) { - if(Version.GLES32 && pname == GL_TEXTURE_BORDER_COLOR) { - p := param[0:4] - s := GetOrCreateSampler(sampler) - s.BorderColor = Vec4f(0.0, 0.0, 0.0, 0.0) - s.BorderColorI = Vec4i(p[0], p[1], p[2], p[3]) - } else { - SamplerParameterv!(const GLint*)(sampler, pname, param) - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameterIuiv(SamplerId sampler, GLenum pname, const GLuint* param) { - SamplerParameterIuiv(sampler, pname, param) -} - -sub void SamplerParameterIuiv(SamplerId sampler, GLenum pname, const GLuint* param) { - if(Version.GLES32 && pname == GL_TEXTURE_BORDER_COLOR) { - p := (as!(const GLint*)(param))[0:4] - s := GetOrCreateSampler(sampler) - s.BorderColor = Vec4f(0.0, 0.0, 0.0, 0.0) - s.BorderColorI = Vec4i(p[0], p[1], p[2], p[3]) - } else { - SamplerParameterv!(const GLuint*)(sampler, pname, param) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameterf(SamplerId sampler, GLenum pname, GLfloat param) { - params := Vec1f(param) - SamplerParameterv!Vec1f(sampler, pname, params) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameterfv(SamplerId sampler, GLenum pname, const GLfloat* param) { - if(Version.GLES32 && pname == GL_TEXTURE_BORDER_COLOR) { - p := param[0:4] - s := GetOrCreateSampler(sampler) - s.BorderColor = Vec4f(p[0], p[1], p[2], p[3]) - s.BorderColorI = Vec4i(0, 0, 0, 0) - } else { - SamplerParameterv!(const GLfloat*)(sampler, pname, param) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameteri(SamplerId sampler, GLenum pname, GLint param) { - params := Vec1i(param) - SamplerParameterv!Vec1i(sampler, pname, params) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glSamplerParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glSamplerParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glSamplerParameter.xhtml", Version.GLES32) -cmd void glSamplerParameteriv(SamplerId sampler, GLenum pname, const GLint* param) { - if(Version.GLES32 && pname == GL_TEXTURE_BORDER_COLOR) { - p := param[0:4] - s := GetOrCreateSampler(sampler) - // TODO: Convert to float using the custom equation in spec. - s.BorderColor = Vec4f(0.0, 0.0, 0.0, 0.0) - s.BorderColorI = Vec4i(p[0], p[1], p[2], p[3]) - } else { - SamplerParameterv!(const GLint*)(sampler, pname, param) - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexBuffer.xhtml", Version.GLES32) -cmd void glTexBuffer(GLenum target, GLenum internalformat, BufferId buffer) { - TexBuffer(target, internalformat, buffer) -} - -sub void TexBuffer(GLenum target, GLenum internalformat, BufferId buffer) { - ctx := GetContext() - size := switch (buffer in ctx.Objects.Buffers) { - case true: ctx.Objects.Buffers[buffer].Size - case false: as!GLsizeiptr(0) - } - TexBufferRange(target, internalformat, buffer, 0, size) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexBufferRange.xhtml", Version.GLES32) -cmd void glTexBufferRange(GLenum target, - GLenum internalformat, - BufferId buffer, - GLintptr offset, - GLsizeiptr size) { - TexBufferRange(target, internalformat, buffer, offset, size) -} - -sub void TexBufferRange(GLenum target, GLenum internalformat, BufferId buffer, GLintptr offset, GLsizeiptr size) { - if (target != GL_TEXTURE_BUFFER) { glErrorInvalidEnum(target) } - t := GetBoundTextureOrErrorInvalidEnum(target) - switch (internalformat) { - case GL_R16, GL_R16F, GL_R16I, GL_R16UI, GL_R32F, GL_R32I, GL_R32UI, GL_R8, GL_R8I, GL_R8UI, - GL_RG16, GL_RG16F, GL_RG16I, GL_RG16UI, GL_RG32F, GL_RG32I, GL_RG32UI, GL_RG8, GL_RG8I, - GL_RG8UI, GL_RGB32F, GL_RGB32I, GL_RGB32UI, GL_RGBA16, GL_RGBA16F, GL_RGBA16I, GL_RGBA16UI, - GL_RGBA32F, GL_RGBA32I, GL_RGBA32UI, GL_RGBA8, GL_RGBA8I, GL_RGBA8UI: { - // version 3.2 - } - default: { - glErrorInvalidEnum(internalformat) - } - } - if buffer == 0 { - t.Buffer = TextureBufferBinding(InternalFormat: internalformat) - } else { - b := GetOrCreateBuffer(buffer) - CheckGE!GLintptr(offset, 0) - CheckLE!GLintptr(offset, as!GLintptr(b.Size)) - CheckSizeGE!GLsizeiptr(size, 1) - CheckLE!GLsizeiptr(size, b.Size - as!GLsizeiptr(offset)) - - t.Buffer = TextureBufferBinding( - Binding: b, - InternalFormat: internalformat, - Offset: offset, - Size: size, - ) - } -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexImage2D.xhtml", Version.GLES32) -cmd void glTexImage2D(GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - TexturePointer data) { - TexImage(IsTexImageCmd, target, - level, 0, 0, 0, // Offsets - 1, width, height, 1, border, 0, GL_TRUE, // Dimensions - as!GLenum(internalformat), format, type, 0, data) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexImage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexImage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexImage3D.xhtml", Version.GLES32) -cmd void glTexImage3D(GLenum target, - GLint level, - GLint internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLint border, - GLenum format, - GLenum type, - TexturePointer data) { - TexImage3D(target, level, internalformat, width, height, depth, border, format, type, data) -} - -sub void TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, TexturePointer data) { - TexImage(IsTexImageCmd | Has3DModifier, target, - level, 0, 0, 0, // Offsets - 1, width, height, depth, border, 0, GL_TRUE, // Dimensions - as!GLenum(internalformat), format, type, 0, data) // Format&data -} - -// Check that wrap is a valid value for GL_TEXTURE_WRAP_* otherwise -// abort with GL_INVALID_ENUM -sub GLenum checkWrapParam(GLenum wrap) { - switch wrap { - case GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_BORDER: { - } - default: { - glErrorInvalidEnum(wrap) - } - } - return wrap -} - -// Check that swizzle is a valid value for GL_TEXTURE_SWIZZLE_* otherwise -// abort with GL_INVALID_ENUM -sub GLenum checkSwizzleParam(GLenum swizzle) { - switch swizzle { - case GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_ZERO, GL_ONE: { /* fine */ } - default: { - glErrorInvalidEnum(swizzle) - } - } - return swizzle -} - -sub void TexParameterv!T(GLenum target, GLenum pname, T params) { - switch target { - case GL_TEXTURE_BUFFER, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: { - glErrorInvalidEnum(target) // Excluded. - } - default: { - } - } - - t := GetBoundTextureOrErrorInvalidEnum(target) - switch pname { - @if(Version.GLES20) - case GL_TEXTURE_MAG_FILTER: { - magFilter := as!GLenum(params[0]) - switch (magFilter) { - case GL_NEAREST, GL_LINEAR: { /* fine */ } - default: { - glErrorInvalidEnum(magFilter) - } - } - t.MagFilter = magFilter - } - @if(Version.GLES20) - case GL_TEXTURE_MIN_FILTER: { - minFilter := as!GLenum(params[0]) - switch (minFilter) { - case GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, - GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, - GL_LINEAR_MIPMAP_LINEAR: { /* fine */ } - default: { - glErrorInvalidEnum(minFilter) - } - } - t.MinFilter = minFilter - } - @if(Version.GLES20) - case GL_TEXTURE_WRAP_S: { - t.WrapS = checkWrapParam(as!GLenum(params[0])) - } - @if(Version.GLES20) - case GL_TEXTURE_WRAP_T: { - t.WrapT = checkWrapParam(as!GLenum(params[0])) - } - @if(Version.GLES30) - case GL_TEXTURE_BASE_LEVEL: { - baseLevel := as!GLint(params[0]) - CheckGE!GLint(baseLevel, 0) - t.BaseLevel = baseLevel - } - @if(Version.GLES30 || Extension.GL_EXT_shadow_samplers) - case GL_TEXTURE_COMPARE_FUNC: { - t.CompareFunc = as!GLenum(params[0]) - } - @if(Version.GLES30 || Extension.GL_EXT_shadow_samplers) - case GL_TEXTURE_COMPARE_MODE: { - t.CompareMode = as!GLenum(params[0]) - } - @if(Version.GLES30) - case GL_TEXTURE_MAX_LEVEL: { - maxLevel := as!GLint(params[0]) - CheckGE!GLint(maxLevel, 0) - t.MaxLevel = maxLevel - } - @if(Version.GLES30) - case GL_TEXTURE_MAX_LOD: { - t.MaxLod = as!GLfloat(params[0]) - } - @if(Version.GLES30) - case GL_TEXTURE_MIN_LOD: { - t.MinLod = as!GLfloat(params[0]) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_A: { - t.SwizzleA = checkSwizzleParam(as!GLenum(params[0])) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_B: { - t.SwizzleB = checkSwizzleParam(as!GLenum(params[0])) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_G: { - t.SwizzleG = checkSwizzleParam(as!GLenum(params[0])) - } - @if(Version.GLES30) - case GL_TEXTURE_SWIZZLE_R: { - t.SwizzleR = checkSwizzleParam(as!GLenum(params[0])) - } - @if(Version.GLES30) - case GL_TEXTURE_WRAP_R: { - t.WrapR = as!GLenum(params[0]) - } - @if(Version.GLES31) - case GL_DEPTH_STENCIL_TEXTURE_MODE: { - t.DepthStencilTextureMode = as!GLenum(params[0]) - } - @if(Version.GLES32) - case GL_TEXTURE_BORDER_COLOR: { - // TODO: Handle - has different behaviour based on the I suffix. - t.BorderColor[0] = as!GLfloat(params[0]) - t.BorderColor[1] = as!GLfloat(params[1]) - t.BorderColor[2] = as!GLfloat(params[2]) - t.BorderColor[3] = as!GLfloat(params[3]) - } - @if(Extension.GL_EXT_texture_filter_anisotropic) - case GL_TEXTURE_MAX_ANISOTROPY_EXT: { - t.MaxAnisotropy = as!GLfloat(params[0]) - } - @if(Extension.GL_EXT_texture_sRGB_decode) - case GL_TEXTURE_SRGB_DECODE_EXT: { - decode := as!GLenum(params[0]) - switch (decode) { - case GL_DECODE_EXT, GL_SKIP_DECODE_EXT: { /* fine */ } - default: { - glErrorInvalidEnum(decode) - } - } - t.DecodeSRGB = decode - } - default: { - glErrorInvalidEnum(pname) - } - } -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameterIiv(GLenum target, GLenum pname, const GLint* params) { - TexParameterIiv(target, pname, params) -} - -sub void TexParameterIiv(GLenum target, GLenum pname, const GLint* params) { - TexParameterv!(const GLint*)(target, pname, params) -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameterIuiv(GLenum target, GLenum pname, const GLuint* params) { - TexParameterIuiv(target, pname, params) -} - -sub void TexParameterIuiv(GLenum target, GLenum pname, const GLuint* params) { - TexParameterv!(const GLuint*)(target, pname, params) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameterf(GLenum target, GLenum parameter, GLfloat value) { - if parameter == GL_TEXTURE_BORDER_COLOR { glErrorInvalidEnum(parameter) } // not scalar - params := Vec4f(value, 0, 0, 0) - TexParameterv!Vec4f(target, parameter, params) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) { - TexParameterv!(const GLfloat*)(target, pname, params) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameteri(GLenum target, GLenum parameter, GLint value) { - if parameter == GL_TEXTURE_BORDER_COLOR { glErrorInvalidEnum(parameter) } // not scalar - params := Vec4i(value, 0, 0, 0) - TexParameterv!Vec4i(target, parameter, params) -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexParameter.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexParameter.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexParameter.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexParameter.xhtml", Version.GLES32) -cmd void glTexParameteriv(GLenum target, GLenum pname, const GLint* params) { - TexParameterv!(const GLint*)(target, pname, params) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexStorage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexStorage2D.xhtml", Version.GLES32) -cmd void glTexStorage2D(GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height) { - TexStorage2D(target, levels, internalformat, width, height) -} - -sub void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - depth := switch (target) { - case GL_TEXTURE_CUBE_MAP: as!GLsizei(6) - default: as!GLsizei(1) - } - TexImage(IsTexStorageCmd, target, - 0, 0, 0, 0, // Offsets - levels, width, height, depth, 0, 0, GL_TRUE, // Dimensions - internalformat, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexStorage2DMultisample.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexStorage2DMultisample.xhtml", Version.GLES32) -cmd void glTexStorage2DMultisample(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLboolean fixedsamplelocations) { - TexImage(IsTexStorageCmd | HasMultisampleModifier, target, - 0, 0, 0, 0, // Offsets - 1, width, height, 1, 0, samples, fixedsamplelocations, // Dimensions - internalformat, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexStorage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexStorage3D.xhtml", Version.GLES32) -cmd void glTexStorage3D(GLenum target, - GLsizei levels, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth) { - TexStorage3D(target, levels, internalformat, width, height, depth) -} - -sub void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { - TexImage(IsTexStorageCmd | Has3DModifier, target, - 0, 0, 0, 0, // Offsets - levels, width, height, depth, 0, 0, GL_TRUE, // Dimensions - internalformat, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES32) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexStorage3DMultisample.xhtml", Version.GLES32) -cmd void glTexStorage3DMultisample(GLenum target, - GLsizei samples, - GLenum internalformat, - GLsizei width, - GLsizei height, - GLsizei depth, - GLboolean fixedsamplelocations) { - TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations) -} - -sub void TexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { - TexImage(IsTexStorageCmd | Has3DModifier | HasMultisampleModifier, target, - 0, 0, 0, 0, // Offsets - 1, width, height, depth, 0, samples, fixedsamplelocations, // Dimensions - internalformat, GL_NONE, GL_NONE, 0, null) // Format&data -} - -@if(Version.GLES10) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexSubImage2D.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexSubImage2D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexSubImage2D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexSubImage2D.xhtml", Version.GLES32) -cmd void glTexSubImage2D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLsizei width, - GLsizei height, - GLenum format, - GLenum type, - TexturePointer data) { - TexImage(IsTexImageCmd | HasSubModifier, target, - level, xoffset, yoffset, 0, // Offsets - 1, width, height, 1, 0, 0, GL_TRUE, // Dimensions - GL_NONE, format, type, 0, data) // Format&data -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTexSubImage3D.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTexSubImage3D.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTexSubImage3D.xhtml", Version.GLES32) -cmd void glTexSubImage3D(GLenum target, - GLint level, - GLint xoffset, - GLint yoffset, - GLint zoffset, - GLsizei width, - GLsizei height, - GLsizei depth, - GLenum format, - GLenum type, - TexturePointer data) { - TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data) -} - -sub void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, TexturePointer data) { - TexImage(IsTexImageCmd | HasSubModifier | Has3DModifier, target, - level, xoffset, yoffset, zoffset, // Offsets - 1, width, height, depth, 0, 0, GL_TRUE, // Dimensions - GL_NONE, format, type, 0, data) // Format&data -} diff --git a/gapis/api/gles/api/transform_feedback.api b/gapis/api/gles/api/transform_feedback.api deleted file mode 100644 index 06f2bcc9de..0000000000 --- a/gapis/api/gles/api/transform_feedback.api +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -@internal -class TransformFeedback { - TransformFeedbackId ID - - // Table 21.35: Transform Feedback State - ref!Buffer Buffer - map!(GLuint, BufferBinding) Buffers - GLboolean Paused = GL_FALSE - GLboolean Active = GL_FALSE - GLenum PrimitiveMode = GL_NONE - @unused string Label -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBeginTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBeginTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBeginTransformFeedback.xhtml", Version.GLES32) -cmd void glBeginTransformFeedback(GLenum primitiveMode) { - switch (primitiveMode) { - case GL_LINES, GL_POINTS, GL_TRIANGLES: { - // version 3.0 - } - default: { - glErrorInvalidEnum(primitiveMode) - } - } - ctx := GetContext() - ctx.Bound.TransformFeedback.Paused = GL_FALSE - ctx.Bound.TransformFeedback.Active = GL_TRUE - ctx.Bound.TransformFeedback.PrimitiveMode = primitiveMode -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindTransformFeedback.xhtml", Version.GLES32) -cmd void glBindTransformFeedback(GLenum target, TransformFeedbackId id) { - ctx := GetContext() - switch (target) { - case GL_TRANSFORM_FEEDBACK: { - // version 3.0 - ctx.Bound.TransformFeedback = GetOrCreateTransformFeedback(id) - } - default: { - glErrorInvalidEnum(target) - } - } -} - -sub ref!TransformFeedback GetOrCreateTransformFeedback(TransformFeedbackId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.TransformFeedbacks[id] == null) { - tf := new!TransformFeedback(ID: id) - for i in as!GLuint(0) .. as!GLuint(ctx.Constants.MaxTransformFeedbackSeparateAttribs) { - tf.Buffers[i] = BufferBinding() - } - ctx.Objects.TransformFeedbacks[id] = tf - ctx.Objects.GeneratedNames.TransformFeedbacks[id] = true - } - return ctx.Objects.TransformFeedbacks[id] -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteTransformFeedbacks.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteTransformFeedbacks.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteTransformFeedbacks.xhtml", Version.GLES32) -cmd void glDeleteTransformFeedbacks(GLsizei count, const TransformFeedbackId* ids) { - CheckCountGE!GLsizei(count, 0) - tfs := ids[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := tfs[i] - if id != 0 { - delete(ctx.Objects.TransformFeedbacks, id) - delete(ctx.Objects.GeneratedNames.TransformFeedbacks, id) - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBeginTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBeginTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBeginTransformFeedback.xhtml", Version.GLES32) -cmd void glEndTransformFeedback() { - ctx := GetContext() - ctx.Bound.TransformFeedback.Paused = GL_FALSE - ctx.Bound.TransformFeedback.Active = GL_FALSE - ctx.Bound.TransformFeedback.PrimitiveMode = GL_NONE -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenTransformFeedbacks.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenTransformFeedbacks.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenTransformFeedbacks.xhtml", Version.GLES32) -cmd void glGenTransformFeedbacks(GLsizei count, TransformFeedbackId* ids) { - CheckCountGE!GLsizei(count, 0) - tfs := ids[0:count] - ctx := GetContext() - for i in (0 .. count) { - id := as!TransformFeedbackId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.TransformFeedbacks[id] = true - tfs[i] = id - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetTransformFeedbackVarying.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetTransformFeedbackVarying.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetTransformFeedbackVarying.xhtml", Version.GLES32) -cmd void glGetTransformFeedbackVarying(ProgramId program, - GLuint index, - GLsizei bufSize, - GLsizei* length, - GLsizei* size, - GLenum* type, - GLchar* name) { - // TODO - writeString(bufSize, length, name) - size[0] = ? - type[0] = ? -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsTransformFeedback.xhtml", Version.GLES32) -cmd GLboolean glIsTransformFeedback(TransformFeedbackId id) { - ctx := GetContext() - return toGLboolean(id in ctx.Objects.TransformFeedbacks) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glPauseTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glPauseTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glPauseTransformFeedback.xhtml", Version.GLES32) -cmd void glPauseTransformFeedback() { - ctx := GetContext() - ctx.Bound.TransformFeedback.Paused = GL_TRUE -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glResumeTransformFeedback.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glResumeTransformFeedback.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glResumeTransformFeedback.xhtml", Version.GLES32) -cmd void glResumeTransformFeedback() { - ctx := GetContext() - ctx.Bound.TransformFeedback.Paused = GL_FALSE -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glTransformFeedbackVaryings.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glTransformFeedbackVaryings.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glTransformFeedbackVaryings.xhtml", Version.GLES32) -cmd void glTransformFeedbackVaryings(ProgramId program, - GLsizei count, - const GLchar* const* varyings, - GLenum bufferMode) { - p := GetProgramOrError(program) - switch (bufferMode) { - case GL_INTERLEAVED_ATTRIBS, GL_SEPARATE_ATTRIBS: { - p.TransformFeedbackBufferMode = bufferMode - } - default: { - glErrorInvalidEnum(bufferMode) - } - } - names := varyings[0:count] - // TODO: Better syntax for clearing map. - p.TransformFeedbackVaryings = Program().TransformFeedbackVaryings - for i in (0 .. count) { - name := as!string(as!char*(names[i])) // Read null-terminated string. TODO: Better syntax. - p.TransformFeedbackVaryings[as!u32(i)] = name - } -} diff --git a/gapis/api/gles/api/util.api b/gapis/api/gles/api/util.api deleted file mode 100644 index 3abe63dd65..0000000000 --- a/gapis/api/gles/api/util.api +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -sub T Select!T(bool cond, T trueValue, T falseValue) { - return switch cond { - case true: trueValue - case false: falseValue - } -} - -sub T SelectNonZero!T(T a, T b) { - return switch a != 0 { - case true: a - case false: b - } -} - -sub T Align!T(T value, T alignment) { - a := SelectNonZero!T(alignment, 1) - return ((value + a - 1) / a) * a -} - -sub T min!T(T a, T b) { - return switch (a < b) { - case true: a - case false: b - } -} - -sub T max!T(T a, T b) { - return switch a > b { - case true: a - case false: b - } -} - -// A dummy class used to force the templates to generate types used by -// hand-written code. -class ForceGenerate { - u32* dummy -} \ No newline at end of file diff --git a/gapis/api/gles/api/vertex_arrays.api b/gapis/api/gles/api/vertex_arrays.api deleted file mode 100644 index 1002757fcf..0000000000 --- a/gapis/api/gles/api/vertex_arrays.api +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -type GLuint VertexBufferBindingIndex - -// Vertex Array Object (VAO) -@internal -class VertexArray { - VertexArrayId ID - - map!(VertexBufferBindingIndex, ref!VertexBufferBinding) VertexBufferBindings - map!(AttributeLocation, ref!VertexAttributeArray) VertexAttributeArrays - - // Table 21.3: Vertex Array Object State - ref!Buffer ElementArrayBuffer - @unused string Label -} - -@internal -class VertexAttributeArray { - // Table 21.3: Vertex Array Object State - GLboolean Enabled = GL_FALSE - GLint Size = 4 // Number of components. 1, 2, 3 or 4. - GLsizei Stride = 0 // Obsolete/incorrect. See VertexBufferBinding stride instead. - GLenum Type = GL_FLOAT // Type of each component. - GLboolean Normalized = GL_FALSE - GLboolean Integer = GL_FALSE // Do not convert to float - the shader uses integer type. - VertexPointer Pointer // Client's data if BoundVertexArray == 0 && Buffer == 0 - ref!VertexBufferBinding Binding - GLuint RelativeOffset = 0 -} - -@internal -class VertexBufferBinding { - VertexBufferBindingIndex Id - - // Table 21.3: Vertex Array Object State - ref!Buffer Buffer - GLintptr Offset = 0 - GLsizei Stride = 16 - GLuint Divisor = 0 // Non-zero values enable instancing. -} - -@internal -class VertexAttributeValue { - GLenum Type - // Table 21.30: Vertex Shader State (not part of program objects) - @unused u8[] Value // Used if VertexAttributeArray is disabled. -} - -sub void CheckAttributeLocation(AttributeLocation location) { - ctx := GetContext() - CheckLocationLT!AttributeLocation(location, as!AttributeLocation(ctx.Constants.MaxVertexAttribs)) -} - -sub void CheckNonDefaultVertexArrayBound() { - ctx := GetContext() - if ctx.Bound.VertexArray.ID == 0 { - glErrorInvalidOperationMsg(new!ERR_INVALID_OPERATION_DEFAULT_VERTEX_ARRAY_BOUND()) - } -} - -sub bool IsDefaultVertexArrayBound() { - ctx := GetContext() - return ctx.Bound.VertexArray.ID == 0 -} - -sub ref!VertexArray GetOrCreateVertexArray(VertexArrayId id) { - ctx := GetContext() - if (id != 0) && (ctx.Objects.VertexArrays[id] == null) { - ctx.Objects.VertexArrays[id] = NewVertexArray(id) - // Dependency to glGenVertexArrays: mark name as new only if need be - if !ctx.Objects.GeneratedNames.VertexArrays[id] { - ctx.Objects.GeneratedNames.VertexArrays[id] = true - } - } - return ctx.Objects.VertexArrays[id] -} - -sub ref!VertexArray NewVertexArray(VertexArrayId id) { - ctx := GetContext() - array := new!VertexArray(ID: id) - if VersionGreaterOrEqual(ctx, 3, 1) { - for i in 0 .. as!VertexBufferBindingIndex(ctx.Constants.MaxVertexAttribBindings) { - array.VertexBufferBindings[i] = new!VertexBufferBinding(Id: i) - } - } else { - for i in 0 .. as!VertexBufferBindingIndex(ctx.Constants.MaxVertexAttribs) { - array.VertexBufferBindings[i] = new!VertexBufferBinding(Id: i) - } - } - for i in (0 .. as!AttributeLocation(ctx.Constants.MaxVertexAttribs)) { - binding := array.VertexBufferBindings[as!VertexBufferBindingIndex(i)] - array.VertexAttributeArrays[i] = new!VertexAttributeArray(Binding: binding) - } - return array -} - -// Logic shared by glGetVertexAttrib* commands. -sub u64 GetVertexAttrib(ref!Context ctx, AttributeLocation index, GLenum pname) { - vao := ctx.Bound.VertexArray - array := vao.VertexAttributeArrays[index] - // TODO: Inline this in the switch once subroutines are allowed in switch. - bindingBuffer := GetID!(u64,Buffer)(array.Binding.Buffer) - return switch (pname) { - case GL_VERTEX_ATTRIB_ARRAY_ENABLED: { as!u64(array.Enabled) } - case GL_VERTEX_ATTRIB_ARRAY_SIZE: { as!u64(array.Size) } - case GL_VERTEX_ATTRIB_ARRAY_TYPE: { as!u64(array.Type) } - case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: { as!u64(array.Normalized) } - case GL_VERTEX_ATTRIB_ARRAY_STRIDE: { as!u64(array.Stride) } - case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: { bindingBuffer } - @if(Version.GLES30) - case GL_VERTEX_ATTRIB_ARRAY_DIVISOR: { as!u64(array.Binding.Divisor) } - @if(Version.GLES30) - case GL_VERTEX_ATTRIB_ARRAY_INTEGER: { as!u64(array.Integer) } - @if(Version.GLES31) - case GL_VERTEX_ATTRIB_BINDING: { as!u64(array.Binding.Id) } - @if(Version.GLES31) - case GL_VERTEX_ATTRIB_RELATIVE_OFFSET: { // SPEC: missing in html - as!u64(array.RelativeOffset) - } - default: { - // glErrorInvalidEnum(pname) - 0 - } - } -} - -sub GLint VertexAttribTypeSize(GLenum type) { - return switch (type) { - case GL_BYTE, GL_UNSIGNED_BYTE: 1 - case GL_SHORT, GL_UNSIGNED_SHORT, GL_HALF_FLOAT, GL_HALF_FLOAT_OES: 2 - case GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_FIXED: 4 - case GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV: 4 - } -} - -sub void ReadVertexArrays(ref!Context ctx, u32 first_index, u32 index_count, u32 instance_count) { - if (index_count > 0) && (instance_count > 0) { - // Only the default vertex array can contain client data pointer. - if IsDefaultVertexArrayBound() { - vao := ctx.Objects.VertexArrays[0] - for i in (0 .. as!AttributeLocation(ctx.Constants.MaxVertexAttribs)) { - arr := vao.VertexAttributeArrays[i] - if arr.Enabled == GL_TRUE { - binding := arr.Binding - if (binding.Buffer == null) && (arr.Pointer != null) { - stride := binding.Stride - size := VertexAttribTypeSize(arr.Type) * arr.Size - divisor := as!u32(binding.Divisor) - if divisor == 0 { - for v in (first_index .. (first_index + index_count)) { - offset := as!GLint(stride) * as!GLint(v) - read(arr.Pointer[offset:offset + size]) - } - } else { - last_instance := instance_count - 1 - last_index := last_instance / divisor - // First index is not added to instanced arrays. - for v in (0 .. (last_index + 1)) { - offset := as!GLint(stride) * as!GLint(v) - read(arr.Pointer[offset:offset + size]) - } - } - } - } - } - } - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glBindVertexArray.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindVertexArray.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindVertexArray.xhtml", Version.GLES32) -cmd void glBindVertexArray(VertexArrayId array) { - BindVertexArray(array) -} - -sub void BindVertexArray(VertexArrayId array) { - ctx := GetContext() - ctx.Bound.VertexArray = GetOrCreateVertexArray(array) -} - -sub void BindVertexBuffer(ref!Context ctx, VertexBufferBindingIndex binding_index, BufferId buffer, GLintptr offset, GLsizei stride) { - CheckGE!GLintptr(offset, 0) - CheckGE!GLsizei(stride, 0) - if VersionGreaterOrEqual(ctx, 3, 1) { - CheckLT!VertexBufferBindingIndex(binding_index, as!VertexBufferBindingIndex(ctx.Constants.MaxVertexAttribBindings)) - CheckLT!GLsizei(stride, as!GLsizei(ctx.Constants.MaxVertexAttribStride)) - } - b := GetOrCreateBuffer(buffer) - vao := ctx.Bound.VertexArray - binding := vao.VertexBufferBindings[binding_index] - binding.Buffer = b - binding.Offset = offset - binding.Stride = stride -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glBindVertexBuffer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glBindVertexBuffer.xhtml", Version.GLES32) -cmd void glBindVertexBuffer(VertexBufferBindingIndex binding_index, BufferId buffer, GLintptr offset, GLsizei stride) { - ctx := GetContext() - CheckNonDefaultVertexArrayBound() - BindVertexBuffer(ctx, binding_index, buffer, offset, stride) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glDeleteVertexArrays.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glDeleteVertexArrays.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glDeleteVertexArrays.xhtml", Version.GLES32) -cmd void glDeleteVertexArrays(GLsizei count, const VertexArrayId* arrays) { - DeleteVertexArrays(count, arrays) -} - -sub void DeleteVertexArrays(GLsizei count, const VertexArrayId* arrays) { - CheckCountGE!GLsizei(count, 0) - ctx := GetContext() - a := arrays[0:count] - for i in (0 .. count) { - id := a[i] - // Silently ignore invalid ids - if id != 0 { - if id in ctx.Objects.VertexArrays { - delete(ctx.Objects.VertexArrays, id) - delete(ctx.Objects.GeneratedNames.VertexArrays, id) - if ctx.Bound.VertexArray.ID == id { - ctx.Bound.VertexArray = ctx.Objects.Default.VertexArray - } - } - } - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glEnableVertexAttribArray.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glEnableVertexAttribArray.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glEnableVertexAttribArray.xhtml", Version.GLES32) -cmd void glDisableVertexAttribArray(AttributeLocation location) { - ctx := GetContext() - CheckAttributeLocation(location) - vao := ctx.Bound.VertexArray - vao.VertexAttributeArrays[location].Enabled = GL_FALSE -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glEnableVertexAttribArray.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glEnableVertexAttribArray.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glEnableVertexAttribArray.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glEnableVertexAttribArray.xhtml", Version.GLES32) -cmd void glEnableVertexAttribArray(AttributeLocation location) { - ctx := GetContext() - CheckAttributeLocation(location) - vao := ctx.Bound.VertexArray - vao.VertexAttributeArrays[location].Enabled = GL_TRUE -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGenVertexArrays.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGenVertexArrays.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGenVertexArrays.xhtml", Version.GLES32) -cmd void glGenVertexArrays(GLsizei count, VertexArrayId* arrays) { - GenVertexArrays(count, arrays) -} - -sub void GenVertexArrays(GLsizei count, VertexArrayId* arrays) { - CheckCountGE!GLsizei(count, 0) - ctx := GetContext() - a := arrays[0:count] - for i in (0 .. count) { - id := as!VertexArrayId(?) - assert(id != 0) - ctx.Objects.GeneratedNames.VertexArrays[id] = true - a[i] = id - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetVertexAttrib.xhtml", Version.GLES32) -cmd void glGetVertexAttribIiv(AttributeLocation index, GLenum pname, GLint* params) { - ctx := GetContext() - CheckAttributeLocation(index) - if pname == GL_CURRENT_VERTEX_ATTRIB { - // attr := ctx.Vertex.Attributes[index] - // TODO: params[0:4] = as!GLint[](attr.Value)[0:4] - write(params[0:4]) - } else { - params[0] = as!GLint(GetVertexAttrib(ctx, index, pname)) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetVertexAttrib.xhtml", Version.GLES32) -cmd void glGetVertexAttribIuiv(AttributeLocation index, GLenum pname, GLuint* params) { - ctx := GetContext() - CheckAttributeLocation(index) - if pname == GL_CURRENT_VERTEX_ATTRIB { - // attr := ctx.Vertex.Attributes[index] - // TODO: params[0:4] = as!GLuint[](attr.Value)[0:4] - write(params[0:4]) - } else { - params[0] = as!GLuint(GetVertexAttrib(ctx, index, pname)) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetVertexAttribPointerv.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttribPointerv.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetVertexAttribPointerv.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetVertexAttribPointerv.xhtml", Version.GLES32) -cmd void glGetVertexAttribPointerv(AttributeLocation index, GLenum pname, void** pointer) { - ctx := GetContext() - CheckAttributeLocation(index) - if pname != GL_VERTEX_ATTRIB_ARRAY_POINTER { glErrorInvalidEnum(pname) } - vao := ctx.Bound.VertexArray - pointer[0] = as!void*(vao.VertexAttributeArrays[index].Pointer) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetVertexAttrib.xhtml", Version.GLES32) -cmd void glGetVertexAttribfv(AttributeLocation index, GLenum pname, GLfloat* params) { - ctx := GetContext() - CheckAttributeLocation(index) - if pname == GL_CURRENT_VERTEX_ATTRIB { - // TODO: params[0:4] = as!GLfloat[](attr.Value)[0:4] - // attr := ctx.Vertex.Attributes[index] - write(params[0:4]) - } else { - params[0] = as!GLfloat(GetVertexAttrib(ctx, index, pname)) - } -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glGetVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glGetVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glGetVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glGetVertexAttrib.xhtml", Version.GLES32) -cmd void glGetVertexAttribiv(AttributeLocation index, GLenum pname, GLint* params) { - ctx := GetContext() - CheckAttributeLocation(index) - if pname == GL_CURRENT_VERTEX_ATTRIB { - // TODO: params[0:4] = as!GLint[](attr.Value)[0:4] - // attr := ctx.Vertex.Attributes[index] - write(params[0:4]) - } else { - params[0] = as!GLint(GetVertexAttrib(ctx, index, pname)) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glIsVertexArray.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glIsVertexArray.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glIsVertexArray.xhtml", Version.GLES32) -cmd GLboolean glIsVertexArray(VertexArrayId array) { - return IsVertexArray(array) -} - -sub GLboolean IsVertexArray(VertexArrayId array) { - ctx := GetContext() - return toGLboolean((array != 0) && (array in ctx.Objects.VertexArrays)) -} - -sub void VertexAttrib!T(AttributeLocation location, GLenum ty, T value) { - ctx := GetContext() - CheckAttributeLocation(location) - vals := make!T(1) - vals[0] = value - ctx.Vertex.Attributes[location] = VertexAttributeValue(Type: ty, Value: as!u8[](vals)) -} - -sub void VertexAttribF(AttributeLocation location, Vec4f value) { - VertexAttrib!Vec4f(location, GL_FLOAT_VEC4, value) -} - -sub void VertexAttribI(AttributeLocation location, Vec4i value) { - VertexAttrib!Vec4i(location, GL_INT_VEC4, value) -} - -sub void VertexAttribU(AttributeLocation location, Vec4u value) { - VertexAttrib!Vec4u(location, GL_UNSIGNED_INT_VEC4, value) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib1f(AttributeLocation location, GLfloat value0) { - VertexAttribF(location, Vec4f(value0, 0.0, 0.0, 1.0)) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib1fv(AttributeLocation location, const GLfloat* value) { - v := value[0:1] - vec := Vec4f(v[0], 0.0, 0.0, 1.0) - VertexAttribF(location, vec) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib2f(AttributeLocation location, GLfloat value0, GLfloat value1) { - VertexAttribF(location, Vec4f(value0, value1, 0.0, 1.0)) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib2fv(AttributeLocation location, const GLfloat* value) { - v := value[0:2] - vec := Vec4f(v[0], v[1], 0.0, 1.0) - VertexAttribF(location, vec) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib3f(AttributeLocation location, - GLfloat value0, - GLfloat value1, - GLfloat value2) { - VertexAttribF(location, Vec4f(value0, value1, value2, 1.0)) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib3fv(AttributeLocation location, const GLfloat* value) { - v := value[0:3] - vec := Vec4f(v[0], v[1], v[2], 1.0) - VertexAttribF(location, vec) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib4f(AttributeLocation location, - GLfloat value0, - GLfloat value1, - GLfloat value2, - GLfloat value3) { - VertexAttribF(location, Vec4f(value0, value1, value2, value3)) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttrib4fv(AttributeLocation location, const GLfloat* value) { - v := value[0:4] - vec := Vec4f(v[0], v[1], v[2], v[3]) - VertexAttribF(location, vec) -} - -sub void VertexAttribBinding(ref!Context ctx, AttributeLocation index, VertexBufferBindingIndex binding_index) { - if VersionGreaterOrEqual(ctx, 3, 1) { - CheckAttributeLocation(index) - CheckLT!VertexBufferBindingIndex(binding_index, as!VertexBufferBindingIndex(ctx.Constants.MaxVertexAttribBindings)) - } - // NB: Some callers may use the default VertexArray and some may not. - // Therefore the caller should do the check if it is needed. - vao := ctx.Bound.VertexArray - vao.VertexAttributeArrays[index].Binding = vao.VertexBufferBindings[binding_index] -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribBinding.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribBinding.xhtml", Version.GLES32) -cmd void glVertexAttribBinding(AttributeLocation index, VertexBufferBindingIndex binding_index) { - ctx := GetContext() - CheckNonDefaultVertexArrayBound() - VertexAttribBinding(ctx, index, binding_index) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttribDivisor.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribDivisor.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribDivisor.xhtml", Version.GLES32) -cmd void glVertexAttribDivisor(AttributeLocation index, GLuint divisor) { - VertexAttribDivisor(index, divisor) -} - -sub void VertexAttribDivisor(AttributeLocation index, GLuint divisor) { - ctx := GetContext() - binding_index := as!VertexBufferBindingIndex(index) - VertexAttribBinding(ctx, index, binding_index) - vao := ctx.Bound.VertexArray - vao.VertexBufferBindings[binding_index].Divisor = divisor -} - -sub void VertexAttribFormat(ref!Context ctx, - AttributeLocation index, - GLint size, - GLenum type, - GLboolean normalized, - GLuint relativeOffset, - bool integer) { - CheckAttributeLocation(index) - if !((1 <= size) && (size <= 4)) { glErrorInvalidValue!GLint(size) } - if (integer) { - switch (type) { - @if(Version.GLES30) - case GL_BYTE, GL_INT, GL_SHORT, GL_UNSIGNED_BYTE, GL_UNSIGNED_INT, GL_UNSIGNED_SHORT: { - } - default: { - glErrorInvalidEnum(type) - } - } - } else { - switch (type) { - @if(Version.GLES20) - case GL_BYTE, GL_FIXED, GL_FLOAT, GL_SHORT, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT: { - } - @if(Extension.GL_OES_vertex_half_float) - case GL_HALF_FLOAT_OES: { - } - @if(Version.GLES30) - case GL_HALF_FLOAT, GL_INT, GL_UNSIGNED_INT: { - } - @if(Version.GLES30) - case GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV: { - if size != 4 { glErrorInvalidOperation() } - } - default: { - glErrorInvalidEnum(type) - } - } - } - // NB: Some callers may use the default VertexArray and some may not. - // Therefore the caller should do the check if it is needed. - if VersionGreaterOrEqual(ctx, 3, 1) { - CheckLE!GLuint(relativeOffset, as!GLuint(ctx.Constants.MaxVertexAttribRelativeOffset)) - } - vao := ctx.Bound.VertexArray - format := vao.VertexAttributeArrays[index] - format.Size = size - format.Type = type - if (!integer) { - format.Normalized = normalized - } - format.RelativeOffset = relativeOffset - format.Integer = toGLboolean(integer) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribFormat.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribFormat.xhtml", Version.GLES32) -cmd void glVertexAttribFormat(AttributeLocation index, - GLint size, - GLenum type, - GLboolean normalized, - GLuint relativeoffset) { - ctx := GetContext() - CheckNonDefaultVertexArrayBound() - VertexAttribFormat(ctx, index, size, type, normalized, relativeoffset, false) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttribI4i(AttributeLocation index, GLint x, GLint y, GLint z, GLint w) { - VertexAttribI(index, Vec4i(x, y, z, w)) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttribI4iv(AttributeLocation index, const GLint* values) { - v := values[0:4] - vec := Vec4i(v[0], v[1], v[2], v[3]) - VertexAttribI(index, vec) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttribI4ui(AttributeLocation index, GLuint x, GLuint y, GLuint z, GLuint w) { - VertexAttribU(index, Vec4u(x, y, z, w)) -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttrib.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttrib.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttrib.xhtml", Version.GLES32) -cmd void glVertexAttribI4uiv(AttributeLocation index, const GLuint* values) { - v := values[0:4] - vec := Vec4u(v[0], v[1], v[2], v[3]) - VertexAttribU(index, vec) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribFormat.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribFormat.xhtml", Version.GLES32) -cmd void glVertexAttribIFormat(AttributeLocation index, GLint size, GLenum type, GLuint relativeoffset) { - ctx := GetContext() - CheckNonDefaultVertexArrayBound() - VertexAttribFormat(ctx, index, size, type, GL_FALSE, relativeoffset, true) -} - -sub void VertexAttribPointer(ref!Context ctx, - AttributeLocation index, - GLint size, - GLenum type, - GLboolean normalized, - GLsizei stride, - VertexPointer pointer, - bool integer) { - boundArrayBuffer := ctx.Bound.ArrayBuffer - // Do not allow use of client's memory for non-default vertex array. - if (!IsDefaultVertexArrayBound()) && (boundArrayBuffer == null) && (pointer != null) { glErrorInvalidOperation() } - VertexAttribFormat(ctx, index, size, type, normalized, 0, integer) - binding_index := as!VertexBufferBindingIndex(index) - VertexAttribBinding(ctx, index, binding_index) - vertexTypeSize := VertexAttribTypeSize(type) - effectiveStride := switch (stride != 0) { - case true: stride - case false: as!GLsizei(vertexTypeSize * size) - } - vao := ctx.Bound.VertexArray - vao.VertexAttributeArrays[index].Stride = stride - vao.VertexAttributeArrays[index].Pointer = pointer - if IsDefaultVertexArrayBound() && (boundArrayBuffer == null) { - // Use client's memory as data buffer - this is the only way to set it. - BindVertexBuffer(ctx, binding_index, 0, 0, effectiveStride) - } else { - // This call does not allow use of client's memory due to check at the top of function, - // although it is possible to clear the buffer later while keeping pointer set. - // I wonder how drivers handle it. We just ignore non-default vertex arrays. - offset := as!GLintptr(as!u64(pointer)) - boundArrayBufferId := GetID!(BufferId,Buffer)(boundArrayBuffer) - BindVertexBuffer(ctx, binding_index, boundArrayBufferId, offset, effectiveStride) - } -} - -@if(Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttribPointer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribPointer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribPointer.xhtml", Version.GLES32) -cmd void glVertexAttribIPointer(AttributeLocation location, - GLint size, - GLenum type, - GLsizei stride, - VertexPointer data) { - ctx := GetContext() - VertexAttribPointer(ctx, location, size, type, GL_FALSE, stride, data, true) -} - -@if(Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttribPointer.xml", Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/docs/man3/html/glVertexAttribPointer.xhtml", Version.GLES30) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexAttribPointer.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexAttribPointer.xhtml", Version.GLES32) -cmd void glVertexAttribPointer(AttributeLocation location, - GLint size, - GLenum type, - GLboolean normalized, - GLsizei stride, - VertexPointer data) { - ctx := GetContext() - VertexAttribPointer(ctx, location, size, type, normalized, stride, data, false) -} - -@if(Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man31/html/glVertexBindingDivisor.xhtml", Version.GLES31) -@doc("https://www.khronos.org/opengles/sdk/docs/man32/html/glVertexBindingDivisor.xhtml", Version.GLES32) -cmd void glVertexBindingDivisor(VertexBufferBindingIndex binding_index, GLuint divisor) { - ctx := GetContext() - CheckLT!VertexBufferBindingIndex(binding_index, as!VertexBufferBindingIndex(ctx.Constants.MaxVertexAttribBindings)) - CheckNonDefaultVertexArrayBound() - vao := ctx.Bound.VertexArray - vao.VertexBufferBindings[binding_index].Divisor = divisor -} diff --git a/gapis/api/gles/compat.go b/gapis/api/gles/compat.go deleted file mode 100644 index e5f33ab369..0000000000 --- a/gapis/api/gles/compat.go +++ /dev/null @@ -1,1374 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "reflect" - "strings" - - "github.com/google/gapid/core/app/analytics" - "github.com/google/gapid/core/data/dictionary" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/math/u32" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/shadertools" -) - -type support int - -const ( - unsupported support = iota - supported - required -) - -var ( - // We don't include tests directly in the gles package as it adds - // significantly to the test build time. - VisibleForTestingCompat = compat -) - -// If the default vertex array object (id 0) is not allowed on -// the target platform, we remap the uses to this array. -const DefaultVertexArrayId = VertexArrayId(0xFFFF0001) - -type extensions map[string]struct{} - -func listToExtensions(list []string) extensions { - out := extensions{} - for _, s := range list { - out[s] = struct{}{} - } - return out -} - -func translateExtensions(in U32ːstringᵐ) extensions { - out := make(extensions, in.Len()) - for _, s := range in.All() { - out[s] = struct{}{} - } - return out -} - -func (e extensions) get(name string) support { - if _, ok := e[name]; ok { - return supported - } - return unsupported -} - -func (s support) String() string { - switch s { - case unsupported: - return "unsupported" - case supported: - return "supported" - case required: - return "required" - default: - return fmt.Sprintf("support<%d>", s) - } -} - -type features struct { - vertexHalfFloatOES support // support for GL_OES_vertex_half_float - eglImageExternal support // support for GL_OES_EGL_image_external - textureMultisample support // support for ARB_texture_multisample - vertexArrayObjects support // support for VBOs - supportGenerateMipmapHint bool // support for GL_GENERATE_MIPMAP_HINT - compressedTextureFormats map[GLenum]struct{} - framebufferSrgb support // support for GL_FRAMEBUFFER_SRGB -} - -func getFeatures(ctx context.Context, version string, ext extensions) (features, *Version, error) { - v, err := ParseVersion(version) - if err != nil { - return features{}, v, err - } - - f := features{ - vertexHalfFloatOES: ext.get("GL_OES_vertex_half_float"), - eglImageExternal: ext.get("GL_OES_EGL_image_external"), - textureMultisample: ext.get("ARB_texture_multisample"), - compressedTextureFormats: getSupportedCompressedTextureFormats(v, ext), - supportGenerateMipmapHint: v.IsES, - } - - // TODO: Properly check the specifications for these flags. - switch { - case v.AtLeastES(3, 0): - f.vertexArrayObjects = supported - case v.AtLeastGL(3, 0): - f.vertexArrayObjects = required - } - - if v.AtLeastES(3, 2) { - f.textureMultisample = required - } - - // GLES defaults FRAMEBUFFER_SRGB to enabled and only allows changing it via - // an extension, while desktop GL defaults to disabled. - if v.IsES { - f.framebufferSrgb = ext.get("GL_EXT_sRGB_write_control") - } else { - f.framebufferSrgb = required - } - - return f, v, nil -} - -type onCompatError func(context.Context, api.CmdID, api.Cmd, error) - -func compat(ctx context.Context, device *device.Instance, onError onCompatError) (transform.Transformer, error) { - ctx = log.Enter(ctx, "compat") - if device.Configuration.Drivers.Opengl == nil { - return nil, fmt.Errorf("Could not find OpenGL device on host") - } - - glDev := device.Configuration.Drivers.Opengl - target, version, err := getFeatures(ctx, glDev.Version, listToExtensions(glDev.Extensions)) - if err != nil { - return nil, fmt.Errorf( - "Error '%v' when getting feature list for version: '%s', extensions: '%s'", - err, glDev.Version, glDev.Extensions) - } - - contexts := map[Contextʳ]features{} - bufferCompat := newBufferCompat(int(glDev.UniformBufferAlignment)) - eglContextHandle := map[Contextʳ]EGLContext{} - - nextTextureID := TextureId(0xffff0000) - newTexture := func(i api.CmdID, cb CommandBuilder, out transform.Writer) TextureId { - s := out.State() - id := nextTextureID - tmp := s.AllocDataOrPanic(ctx, id) - defer tmp.Free() - out.MutateAndWrite(ctx, i.Derived(), cb.GlGenTextures(1, tmp.Ptr()).AddWrite(tmp.Data())) - nextTextureID-- - return id - } - - // Definitions of Vertex Arrays backed by client memory. - // We postpone the write of the command until draw call. - clientVAs := map[VertexAttributeArrayʳ]*GlVertexAttribPointer{} - - textureCompat := &textureCompat{ - f: target, - v: version, - origSwizzle: map[GLenum]map[Textureʳ]GLenum{ - GLenum_GL_TEXTURE_SWIZZLE_R: {}, - GLenum_GL_TEXTURE_SWIZZLE_G: {}, - GLenum_GL_TEXTURE_SWIZZLE_B: {}, - GLenum_GL_TEXTURE_SWIZZLE_A: {}, - }, - compatSwizzle: map[Textureʳ]map[GLenum]GLenum{}, - } - - // TODO: Implement full support for external images. - convertTexTarget := func(tex interface { - Target() GLenum - SetTarget(GLenum) - }) { - t := tex.Target() - if t == GLenum_GL_TEXTURE_EXTERNAL_OES && target.eglImageExternal == unsupported { - // Remap external textures to plain 2D textures - this matches GLSL compat. - // TODO: This aliases GLenum_GL_TEXTURE_EXTERNAL_OES and GLenum_GL_TEXTURE_2D - tex.SetTarget(GLenum_GL_TEXTURE_2D) - } - } - - var t transform.Transformer - t = transform.Transform("compat", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - dID := id.Derived() - s := out.State() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - switch cmd := cmd.(type) { - case *EglMakeCurrent: // TODO: Check for GLX, CGL, WGL... - // The compatibility layer introduces calls to GL functions that are defined for desktop GL - // and for GLES 3.0+. If the trace originated on a GLES 2.0 device, these new commands' mutate - // functions will fail the minRequiredVersion checks (which look at the version coming from - // the original context from the trace). - // TODO(dsrbecky): This might make some commands valid for replay which were invalid on trace. - scs := FindStaticContextState(s.Arena, cmd.Extras()) - if !scs.IsNil() && !version.IsES && scs.Constants().MajorVersion() < 3 { - clone := cmd.clone(s.Arena) - clone.Extras().MustClone(cmd.Extras().All()...) - for _, e := range clone.Extras().All() { - if cs, ok := e.(*StaticContextState); ok { - cs.Constants().SetMajorVersion(3) - cs.Constants().SetMinorVersion(0) - } - } - cmd = clone - } - - // Mutate to set the context, Version and Extensions strings. - if err := out.MutateAndWrite(ctx, id, cmd); err != nil { - return err - } - - c := GetContext(s, cmd.Thread()) - if c.IsNil() || !c.Other().Initialized() { - return nil - } - if _, found := contexts[c]; found { - return nil - } - - source, _, err := getFeatures(ctx, c.Constants().Version(), translateExtensions(c.Constants().Extensions())) - if err != nil { - log.E(log.V{ - "version": c.Constants().Version(), - "extensions": c.Constants().Extensions(), - }.Bind(ctx), "Error getting feature list: %v", err) - return err - } - - contexts[c] = source - eglContextHandle[c] = cmd.Context() - - if target.vertexArrayObjects == required && - source.vertexArrayObjects != required { - // Replay device requires VAO, but capture did not enforce it. - // Satisfy the target by creating and binding a single VAO - // which we will use instead of the default VAO (id 0). - tmp := s.AllocDataOrPanic(ctx, VertexArrayId(DefaultVertexArrayId)) - defer tmp.Free() - if err := out.MutateAndWrite(ctx, dID, cb.GlGenVertexArrays(1, tmp.Ptr()).AddWrite(tmp.Data())); err != nil { - return err - } - if err := out.MutateAndWrite(ctx, dID, cb.GlBindVertexArray(DefaultVertexArrayId)); err != nil { - return err - } - } - return nil - - case *EglCreateImageKHR: - if target.eglImageExternal == unsupported { - // Only mutate, don't write. EGL images are treated as regular textures. - return cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - } - - if cmd.Target() == EGLenum_EGL_NATIVE_BUFFER_ANDROID { - // Need to create a texture, but probably don't have a context. - // This case is handled in glEGLImageTargetTexture2DOES below. - // Only mutate, don't write. - return cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - } - - return out.MutateAndWrite(ctx, id, cmd) - } - - c := GetContext(s, cmd.Thread()) - if c.IsNil() || !c.Other().Initialized() { - // The compatibility translations below assume that we have a valid context. - return out.MutateAndWrite(ctx, id, cmd) - } - - if cmd.CmdFlags(ctx, id, s).IsDrawCall() { - t := newTweaker(out, dID, cb) - disableUnusedAttribArrays(ctx, t) - defer t.revert(ctx) - } - - switch cmd := cmd.(type) { - case *GlBindBuffer: - if cmd.Buffer() == 0 { - buf, err := subGetBoundBuffer(ctx, nil, api.CmdNoID, nil, s, GetState(s), cmd.Thread(), nil, nil, cmd.Target()) - if err != nil { - log.E(ctx, "Can not get bound buffer: %v ", err) - } - if buf.IsNil() { - // The buffer is already unbound. Thus this command is a no-op. - // It is helpful to remove those no-ops in case the replay driver does not support the target. - return nil - } - } else if !c.Objects().GeneratedNames().Buffers().Get(cmd.Buffer()) { - // glGenBuffers() was not used to generate the buffer. Legal in GLES 2. - tmp := s.AllocDataOrPanic(ctx, cmd.Buffer()) - defer tmp.Free() - out.MutateAndWrite(ctx, dID, cb.GlGenBuffers(1, tmp.Ptr()).AddRead(tmp.Data())) - } - - case *GlBindTexture: - { - cmd := cmd.clone(s.Arena) - if cmd.Texture() != 0 && !c.Objects().GeneratedNames().Textures().Get(cmd.Texture()) { - // glGenTextures() was not used to generate the texture. Legal in GLES 2. - tmp := s.AllocDataOrPanic(ctx, cmd.Texture()) - out.MutateAndWrite(ctx, dID, cb.GlGenTextures(1, tmp.Ptr()).AddRead(tmp.Data())) - defer tmp.Free() - } - - convertTexTarget(cmd) - - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlBindVertexArray: - if cmd.Array() == VertexArrayId(0) { - if target.vertexArrayObjects == required && - contexts[c].vertexArrayObjects != required { - // NB: This leaks state change upstream. - // In particular, when the tweaker saves and then restores vertex array binding, - // it will restore it to DefaultVertexArrayId instead of 0. It is harmless. - return out.MutateAndWrite(ctx, id, cb.GlBindVertexArray(DefaultVertexArrayId)) - } - } - - case *GlBindVertexArrayOES: - if cmd.Array() == VertexArrayId(0) { - if target.vertexArrayObjects == required && - contexts[c].vertexArrayObjects != required { - return out.MutateAndWrite(ctx, id, cb.GlBindVertexArray(DefaultVertexArrayId)) - } - } - // Translate to non-OES call. - return out.MutateAndWrite(ctx, id, cb.GlBindVertexArray(cmd.Array())) - - case *GlGenVertexArraysOES: - // Translate to non-OES call. - c := cb.GlGenVertexArrays(cmd.Count(), cmd.Arrays()) - c.Extras().Add(cmd.Extras().All()...) - return out.MutateAndWrite(ctx, id, c) - - case *GlBindBufferBase: - if cmd.Buffer() == 0 { - genBuf, err := subGetBoundBuffer(ctx, nil, api.CmdNoID, nil, s, GetState(s), cmd.Thread(), nil, nil, cmd.Target()) - if err != nil { - onError(ctx, id, cmd, fmt.Errorf("Can not get bound buffer: %v", err)) - } - idxBuf, err := subGetBoundBufferAtIndex(ctx, nil, api.CmdNoID, nil, s, GetState(s), cmd.Thread(), nil, nil, cmd.Target(), cmd.Index()) - if err != nil { - onError(ctx, id, cmd, fmt.Errorf("Can not get bound buffer: %v", err)) - } - if genBuf.IsNil() && idxBuf.IsNil() { - // Both of the binding points are already clear. Thus this command is a no-op. - // It is helpful to remove those no-ops in case the replay driver does not support the target. - return nil - } - } - - case *GlBufferData: - bufferCompat.modifyBufferData(ctx, out, cb, c, id, cmd.Target(), func() { out.MutateAndWrite(ctx, id, cmd) }) - return nil - - case *GlBufferSubData: - bufferCompat.modifyBufferData(ctx, out, cb, c, id, cmd.Target(), func() { out.MutateAndWrite(ctx, id, cmd) }) - return nil - - case *GlCopyBufferSubData: - bufferCompat.modifyBufferData(ctx, out, cb, c, id, cmd.WriteTarget(), func() { out.MutateAndWrite(ctx, id, cmd) }) - return nil - - case *GlBindBufferRange: - bufferCompat.bindBufferRange(ctx, out, cb, c, id, cmd) - return nil - - case *GlDisableVertexAttribArray: - if c.Bound().VertexArray().VertexAttributeArrays().Get(cmd.Location()).Enabled() == GLboolean_GL_FALSE { - // Ignore the call if it is redundant (i.e. it is already disabled). - // Some applications iterate over all arrays and explicitly disable them. - // This is a problem if the target supports fewer arrays than the capture. - return nil - } - - case *GlVertexAttrib4fv: - if c.Vertex().Attributes().Contains(cmd.Location()) { - oldAttrib := c.Vertex().Attributes().Get(cmd.Location()) - oldValue := oldAttrib.Value().MustRead(ctx, cmd, s, nil /* builder */) - cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - newAttrib := c.Vertex().Attributes().Get(cmd.Location()) - newValue := newAttrib.Value().MustRead(ctx, cmd, s, nil /* builder */) - if reflect.DeepEqual(oldValue, newValue) { - // Ignore the call if it is redundant. - // Some applications iterate over all arrays and explicitly initialize them. - // This is a problem if the target supports fewer arrays than the capture. - return nil - } - } - return out.MutateAndWrite(ctx, id, cmd) - - case *GlGetVertexAttribIiv, - *GlGetVertexAttribIuiv, - *GlGetVertexAttribPointerv, - *GlGetVertexAttribfv, - *GlGetVertexAttribiv: - // Some applications iterate over all arrays and query their state. - // This may fail if the target supports fewer arrays than the capture. - // As these should have no side-effects, just drop them. - return nil - - case *GlShaderSource: - if version.IsES { // No compat required. - return out.MutateAndWrite(ctx, id, cmd) - } - // Apply the state mutation of the unmodified glShaderSource - // command. - // This is so we can grab the source string from the Shader object. - // We will actually provide the source to driver at compile time. - return cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - - case *GlCompileShader: - if version.IsES { // No compat required. - return out.MutateAndWrite(ctx, id, cmd) - } - shader := c.Objects().Shaders().Get(cmd.Shader()) - src := "" - - st, err := shader.Type().ShaderType() - if err != nil { - onError(ctx, id, cmd, err) - } - opts := shadertools.ConvertOptions{ - ShaderType: st, - Relaxed: true, // find_issues will still report bad GLSL. - StripOptimizations: true, - TargetGLSLVersion: version.MaxGLSL().AsInt(), - } - - // Trim any prefix whitespace / newlines. - // This isn't legal if it comes before the #version, but this - // will be picked up by find_issues.go anyway. - src = strings.TrimLeft(shader.Source(), "\n\r\t ") - - res, err := shadertools.ConvertGlsl(src, &opts) - if err != nil { - // Could not convert the shader. - onError(ctx, id, cmd, err) - return out.MutateAndWrite(ctx, id, cmd) - } - - src = res.SourceCode - - tmpSrc := s.AllocDataOrPanic(ctx, src) - tmpPtrToSrc := s.AllocDataOrPanic(ctx, tmpSrc.Ptr()) - defer tmpSrc.Free() - defer tmpPtrToSrc.Free() - srcCmd := cb.GlShaderSource(cmd.Shader(), 1, tmpPtrToSrc.Ptr(), memory.Nullptr). - AddRead(tmpSrc.Data()). - AddRead(tmpPtrToSrc.Data()) - return out.MutateAndWrite(ctx, id, srcCmd) - - // TODO: glVertexAttribIPointer - case *GlVertexAttribPointer: - if cmd.Type() == GLenum_GL_HALF_FLOAT_OES && target.vertexHalfFloatOES == unsupported { - // Convert GL_HALF_FLOAT_OES to GL_HALF_FLOAT_ARB. - cmd = cb.GlVertexAttribPointer(cmd.Location(), cmd.Size(), GLenum_GL_HALF_FLOAT_ARB, cmd.Normalized(), cmd.Stride(), memory.Pointer(cmd.Data())) - } - vaa := c.Bound().VertexArray().VertexAttributeArrays().Get(cmd.Location()) - if target.vertexArrayObjects == required && c.Bound().ArrayBuffer().IsNil() { - // Client-pointers are not supported, we need to copy this data to a buffer. - // However, we can't do this now as the observation only happens at the draw call. - clientVAs[vaa] = cmd - } else { - delete(clientVAs, vaa) - return out.MutateAndWrite(ctx, id, cmd) - } - return nil - - case *GlDrawBuffers: - // Currently the default framebuffer for replay is single-buffered - // and so we need to transform any usage of GL_BACK to GL_FRONT. - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - bufs := cmd.Bufs().Slice(0, uint64(cmd.N()), s.MemoryLayout).MustRead(ctx, cmd, s, nil) - for i, buf := range bufs { - if buf == GLenum_GL_BACK { - bufs[i] = GLenum_GL_FRONT - } - } - tmp := s.AllocDataOrPanic(ctx, bufs) - defer tmp.Free() - return out.MutateAndWrite(ctx, id, cb.GlDrawBuffers(cmd.N(), tmp.Ptr()).AddRead(tmp.Data())) - - case *GlDrawArrays: - if target.vertexArrayObjects == required { - if clientVAsBound(c, clientVAs) { - first := uint32(cmd.FirstIndex()) - count := uint32(cmd.IndicesCount()) - t := newTweaker(out, dID, cb) - defer t.revert(ctx) - moveClientVBsToVAs(ctx, t, clientVAs, first, count, id, cmd, s, c, out) - } - } - compatMultiviewDraw(ctx, id, cmd, out) - return nil - - case drawElements: - if target.vertexArrayObjects != required { - compatMultiviewDraw(ctx, id, cmd, out) - } else { - t := newTweaker(out, dID, cb) - defer t.revert(ctx) - compatDrawElements(ctx, t, clientVAs, id, cmd, s, out) - } - return nil - - case *GlCompressedTexImage2D: - if _, supported := target.compressedTextureFormats[cmd.Internalformat()]; !supported { - if err := decompressTexImage2D(ctx, id, cmd, s, out); err == nil { - return nil - } - onError(ctx, id, cmd, fmt.Errorf("Error decompressing texture: %v", err)) - } - - case *GlCompressedTexSubImage2D: - if _, supported := target.compressedTextureFormats[cmd.Internalformat()]; !supported { - if err := decompressTexSubImage2D(ctx, id, cmd, s, out); err == nil { - return nil - } - onError(ctx, id, cmd, fmt.Errorf("Error decompressing texture: %v", err)) - } - - case *GlTexBufferEXT: - if version.AtLeastGL(3, 1) { // Strip suffix on desktop. - cmd := cb.GlTexBuffer(cmd.Target(), cmd.Internalformat(), cmd.Buffer()) - return out.MutateAndWrite(ctx, id, cmd) - } - - // TODO: glTexStorage functions are not guaranteed to be supported. Consider replacing with glTexImage calls. - // TODO: Handle glTextureStorage family of functions - those use direct state access, not the bound texture. - case *GlTexStorage1DEXT: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - cmd := cb.GlTexStorage1D(cmd.Target(), cmd.Levels(), cmd.Internalformat(), cmd.Width()) - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage2D: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage2DEXT: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - cmd := cb.GlTexStorage2D(cmd.Target(), cmd.Levels(), cmd.Internalformat(), cmd.Width(), cmd.Height()) - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage2DMultisample: - if version.IsES || version.AtLeastGL(4, 3) { - // glTexStorage2DMultisample is supported by replay device. - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } else { - // glTexStorage2DMultisample is not supported by replay device. - // Use glTexImage2DMultisample instead. - cmd := cb.GlTexImage2DMultisample(cmd.Target(), cmd.Samples(), cmd.Internalformat(), cmd.Width(), cmd.Height(), cmd.Fixedsamplelocations()) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage3D: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage3DEXT: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - cmd := cb.GlTexStorage3D(cmd.Target(), cmd.Levels(), cmd.Internalformat(), cmd.Width(), cmd.Height(), cmd.Depth()) - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage3DMultisample: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexStorage3DMultisampleOES: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - cmd := cb.GlTexStorage3DMultisample(cmd.Target(), cmd.Samples(), cmd.Internalformat(), cmd.Width(), cmd.Height(), cmd.Depth(), cmd.Fixedsamplelocations()) - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexImage2D: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{ - func() GLenum { return GLenum(cmd.Internalformat()) }, - func(fmt GLenum) { cmd.SetInternalformat(GLint(fmt)) }, - } - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, fmt, ty, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexImage3D: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{ - func() GLenum { return GLenum(cmd.Internalformat()) }, - func(fmt GLenum) { cmd.SetInternalformat(GLint(fmt)) }, - } - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, fmt, ty, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexImage3DOES: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, fmt, ty, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - extras := cmd.extras - cmd := cb.GlTexImage3D(cmd.Target(), cmd.Level(), GLint(cmd.Internalformat()), cmd.Width(), cmd.Height(), cmd.Depth(), cmd.Border(), cmd.Fmt(), cmd.Type(), memory.Pointer(cmd.Pixels())) - cmd.extras = extras - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexSubImage2D: - { - cmd := cmd.clone(s.Arena) - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), nil, fmt, ty, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexSubImage3D: - { - cmd := cmd.clone(s.Arena) - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), nil, fmt, ty, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlTexSubImage3DOES: - { - cmd := cmd.clone(s.Arena) - fmt := &glenumProperty{cmd.Fmt, cmd.SetFmt} - ty := &glenumProperty{cmd.Type, cmd.SetType} - textureCompat.convertFormat(ctx, cmd.Target(), nil, fmt, ty, out, id, cmd) - if !version.IsES { // Strip suffix on desktop. - extras := cmd.extras - cmd := cb.GlTexSubImage3D(cmd.Target(), cmd.Level(), cmd.Xoffset(), cmd.Yoffset(), cmd.Zoffset(), cmd.Width(), cmd.Height(), cmd.Depth(), cmd.Fmt(), cmd.Type(), memory.Pointer(cmd.Pixels())) - cmd.extras = extras - return out.MutateAndWrite(ctx, id, cmd) - } - return out.MutateAndWrite(ctx, id, cmd) - } - case *GlCopyTexImage2D: - { - cmd := cmd.clone(s.Arena) - internalFormat := &glenumProperty{cmd.Internalformat, cmd.SetInternalformat} - textureCompat.convertFormat(ctx, cmd.Target(), internalFormat, nil, nil, out, id, cmd) - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlTexParameterIivOES: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterIuivOES: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterIiv: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterIuiv: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterf: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Parameter(), out, id, cmd) - return err - } - case *GlTexParameterfv: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameteri: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Parameter(), out, id, cmd) - return err - } - case *GlTexParameteriv: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterIivEXT: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - case *GlTexParameterIuivEXT: - { - cmd := cmd.clone(s.Arena) - convertTexTarget(cmd) - err := out.MutateAndWrite(ctx, id, cmd) - textureCompat.postTexParameter(ctx, cmd.Target(), cmd.Pname(), out, id, cmd) - return err - } - - case *GlProgramBinary: - if !canUsePrecompiledShader(c, glDev) { - for _, cmd := range buildStubProgram(ctx, cmd.Thread(), cmd.Extras(), s, cmd.Program()) { - t.Transform(ctx, id, cmd, out) - } - return nil - } - - case *GlProgramBinaryOES: - if !canUsePrecompiledShader(c, glDev) { - for _, cmd := range buildStubProgram(ctx, cmd.Thread(), cmd.Extras(), s, cmd.Program()) { - t.Transform(ctx, id, cmd, out) - } - return nil - } - - case *GlHint: - if cmd.Target() == GLenum_GL_GENERATE_MIPMAP_HINT && !target.supportGenerateMipmapHint { - return nil // Not supported in the core profile of OpenGL. - } - - case *GlDebugMessageCallback, - *GlDebugMessageControl, - *GlDebugMessageCallbackKHR, - *GlDebugMessageControlKHR: - // Ignore - the callback function address is invalid in replay. - return nil - - case *GlGetBooleani_v, - *GlGetBooleanv, - *GlGetFloatv, - *GlGetInteger64i_v, - *GlGetInteger64v, - *GlGetIntegeri_v, - *GlGetIntegerv, - *GlGetInternalformativ, - *GlGetString, - *GlGetStringi: - // The acceptable values of these get functions vary between GL versions. - // As these should have no side-effects, just drop them. - return nil - - case *GlGetActiveAttrib, - *GlGetActiveUniform: - // The number of active attributes and uniforms can vary between compilers - // depending on their ability to eliminate dead code. In particular, - // dead code in pixel shader can allow code removal in the vertex shader. - // As these should have no side-effects, just drop them. - return nil - - case *GlGetProgramInterfaceiv: - // Introduced as core in 4.3, but macOS caps out at 4.1. - // As this should have no side-effects, just drop them. - return nil - - case *GlLabelObjectEXT, - *GlGetObjectLabelEXT, - *GlObjectLabel, - *GlObjectLabelKHR, - *GlGetObjectLabel, - *GlObjectPtrLabel, - *GlGetObjectPtrLabel, - *GlGetObjectLabelKHR: - // These methods require non-trivial remapping for replay. - // As they do not affect rendering output, just drop them. - return nil - - case *GlInsertEventMarkerEXT, - *GlPushGroupMarkerEXT, - *GlPopGroupMarkerEXT, - *GlPushDebugGroup, - *GlPopDebugGroup, - *GlPushDebugGroupKHR, - *GlPopDebugGroupKHR, - *GlDebugMessageInsertKHR: - // Debug markers may not be supported on the replay device. - // As they do not affect rendering output, just drop them. - return nil - - case *GlGetProgramBinary, - *GlGetProgramBinaryOES: - // Program binaries are very driver specific. This command may fail on replay - // because one of the arguments must be GL_PROGRAM_BINARY_LENGTH. - // It has no side effects, so just drop it. - return nil - - case *GlEnable: - if cmd.Capability() == GLenum_GL_FRAMEBUFFER_SRGB && - target.framebufferSrgb == required && contexts[c].framebufferSrgb != required && - c.Bound().DrawFramebuffer().GetID() == 0 { - // Ignore enabling of FRAMEBUFFER_SRGB if the capture device did not - // support an SRGB default framebuffer, but the replay device does. This - // is only done if the current bound draw framebuffer is the default - // framebuffer. The state is mutated so that when a non-default - // framebuffer is bound later on, FRAMEBUFFER_SRGB will be enabled. - // (see GlBindFramebuffer below) - return cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - } - - case *GlDisable: - // GL_QCOM_alpha_test adds back GL_ALPHA_TEST from GLES 1.0 as extension. - // It seems that applications only disable it to make sure it is off, so - // we can safely ignore it. We should not ignore glEnable for it though. - if cmd.Capability() == GLenum_GL_ALPHA_TEST_QCOM { - return nil - } - - case *GlGetGraphicsResetStatusEXT: - // From extension GL_EXT_robustness - // It may not be implemented by the replay driver. - // It has no effect on rendering so just drop it. - return nil - - case *GlDiscardFramebufferEXT: // GL_EXT_discard_framebuffer - // It may not be implemented by the replay driver. - // It is only a hint so we can just drop it. - // TODO: It has performance impact so we should not ignore it when profiling. - return nil - - case *GlInvalidateFramebuffer, *GlInvalidateSubFramebuffer: - if !version.AtLeastES(3, 0) || !version.AtLeastGL(4, 3) { - return nil // Not supported. Only a hint. Drop it. - } - - case *GlMapBufferOES: - if !version.IsES { // Remove extension suffix on desktop. - cmd := cb.GlMapBuffer(cmd.Target(), cmd.Access(), memory.Pointer(cmd.Result())) - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlMapBufferRangeEXT: - if !version.IsES { // Remove extension suffix on desktop. - cmd := cb.GlMapBufferRange(cmd.Target(), cmd.Offset(), cmd.Length(), cmd.Access(), memory.Pointer(cmd.Result())) - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlFlushMappedBufferRangeEXT: - if !version.IsES { // Remove extension suffix on desktop. - extras := cmd.extras - cmd := cb.GlFlushMappedBufferRange(cmd.Target(), cmd.Offset(), cmd.Length()) - cmd.extras = extras - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlUnmapBufferOES: - if !version.IsES { // Remove extension suffix on desktop. - extras := cmd.extras - cmd := cb.GlUnmapBuffer(cmd.Target(), cmd.Result()) - cmd.extras = extras - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlDeleteBuffers: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Buffers().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Buffers()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteBuffers(cnt, buf) }) - return nil - } - - case *GlDeleteFramebuffers: - // If you delete a framebuffer that is currently bound then the - // binding automatically reverts back to the default framebuffer - // (0). As we do compat for glBindFramebuffer(), scan the list of - // framebuffers that are being deleted, and forward them to a fake - // call to glBindFramebuffer(XXX, 0) if we find any. - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - fbs, err := cmd.Framebuffers().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - for _, fb := range fbs { - if fb == c.Bound().DrawFramebuffer().ID() { - t.Transform(ctx, dID, cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, 0), out) - } - if fb == c.Bound().ReadFramebuffer().ID() { - t.Transform(ctx, dID, cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, 0), out) - } - } - - deleteCompat(ctx, fbs, dID, dictionary.From(c.Objects().Framebuffers()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteFramebuffers(cnt, buf) }) - return nil - } - - case *GlDeleteProgramPipelines: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Pipelines().Slice(0, uint64(cmd.N()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Pipelines()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteProgramPipelines(cnt, buf) }) - return nil - } - - case *GlDeleteQueries: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Queries().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Queries()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteQueries(cnt, buf) }) - return nil - } - - case *GlDeleteRenderbuffers: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Renderbuffers().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Renderbuffers()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteRenderbuffers(cnt, buf) }) - return nil - } - - case *GlDeleteSamplers: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Samplers().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Samplers()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteSamplers(cnt, buf) }) - return nil - } - - case *GlDeleteTextures: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Textures().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().Textures()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteTextures(cnt, buf) }) - return nil - } - - case *GlDeleteTransformFeedbacks: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Ids().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().TransformFeedbacks()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteTransformFeedbacks(cnt, buf) }) - return nil - } - - case *GlDeleteVertexArrays: - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - ids, err := cmd.Arrays().Slice(0, uint64(cmd.Count()), s.MemoryLayout).Read(ctx, cmd, s, nil) - if err == nil { - deleteCompat(ctx, ids, dID, dictionary.From(c.Objects().VertexArrays()), s, out, - func(cnt GLsizei, buf memory.Pointer) api.Cmd { return cb.GlDeleteVertexArrays(cnt, buf) }) - return nil - } - - case *GlBindFramebuffer: - if cmd.Framebuffer() != 0 && !c.Objects().GeneratedNames().Framebuffers().Get(cmd.Framebuffer()) { - // glGenFramebuffers() was not used to generate the buffer. Legal in GLES. - tmp := s.AllocDataOrPanic(ctx, cmd.Framebuffer()) - defer tmp.Free() - out.MutateAndWrite(ctx, dID, cb.GlGenFramebuffers(1, tmp.Ptr()).AddRead(tmp.Data())) - } - - if target.framebufferSrgb == required && contexts[c].framebufferSrgb != required && - c.Pixel().FramebufferSrgb() != 0 { - // Replay device defaults FRAMEBUFFER_SRGB to disabled and allows - // enabling it (desktop), while the capture device defaulted to enabled - // and may or may not have allowed it to be changed (GLES). While at the - // same time, we currently assume that the default frame buffer is not - // SRGB capable. Thus, when SRGB is enabled in the state, and we're - // binding the default framebuffer, SRGB needs to be disabled, and - // specifically enabled when binding the non-default framebuffer. - // (If it was explicitly disabled in the capture, no change is needed.) - // TODO: Handle the use of the EGL KHR_gl_colorspace extension. - if cmd.Target() == GLenum_GL_FRAMEBUFFER || cmd.Target() == GLenum_GL_DRAW_FRAMEBUFFER { - origSrgb := c.Pixel().FramebufferSrgb() - if cmd.Framebuffer() == 0 { - out.MutateAndWrite(ctx, dID, cb.GlDisable(GLenum_GL_FRAMEBUFFER_SRGB)) - } else { - out.MutateAndWrite(ctx, dID, cb.GlEnable(GLenum_GL_FRAMEBUFFER_SRGB)) - } - // Change the replay driver state, but keep our mutated state, - // so we know what to do the next time we see glBindFramebuffer. - // TODO: Handle SRGB better. - c.Pixel().SetFramebufferSrgb(origSrgb) - } - } - - case *EglDestroyContext: - // Removing the context would interfere with the EGLImage compat below, - // since TextureID remapping relies on being able to find the Context by ID. - return nil - - case *GlEGLImageTargetTexture2DOES: - { - eglImage := GetState(s).EGLImages().Get(EGLImageKHR(cmd.Image())) - if eglImage.IsNil() { - analytics.SendBug(1498) - onError(ctx, id, cmd, fmt.Errorf("Encountered nil eglImage. Replay may be corrupt. See: https://github.com/google/gapid/issues/1498")) - return out.MutateAndWrite(ctx, id, cmd) - } - - t := newTweaker(out, dID, cb) - t.GlBindBuffer_PixelUnpackBuffer(ctx, 0) - - imgs := eglImage.Images() - img := imgs.Get(0) - sizedFormat := img.SizedFormat() // Might be RGB565 which is not supported on desktop - sizedFormatProp := &glenumProperty{func() GLenum { return sizedFormat }, func(f GLenum) { sizedFormat = f }} - - if target.eglImageExternal == unsupported { - target := cmd.Target() - - switch target { - case GLenum_GL_TEXTURE_2D, GLenum_GL_TEXTURE_EXTERNAL_OES: - // First time this texture is sync'ed. Initilize it. - if c.Bound().TextureUnit().Binding2d().Image().IsNil() { - textureCompat.convertFormat(ctx, GLenum_GL_TEXTURE_2D, sizedFormatProp, nil, nil, out, id, cmd) - out.MutateAndWrite(ctx, dID, cb.GlTexImage2D(GLenum_GL_TEXTURE_2D, 0, GLint(sizedFormat), img.Width(), img.Height(), 0, img.DataFormat(), img.DataType(), memory.Nullptr)) - // External textures use GL_LINEAR as the default and only allow GL_LINEAR or GL_NEAREST. - if c.Bound().TextureUnit().Binding2d().MinFilter() == GLenum_GL_NEAREST_MIPMAP_LINEAR { - out.MutateAndWrite(ctx, dID, cb.GlTexParameteri(GLenum_GL_TEXTURE_2D, GLenum_GL_TEXTURE_MIN_FILTER, GLint(GLenum_GL_LINEAR))) - } - } - case GLenum_GL_TEXTURE_2D_ARRAY: - // First time this texture is sync'ed. Initilize it. - if c.Bound().TextureUnit().Binding2dArray().Image().IsNil() { - textureCompat.convertFormat(ctx, GLenum_GL_TEXTURE_2D_ARRAY, sizedFormatProp, nil, nil, out, id, cmd) - out.MutateAndWrite(ctx, dID, cb.GlTexImage3D(GLenum_GL_TEXTURE_2D_ARRAY, 0, GLint(sizedFormat), img.Width(), img.Height(), GLsizei(imgs.Len()), 0, img.DataFormat(), img.DataType(), memory.Nullptr)) - // External textures use GL_LINEAR as the default and only allow GL_LINEAR or GL_NEAREST. - if c.Bound().TextureUnit().Binding2dArray().MinFilter() == GLenum_GL_NEAREST_MIPMAP_LINEAR { - out.MutateAndWrite(ctx, dID, cb.GlTexParameteri(GLenum_GL_TEXTURE_2D_ARRAY, GLenum_GL_TEXTURE_MIN_FILTER, GLint(GLenum_GL_LINEAR))) - } - } - default: - onError(ctx, id, cmd, fmt.Errorf("Unexpected GlEGLImageTargetTexture2DOES target: %v", target)) - } - } else { - switch eglImage.Target() { - case EGLenum_EGL_GL_TEXTURE_2D: - // Already a texture backed external image. - case EGLenum_EGL_NATIVE_BUFFER_ANDROID: - // Create a new texture and create the external image based on it instead. - texID := newTexture(id, cb, out) - t.glBindTexture_2D(ctx, texID) - textureCompat.convertFormat(ctx, GLenum_GL_TEXTURE_2D, sizedFormatProp, nil, nil, out, id, cmd) - out.MutateAndWrite(ctx, dID, cb.GlTexImage2D(GLenum_GL_TEXTURE_2D, 0, GLint(sizedFormat), img.Width(), img.Height(), 0, img.DataFormat(), img.DataType(), memory.Nullptr)) - // The mutate here will change the EGLImage to now be backed by our texture. - // We can pass null pointers for most arguments, as they are ignored in the - // custom replay. - out.MutateAndWrite(ctx, dID, cb.EglCreateImageKHR(memory.Nullptr, eglContextHandle[c], EGLenum_EGL_GL_TEXTURE_2D, EGLClientBuffer(texID), memory.Nullptr, cmd.Image())) - default: - onError(ctx, id, cmd, fmt.Errorf("Unexpected eglCreateImageKHR target: %v", cmd.Target())) - } - } - - // Update the content if we made a snapshot. - if e := FindEGLImageData(cmd.Extras()); e != nil { - t.setUnpackStorage(ctx, NewPixelStorageState(s.Arena, - 0, // ImageHeight - 0, // SkipImages - 0, // RowLength - 0, // SkipRows - 0, // SkipPixels - 1, // Alignment - ), 0) - if target.eglImageExternal != unsupported && eglImage.Target() == EGLenum_EGL_GL_TEXTURE_2D { - // Update the actual underlying texture of the eglImage. - t.eglMakeCurrent(ctx, eglImage.Context()) - t.glBindTexture_2D(ctx, TextureId(eglImage.Buffer().Address())) - } - - ptr := s.AllocOrPanic(ctx, e.Size) - out.MutateAndWrite(ctx, dID, cb.GlTexSubImage2D(GLenum_GL_TEXTURE_2D, 0, 0, 0, e.Width, e.Height, e.Format, e.Type, ptr.Ptr()).AddRead(ptr.Range(), e.ID)) - ptr.Free() - } - - // The revert is needed before we replay the command to restore - // the correct context and texture bindings. - t.revert(ctx) - if target.eglImageExternal != unsupported { - out.MutateAndWrite(ctx, id, cmd) - } - return nil - } - - // EXT_multisampled_render_to_texture - case *GlRenderbufferStorageMultisampleEXT: - { - // TODO: Support multi-sample rendering. - cmd := cb.GlRenderbufferStorage(cmd.Target(), cmd.Internalformat(), cmd.Width(), cmd.Height()) - return out.MutateAndWrite(ctx, id, cmd) - } - - // EXT_multisampled_render_to_texture - case *GlFramebufferTexture2DMultisampleEXT: - { - // TODO: Support multi-sample rendering. - cmd := cb.GlFramebufferTexture2D(cmd.Target(), cmd.Attachment(), cmd.Textarget(), cmd.Texture(), cmd.Level()) - return out.MutateAndWrite(ctx, id, cmd) - } - - case *GlFramebufferTextureMultiviewOVR: - { - cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - // Translate it to the non-multiview version, but do not modify state, - // otherwise we would lose the knowledge about view count. - return out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - cb.GlFramebufferTextureLayer(cmd.Target(), cmd.Attachment(), cmd.Texture(), cmd.Level(), cmd.BaseViewIndex()).Call(ctx, s, b) - return nil - })) - } - - case *GlFramebufferTextureMultisampleMultiviewOVR: - { - // TODO: Support multi-sample rendering. - cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */) - // Translate it to the non-multiview version, but do not modify state, - // otherwise we would lose the knowledge about view count. - return out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - cb.GlFramebufferTextureLayer(cmd.Target(), cmd.Attachment(), cmd.Texture(), cmd.Level(), cmd.BaseViewIndex()).Call(ctx, s, b) - return nil - })) - } - - case *GlLinkProgram: - { - out.MutateAndWrite(ctx, id, cmd) - // Forcefully get all uniform locations, so that we can remap for applications that - // just assume locations (in particular, apps tend to assume arrays are consecutive) - // TODO: We should warn the developers that the consecutive layout is not guaranteed. - prog := c.Objects().Programs().Get(cmd.Program()) - if res := prog.ActiveResources(); !res.IsNil() { - for _, uniformIndex := range res.DefaultUniformBlock().Keys() { - uniform := res.DefaultUniformBlock().Get(uniformIndex) - baseName := strings.TrimSuffix(uniform.Name(), "[0]") - for i := uint32(0); i < uint32(uniform.ArraySize()); i++ { - name := baseName - if i != 0 { - name = fmt.Sprintf("%v[%v]", name, i) - } - loc := UniformLocation(uniform.Locations().Get(i)) - tmp := s.AllocDataOrPanic(ctx, name) - defer tmp.Free() - cmd := cb.GlGetUniformLocation(cmd.Program(), tmp.Ptr(), loc). - AddRead(tmp.Data()) - out.MutateAndWrite(ctx, dID, cmd) - } - } - } - return nil - } - - case *GlStartTilingQCOM, *GlEndTilingQCOM, - *EglCreateNativeClientBufferANDROID: - if !version.IsES { - // This extension is not applicable on desktop. - return nil - } - - default: - flags := cmd.CmdFlags(ctx, id, s) - if flags.IsClear() { - compatMultiviewDraw(ctx, id, cmd, out) - return nil - } - if flags.IsDrawCall() { - if clientVAsBound(c, clientVAs) { - onError(ctx, id, cmd, fmt.Errorf("Draw call with client-pointers not handled by the compatability layer. Command: %v", cmd)) - } - compatMultiviewDraw(ctx, id, cmd, out) - return nil - } - } - - return out.MutateAndWrite(ctx, id, cmd) - }) - - return t, nil -} - -// Naive multiview implementation - invoke each draw call several times with different layers -func compatMultiviewDraw(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) { - s := out.State() - c := GetContext(s, cmd.Thread()) - dID := id.Derived() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - numViews := uint32(1) - c.Bound().DrawFramebuffer().ForEachAttachment(func(name GLenum, att FramebufferAttachment) { - numViews = u32.Max(numViews, uint32(att.NumViews())) - }) - if numViews > 1 { - for viewID := GLuint(0); viewID < GLuint(numViews); viewID++ { - // Set the magic uniform which shaders use to fetch view-dependent attributes. - // It is missing from the observed extras, so normal mutation would fail. - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - if !c.Bound().Program().IsNil() { - viewIDLocation := UniformLocation(0x7FFF0000) - tmp := s.AllocDataOrPanic(ctx, "gapid_gl_ViewID_OVR") - defer tmp.Free() - cb.GlGetUniformLocation(c.Bound().Program().ID(), tmp.Ptr(), viewIDLocation). - AddRead(tmp.Data()). - Call(ctx, s, b) - cb.GlUniform1ui(viewIDLocation, viewID).Call(ctx, s, b) - } - return nil - })) - - // For each attachment, bind the layer corresponding to this ViewID. - // Do not modify the state so that we do not revert to single-view for next draw call. - c.Bound().DrawFramebuffer().ForEachAttachment(func(name GLenum, a FramebufferAttachment) { - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - if !a.Texture().IsNil() { - cb.GlFramebufferTextureLayer(GLenum_GL_DRAW_FRAMEBUFFER, name, a.Texture().ID(), a.TextureLevel(), a.TextureLayer()+GLint(viewID)).Call(ctx, s, b) - } - return nil - })) - }) - out.MutateAndWrite(ctx, id, cmd) - } - } else { - out.MutateAndWrite(ctx, id, cmd) - } -} - -func (fb Framebufferʳ) ForEachAttachment(action func(GLenum, FramebufferAttachment)) { - for _, i := range fb.ColorAttachments().Keys() { - action(GLenum_GL_COLOR_ATTACHMENT0+GLenum(i), fb.ColorAttachments().Get(i)) - } - action(GLenum_GL_DEPTH_ATTACHMENT, fb.DepthAttachment()) - action(GLenum_GL_STENCIL_ATTACHMENT, fb.StencilAttachment()) -} - -// canUsePrecompiledShader returns true if precompiled shaders / programs -// captured with the context c can be replayed on the device d. -func canUsePrecompiledShader(c Contextʳ, d *device.OpenGLDriver) bool { - return c.Constants().Vendor() == d.Vendor && c.Constants().Version() == d.Version -} - -// disableUnusedAttribArrays disables all vertex attribute arrays that are not -// used by the currently bound program. This is a compatibility fix for devices -// that will error with GL_INVALID_OPERATION if there's an enabled (but unused) -// vertex attribute array that has no array data when drawing. AFAICT, this -// particular behavior is undefined according to the spec. -func disableUnusedAttribArrays(ctx context.Context, t *tweaker) { - p := t.c.Bound().Program() - if p.IsNil() || p.ActiveResources().IsNil() { - return - } - inputs := p.ActiveResources().ProgramInputs() - used := make([]bool, t.c.Constants().MaxVertexAttribBindings()) - for _, input := range inputs.All() { - for _, l := range input.Locations().All() { - if l >= 0 && l < GLint(len(used)) { - used[l] = true - } - } - } - - for _, l := range t.c.Bound().VertexArray().VertexAttributeArrays().Keys() { - arr := t.c.Bound().VertexArray().VertexAttributeArrays().Get(l) - if arr.Enabled() == GLboolean_GL_TRUE && l < AttributeLocation(len(used)) && !used[l] { - t.glDisableVertexAttribArray(ctx, l) - } - } -} - -// It is a no-op to delete objects that do not exist. -// GAPID uses a shared context for replay - while its fine to delete ids that do -// not exist in this context, they might exist in another. Strip out any ids -// that do not belong to this context. -func deleteCompat( - ctx context.Context, - ids interface{}, - id api.CmdID, - d dictionary.I, - s *api.GlobalState, - out transform.Writer, - create func(GLsizei, memory.Pointer) api.Cmd) { - - r := reflect.ValueOf(ids) - count := r.Len() - zero := reflect.Zero(r.Type().Elem()) - for i := 0; i < count; i++ { - id := r.Index(i).Interface() - if !d.Contains(id) { - r.Index(i).Set(zero) // Deleting 0 is also a no-op. - } - } - - tmp := s.AllocDataOrPanic(ctx, ids) - defer tmp.Free() - cmd := create(GLsizei(count), tmp.Ptr()) - cmd.Extras().GetOrAppendObservations().AddRead(tmp.Data()) - out.MutateAndWrite(ctx, id, cmd) -} diff --git a/gapis/api/gles/compat_buffers.go b/gapis/api/gles/compat_buffers.go deleted file mode 100644 index f5b09d0b8d..0000000000 --- a/gapis/api/gles/compat_buffers.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" -) - -// bufferCompat provides compatibility transformations for GL buffers. -type bufferCompat struct { - // uniformBufferAlignment is the target's minimum alignment for uniform - // buffers. - uniformBufferAlignment int - // unaligned is a map of compat generated aligned buffer IDs to their - // original buffer. - unaligned map[BufferId]Bufferʳ - // scratch holds the temporary buffers created by the bufferCompat. - scratch map[scratchBufferKey]scratchBuffer - // nextBufferID is the buffer identifer to use for the next created scratch - // buffer. - nextBufferID BufferId -} - -func newBufferCompat(uniformBufferAlignment int) *bufferCompat { - return &bufferCompat{ - uniformBufferAlignment: uniformBufferAlignment, - unaligned: map[BufferId]Bufferʳ{}, - scratch: map[scratchBufferKey]scratchBuffer{}, - nextBufferID: BufferId(0xffff0000), - } -} - -// scratchBufferKey is the key to the bufferCompat's scratch-buffer map. -type scratchBufferKey struct { - c Contextʳ // The current GL context. - Target GLenum // The buffer target. - Index GLuint // The buffer binding index. -} - -// scratchBufferKey is the value to the bufferCompat's scratch-buffer map. -type scratchBuffer struct { - size GLsizeiptr // Size of the buffer. - id BufferId // Identifier of the buffer. -} - -// modifyBufferData deals with the complexities of copying unaligned buffer data -// to their aligned copies and should be called when ever a buffer is to be -// modified. modify is called to apply the buffer modification. -func (m *bufferCompat) modifyBufferData(ctx context.Context, out transform.Writer, cb CommandBuilder, c Contextʳ, id api.CmdID, target GLenum, modify func()) { - id = id.Derived() - s := out.State() - - // Get the target buffer. - buf, err := subGetBoundBuffer(ctx, nil, api.CmdNoID, nil, s, GetState(s), cb.Thread, nil, nil, target) - if buf.IsNil() || err != nil { - // Unknown buffer - modify() - return - } - - // Lookup the original (unaligned) buffer. - unaligned, ok := m.unaligned[buf.ID()] - if !ok { - // Buffer was not unaligned - modify() - return - } - - // Walk the current bindings looking for those referencing the aligned - // buffer. - type binding struct { - index GLuint - offset GLintptr - size GLsizeiptr - } - - rebind := []binding{} - for i, b := range c.Bound().UniformBuffers().All() { - if b.Binding().IsNil() || m.unaligned[b.Binding().ID()] != unaligned { - continue - } - - rebind = append(rebind, binding{ - index: GLuint(i), - offset: b.Start(), - size: b.Size(), - }) - } - - if len(rebind) == 0 { - // No unaligned buffers require copying. - modify() - return - } - - // Bind the original unaligned buffer. - out.MutateAndWrite(ctx, id, cb.GlBindBuffer(target, unaligned.ID())) - - // Apply the modification. - modify() - - // Rebind all the unaligned bindings. - for _, r := range rebind { - cmd := cb.GlBindBufferRange(target, r.index, buf.ID(), r.offset, r.size) - m.bindBufferRange(ctx, out, cb, c, id, cmd) - } -} - -// bindBufferRange provides compatibiliy for glBindBufferRange by handling -// buffers that do not meet their minimum alignment on the target device. -// If a buffer is unaligned, then a new buffer is created and the data range is -// copied to this new buffer, and the new buffer is bound. -func (m *bufferCompat) bindBufferRange(ctx context.Context, out transform.Writer, cb CommandBuilder, c Contextʳ, id api.CmdID, cmd *GlBindBufferRange) { - misalignment := cmd.Offset() % GLintptr(m.uniformBufferAlignment) - - if cmd.Target() != GLenum_GL_UNIFORM_BUFFER || misalignment == 0 { - out.MutateAndWrite(ctx, id, cmd) - return - } - - dID := id.Derived() - - // We have a glBindBufferRange() taking a uniform buffer with an illegal - // offset alignment. - - orig := c.Objects().Buffers().Get(cmd.Buffer()) - if orig.IsNil() { - return // Don't know what buffer this is referring to. - } - - // We need a scratch buffer to copy the buffer data to a correct - // alignment. - scratchKey := scratchBufferKey{c, cmd.Target(), cmd.Index()} - - // Look for pre-existing buffer we can reuse. - buffer, ok := m.scratch[scratchKey] - if !ok { - buffer.id = m.newBuffer(ctx, dID, cb, out) - m.scratch[scratchKey] = buffer - } - - // Bind the scratch buffer to GL_COPY_WRITE_BUFFER - origCopyWriteBuffer := c.Bound().CopyWriteBuffer() - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_COPY_WRITE_BUFFER, buffer.id)) - - if buffer.size < cmd.Size() { - // Resize the scratch buffer - out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_COPY_WRITE_BUFFER, cmd.Size(), memory.Nullptr, GLenum_GL_DYNAMIC_COPY)) - buffer.size = cmd.Size() - m.scratch[scratchKey] = buffer - } - - // Copy out the unaligned data to the scratch buffer in the - // GL_COPY_WRITE_BUFFER binding. - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(cmd.Target(), cmd.Buffer())) - out.MutateAndWrite(ctx, dID, cb.GlCopyBufferSubData(cmd.Target(), GLenum_GL_COPY_WRITE_BUFFER, cmd.Offset(), 0, cmd.Size())) - - // We can now bind the range with correct alignment. - out.MutateAndWrite(ctx, id, cb.GlBindBufferRange(cmd.Target(), cmd.Index(), buffer.id, 0, cmd.Size())) - - // Restore old GL_COPY_WRITE_BUFFER binding. - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_COPY_WRITE_BUFFER, origCopyWriteBuffer.GetID())) - - m.unaligned[buffer.id] = orig -} - -func (m *bufferCompat) newBuffer(ctx context.Context, id api.CmdID, cb CommandBuilder, out transform.Writer) BufferId { - s := out.State() - bufID := m.nextBufferID - tmp := s.AllocDataOrPanic(ctx, bufID) - out.MutateAndWrite(ctx, id, cb.GlGenBuffers(1, tmp.Ptr()).AddWrite(tmp.Data())) - m.nextBufferID-- - return bufID -} diff --git a/gapis/api/gles/compat_client.go b/gapis/api/gles/compat_client.go deleted file mode 100644 index d6c74de4e0..0000000000 --- a/gapis/api/gles/compat_client.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "reflect" - - "github.com/google/gapid/core/math/interval" - "github.com/google/gapid/core/math/u64" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/resolve" -) - -var _ = []drawElements{ - &GlDrawElements{}, - &GlDrawRangeElements{}, -} - -type drawElements interface { - api.Cmd - indexLimits() (resolve.IndexRange, bool) - DrawMode() GLenum - IndicesCount() GLsizei - IndicesType() GLenum - Indices() IndicesPointer - SetIndices(IndicesPointer) -} - -func (d *GlDrawElements) indexLimits() (resolve.IndexRange, bool) { return resolve.IndexRange{}, false } - -func (d *GlDrawRangeElements) indexLimits() (resolve.IndexRange, bool) { - return resolve.IndexRange{ - First: uint32(d.Start()), - Count: uint32(d.End()-d.Start()) + 1, - }, true -} - -func cloneCmd(cmd api.Cmd, a arena.Arena) api.Cmd { - vc := reflect.ValueOf(cmd) - va := reflect.ValueOf(a) - return vc.MethodByName("Clone").Call([]reflect.Value{va})[0].Interface().(api.Cmd) -} - -// compatDrawElements performs compatibility logic to translate a draw elements -// call, moving all client-side pointers to buffers. -func compatDrawElements( - ctx context.Context, - t *tweaker, - clientVAs map[VertexAttributeArrayʳ]*GlVertexAttribPointer, - id api.CmdID, - cmd drawElements, - s *api.GlobalState, - out transform.Writer) { - - c := GetContext(s, cmd.Thread()) - e := externs{ctx: ctx, cmd: cmd, s: s} - - ib := c.Bound().VertexArray().ElementArrayBuffer() - clientIB := ib.IsNil() - clientVB := clientVAsBound(c, clientVAs) - - if clientIB { - // The indices for the glDrawElements call is in client memory. - // We need to move this into a temporary buffer. - - // Generate a new element array buffer and bind it. - bufID := t.glGenBuffer(ctx) - t.GlBindBuffer_ElementArrayBuffer(ctx, bufID) - - // By moving the draw call's observations earlier, populate the element array buffer. - size, base := DataTypeSize(cmd.IndicesType())*int(cmd.IndicesCount()), memory.Pointer(cmd.Indices()) - glBufferData := t.cb.GlBufferData(GLenum_GL_ELEMENT_ARRAY_BUFFER, GLsizeiptr(size), memory.Pointer(base), GLenum_GL_STATIC_DRAW) - glBufferData.extras = *cmd.Extras() - out.MutateAndWrite(ctx, t.dID, glBufferData) - - if clientVB { - // Some of the vertex arrays for the glDrawElements call is in - // client memory and we need to move this into temporary buffer(s). - // The indices are also in client memory, so we need to apply the - // command's reads now so that the indices can be read from the - // application pool. - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - indexSize := DataTypeSize(cmd.IndicesType()) - data := U8ᵖ(cmd.Indices()).Slice(0, uint64(indexSize*int(cmd.IndicesCount())), s.MemoryLayout) - limits, ok := cmd.indexLimits() - if !ok { - limits = e.calcIndexLimits(data, indexSize) - } - moveClientVBsToVAs(ctx, t, clientVAs, limits.First, limits.Count, id, cmd, s, c, out) - } - - cmd := cloneCmd(cmd, s.Arena).(drawElements) - cmd.SetIndices(0) - compatMultiviewDraw(ctx, id, cmd, out) - return - - } else if clientVB { // GL_ELEMENT_ARRAY_BUFFER is bound - // Some of the vertex arrays for the glDrawElements call is in - // client memory and we need to move this into temporary buffer(s). - // The indices are server-side, so can just be read from the internal - // pooled buffer. - data := ib.Data() - indexSize := DataTypeSize(cmd.IndicesType()) - count := data.Count() - start := u64.Min(cmd.Indices().Address(), count) // Clamp - end := u64.Min(start+uint64(indexSize)*uint64(cmd.IndicesCount()), count) // Clamp - limits, ok := cmd.indexLimits() - if !ok { - limits = e.calcIndexLimits(data.Slice(start, end), indexSize) - } - moveClientVBsToVAs(ctx, t, clientVAs, limits.First, limits.Count, id, cmd, s, c, out) - } - compatMultiviewDraw(ctx, id, cmd, out) -} - -// clientVAsBound returns true if there are any vertex attribute arrays enabled -// with pointers to client-side memory. -func clientVAsBound(c Contextʳ, clientVAs map[VertexAttributeArrayʳ]*GlVertexAttribPointer) bool { - for _, arr := range c.Bound().VertexArray().VertexAttributeArrays().All() { - if arr.Enabled() == GLboolean_GL_TRUE { - if _, ok := clientVAs[arr]; ok { - return true - } - } - } - return false -} - -// moveClientVBsToVAs is a compatability helper for transforming client-side -// vertex array data (which is not supported by glVertexAttribPointer in later -// versions of GL), into array-buffers. -func moveClientVBsToVAs( - ctx context.Context, - t *tweaker, - clientVAs map[VertexAttributeArrayʳ]*GlVertexAttribPointer, - first, count uint32, // vertex indices - id api.CmdID, - cmd api.Cmd, - s *api.GlobalState, - c Contextʳ, - out transform.Writer) { - - if count == 0 { - return - } - - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - rngs := interval.U64RangeList{} - // Gather together all the client-buffers in use by the vertex-attribs. - // Merge together all the memory intervals that these use. - va := c.Bound().VertexArray() - for _, arr := range va.VertexAttributeArrays().All() { - if arr.Enabled() == GLboolean_GL_TRUE { - vb := arr.Binding() - if cmd, ok := clientVAs[arr]; ok { - // TODO: We're currently ignoring the Offset and Stride fields of the VBB. - // TODO: We're currently ignoring the RelativeOffset field of the VA. - // TODO: Merge logic with ReadVertexArrays macro in vertex_arrays.api. - if vb.Divisor() != 0 { - panic("Instanced draw calls not currently supported by the compatibility layer") - } - stride, size := int(cmd.Stride()), DataTypeSize(cmd.Type())*int(cmd.Size()) - if stride == 0 { - stride = size - } - rng := memory.Range{ - Base: cmd.Data().Address(), // Always start from the 0'th vertex to simplify logic. - Size: uint64(int(first+count-1)*stride + size), - } - interval.Merge(&rngs, rng.Span(), true) - } - } - } - - // Create an array-buffer for each chunk of overlapping client-side buffers in - // use. These are populated with data below. - ids := make([]BufferId, len(rngs)) - for i := range rngs { - ids[i] = t.glGenBuffer(ctx) - } - - // Apply the memory observations that were made by the draw call now. - // We need to do this as the glBufferData calls below will require the data. - dID := id.Derived() - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - cmd.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - return nil - })) - - // Note: be careful of overwriting the observations made above, before the - // calls to glBufferData below. - - // Fill the array-buffers with the observed memory data. - for i, rng := range rngs { - base := memory.BytePtr(rng.First) - size := GLsizeiptr(rng.Count) - t.GlBindBuffer_ArrayBuffer(ctx, ids[i]) - out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_ARRAY_BUFFER, size, base, GLenum_GL_STATIC_DRAW)) - } - - // Redirect all the vertex attrib arrays to point to the array-buffer data. - for _, l := range va.VertexAttributeArrays().Keys() { - arr := va.VertexAttributeArrays().Get(l) - if arr.Enabled() == GLboolean_GL_TRUE { - if glVAP, ok := clientVAs[arr]; ok { - glVAP := glVAP.clone(s.Arena) - i := interval.IndexOf(&rngs, glVAP.Data().Address()) - t.GlBindBuffer_ArrayBuffer(ctx, ids[i]) - // The glVertexAttribPointer call may have come from a different thread - // and there's no guarantees that the thread still has the context bound. - // Use the draw call's thread instead. - glVAP.SetThread(cmd.Thread()) - glVAP.SetData(glVAP.Data() - VertexPointer(rngs[i].First)) // Offset - out.MutateAndWrite(ctx, dID, glVAP) - } - } - } -} diff --git a/gapis/api/gles/compat_test.go b/gapis/api/gles/compat_test.go deleted file mode 100644 index cf89971fae..0000000000 --- a/gapis/api/gles/compat_test.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles_test - -import ( - "context" - "fmt" - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/memory" -) - -var compat = gles.VisibleForTestingCompat - -const OpenGL_3_0 = "3.0" - -var p = memory.BytePtr - -func newState(ctx context.Context) *api.GlobalState { - s, err := capture.NewState(ctx) - if err != nil { - panic(err) - } - return s -} - -func TestGlVertexAttribPointerCompatTest(t *testing.T) { - ctx := log.Testing(t) - ctx = database.Put(ctx, database.NewInMemory(ctx)) - - a := arena.New() - defer a.Dispose() - - h := &capture.Header{ABI: device.AndroidARMv7a} - ml := h.ABI.MemoryLayout - cap, err := capture.NewGraphicsCapture(ctx, a, "test", h, nil, []api.Cmd{}) - if err != nil { - panic(err) - } - - capturePath, err := cap.Path(ctx) - if err != nil { - panic(err) - } - - ctx = capture.Put(ctx, capturePath) - ctx = gles.PutUnusedIDMap(ctx) - - dev := &device.Instance{Configuration: &device.Configuration{ - Drivers: &device.Drivers{ - Opengl: &device.OpenGLDriver{Version: OpenGL_3_0}, - }, - }} - - onCompatError := func(ctx context.Context, id api.CmdID, cmd api.Cmd, err error) { - log.E(ctx, "%v %v: %v", id, cmd, err) - } - - ct, err := compat(ctx, dev, onCompatError) - if err != nil { - log.E(ctx, "Error creating compatability transform: %v", err) - return - } - - positions := []float32{-1., -1., 1., -1., -1., 1., 1., 1.} - indices := []uint16{0, 1, 2, 1, 2, 3} - r := &transform.Recorder{S: newState(ctx)} - ctxHandle, displayHandle, surfaceHandle := p(1), p(2), p(3) - cb := gles.CommandBuilder{Thread: 0, Arena: a} - eglMakeCurrent := cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle, 0) - eglMakeCurrent.Extras().Add(gles.NewStaticContextStateForTest(a), gles.NewDynamicContextStateForTest(a, 64, 64, true)) - - cmds := []api.Cmd{ - cb.EglCreateContext(displayHandle, memory.Nullptr, memory.Nullptr, memory.Nullptr, ctxHandle), - eglMakeCurrent, - } - - vertId := gles.ShaderId(1) - fragId := gles.ShaderId(2) - progId := gles.ProgramId(3) - attIdx := gles.AttributeLocation(0) - vertSrc := "void main() {}" - fragSrc := vertSrc - - cmds = append(cmds, gles.BuildProgram(ctx, r.S, cb, vertId, fragId, progId, vertSrc, fragSrc)...) - - resources := gles.MakeActiveProgramResourcesʳ(a) - attribute := gles.MakeProgramResourceʳ(a) - attribute.Locations().Add(0, gles.GLint(attIdx)) - resources.ProgramInputs().Add(uint32(attIdx), attribute) - lpe := gles.MakeLinkProgramExtra(a) - lpe.SetLinkStatus(gles.GLboolean_GL_TRUE) - lpe.SetActiveResources(resources) - cmds = append(cmds, api.WithExtras(cb.GlLinkProgram(progId), lpe)) - - cmds = append(cmds, []api.Cmd{ - cb.GlUseProgram(progId), - cb.GlEnableVertexAttribArray(attIdx), - cb.GlVertexAttribPointer(attIdx, 2, gles.GLenum_GL_FLOAT, gles.GLboolean(0), 8, p(0x100000)). - AddRead(memory.Store(ctx, ml, p(0x100000), positions)), - cb.GlDrawElements(gles.GLenum_GL_TRIANGLES, gles.GLsizei(len(indices)), gles.GLenum_GL_UNSIGNED_SHORT, p(0x200000)). - AddRead(memory.Store(ctx, ml, p(0x200000), indices)), - }...) - - api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - ct.Transform(ctx, api.CmdNoID, cmd, r) - return nil - }) - - // Find glDrawElements and check it is using a buffer instead of client's memory now - s := newState(ctx) - var found bool - err = api.ForeachCmd(ctx, r.Cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - if err := cmd.Mutate(ctx, id, s, nil, nil); err != nil { - return fmt.Errorf("Fail to mutate command %v: %v", cmd, err) - } - - if _, ok := cmd.(*gles.GlDrawElements); ok { - ctx := gles.GetContext(s, cmd.Thread()) - vao := ctx.Bound().VertexArray() - array := vao.VertexAttributeArrays().Get(0) - binding := array.Binding() - if !binding.Buffer().IsNil() && array.Pointer() == 0 { - found = true - return api.Break // Success - } else { - t.Error("glDrawElements does not source vertex data from buffer.") - return api.Break - } - } - return nil - }) - assert.For(ctx, "err").ThatError(err).Succeeded() - - if !found { - t.Error("glDrawElements command not found.") - } -} diff --git a/gapis/api/gles/context.go b/gapis/api/gles/context.go deleted file mode 100644 index 76c9b371da..0000000000 --- a/gapis/api/gles/context.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "fmt" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/gapis/api" -) - -// Name returns the display-name of the context. -func (c Contextʳ) Name() string { - name := fmt.Sprintf("OpenGL ES context %d", int(c.Identifier())) - if name := c.Other().ThreadName(); name != "" { - name += fmt.Sprintf(" - \"%s\"", name) - } - return name -} - -// ID returns the context's unique identifier. -func (c Contextʳ) ID() api.ContextID { - if c.IsNil() { - return api.ContextID{} - } - return api.ContextID(id.OfString(fmt.Sprintf("GLES Context %v", c.Identifier()))) -} - -// API returns the GLES API. -func (c Contextʳ) API() api.API { - return API{} -} diff --git a/gapis/api/gles/custom_replay.go b/gapis/api/gles/custom_replay.go deleted file mode 100644 index 3429ce4f78..0000000000 --- a/gapis/api/gles/custom_replay.go +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "strings" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/replay/value" -) - -// objectKey is a map and object identifier pair used for a remapping key. -// Ideally we'd just use the object or object pointer as the key, but we have -// commands that want to remap the identifier before the state object is -// created. -// TODO: It maybe possible to rework the state-mutator and/or APIs to achieve -// this. -type objectKey struct { - mapPtr interface{} - mapKey interface{} -} - -func (i BufferId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Buffers(), i}, true - } - return -} - -func (i FramebufferId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Framebuffers(), i}, true - } - return -} - -func (i RenderbufferId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Renderbuffers(), i}, true - } - return -} - -func (i ProgramId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Programs(), i}, true - } - return -} - -func (i ShaderId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Shaders(), i}, true - } - return -} - -func (i TextureId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Textures(), i}, true - } - return -} - -func (i UniformBlockIndex) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - program := ctx.Bound().Program().GetID() - switch cmd := cmd.(type) { - case *GlGetActiveUniformBlockName: - program = cmd.Program() - case *GlGetActiveUniformBlockiv: - program = cmd.Program() - case *GlGetUniformBlockIndex: - program = cmd.Program() - case *GlUniformBlockBinding: - program = cmd.Program() - } - return struct { - p Programʳ - i UniformBlockIndex - }{ctx.Objects().Programs().Get(program), i}, true -} - -func (i VertexArrayId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().VertexArrays(), i}, true - } - return -} - -func (i QueryId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Queries(), i}, true - } - return -} - -func (i GLsync) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && !i.IsNullptr() { - key, remap = objectKey{ctx.Objects().SyncObjects(), i}, true - } - return -} - -func (i EGLImageKHR) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - if !i.IsNullptr() { - key, remap = objectKey{GetState(s).EGLImages(), i}, true - } - return -} - -func (i GLsync) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - return value.AbsolutePointer(i) -} - -func (i SamplerId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Samplers(), i}, true - } - return -} - -func (i PipelineId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().Pipelines(), i}, true - } - return -} - -func (i TransformFeedbackId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && i != 0 { - key, remap = objectKey{ctx.Objects().TransformFeedbacks(), i}, true - } - return -} - -func (i UniformLocation) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - program := ctx.Bound().Program().GetID() - switch cmd := cmd.(type) { - case *GlGetActiveUniform: - program = cmd.Program() - case *GlGetUniformLocation: - program = cmd.Program() - } - return struct { - p Programʳ - l UniformLocation - }{ctx.Objects().Programs().Get(program), i}, true -} - -func (i SrcImageId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - c, ok := cmd.(interface { - api.Cmd - SrcName() SrcImageId - SrcTarget() GLenum - }) - if !ok { - panic(fmt.Errorf("Remap of SrcImageId for unhandled command: %v", cmd)) - } - return remapImageID(c, s, GLuint(c.SrcName()), c.SrcTarget()) -} - -func (i DstImageId) remap(cmd api.Cmd, s *api.GlobalState) (key interface{}, remap bool) { - c, ok := cmd.(interface { - api.Cmd - DstName() DstImageId - DstTarget() GLenum - }) - if !ok { - panic(fmt.Errorf("Remap of DstImageId for unhandled command: %v", cmd)) - } - return remapImageID(c, s, GLuint(c.DstName()), c.DstTarget()) -} - -func remapImageID(cmd api.Cmd, s *api.GlobalState, name GLuint, target GLenum) (key interface{}, remap bool) { - ctx := GetContext(s, cmd.Thread()) - if !ctx.IsNil() && name != 0 { - if target == GLenum_GL_RENDERBUFFER { - return RenderbufferId(name).remap(cmd, s) - } - return TextureId(name).remap(cmd, s) - } - return -} - -func (i IndicesPointer) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - c := GetContext(s, cmd.Thread()) - if !c.Bound().VertexArray().ElementArrayBuffer().IsNil() { - return value.AbsolutePointer(i) - } - return value.ObservedPointer(i) -} - -func (i VertexPointer) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - c := GetContext(s, cmd.Thread()) - if !c.Bound().ArrayBuffer().IsNil() { - return value.AbsolutePointer(i) - } - return value.ObservedPointer(i) -} - -func (i TexturePointer) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - if i == 0 || !GetContext(s, cmd.Thread()).Bound().PixelUnpackBuffer().IsNil() { - return value.AbsolutePointer(i) - } - return value.ObservedPointer(i) -} - -func (i BufferDataPointer) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - if i == 0 { - return value.AbsolutePointer(i) - } - return value.ObservedPointer(i) -} - -func (i EGLImageKHR) value(b *builder.Builder, cmd api.Cmd, s *api.GlobalState) value.Value { - return value.AbsolutePointer(i) -} - -func (ω *EglCreateContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).EGLContexts().Get(ω.Result()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *EglMakeCurrent) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - prevContext := GetState(s).Contexts().Get(ω.Thread()) - existed := GetState(s).EGLContexts().Contains(ω.Context()) - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - if ω.Context() == 0 { - if prevContext.IsNil() { - return nil - } - ctxID := uint32(prevContext.Identifier()) - return cb.ReplayUnbindRenderer(ctxID).Mutate(ctx, id, s, b, nil) - } - ctxID := uint32(GetState(s).EGLContexts().Get(ω.Context()).Identifier()) - if !existed { - // The eglCreateContext call was missing, so fake it (can happen on Samsung). - if err := cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil); err != nil { - return err - } - } - if cs := FindDynamicContextState(s.Arena, ω.Extras()); !cs.IsNil() { - cmd := cb.ReplayChangeBackbuffer( - ctxID, - cs.BackbufferWidth(), - cs.BackbufferHeight(), - cs.BackbufferColorFmt(), - cs.BackbufferDepthFmt(), - cs.BackbufferStencilFmt(), - ) - if err := cmd.Mutate(ctx, id, s, b, nil); err != nil { - return err - } - } - if err := cb.ReplayBindRenderer(ctxID, false).Mutate(ctx, id, s, b, nil); err != nil { - return err - } - return nil -} - -func (ω *EglCreateImageKHR) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - - if ω.Target() != EGLenum_EGL_GL_TEXTURE_2D { - return fmt.Errorf("Cannot create a non texture backed EGLImage: %v", ω) - } - - ctxID := uint32(GetState(s).EGLContexts().Get(ω.Context()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateExternalImage(ctxID, TextureId(ω.Buffer().Address()), ω.Result()).Mutate(ctx, id, s, b, nil) -} - -func (ω *EglSwapBuffers) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - // Get context ID from current Thread - context := GetState(s).Contexts().Get(ω.Thread()) - if context.IsNil() { - return fmt.Errorf("No EGL context in thread calling eglSwapBuffers, thread: %v", ω.Thread()) - } - ctxID := uint32(context.Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayFrameDelimiter(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *WglCreateContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).WGLContexts().Get(ω.Result()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *WglCreateContextAttribsARB) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).WGLContexts().Get(ω.Result()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *WglMakeCurrent) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - if ω.Hglrc() == 0 { - return nil - } - ctxID := uint32(GetState(s).WGLContexts().Get(ω.Hglrc()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayBindRenderer(ctxID, false).Mutate(ctx, id, s, b, nil) -} - -func (ω *CGLCreateContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).CGLContexts().Get(ω.Ctx().MustRead(ctx, ω, s, b)).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *CGLSetCurrentContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - if ω.Ctx() == 0 { - return nil - } - ctxID := uint32(GetState(s).CGLContexts().Get(ω.Ctx()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayBindRenderer(ctxID, false).Mutate(ctx, id, s, b, nil) -} - -func (ω *GlXCreateContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).GLXContexts().Get(ω.Result()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *GlXCreateNewContext) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - ctxID := uint32(GetState(s).GLXContexts().Get(ω.Result()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayCreateRenderer(ctxID).Mutate(ctx, id, s, b, nil) -} - -func (ω *GlXMakeContextCurrent) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - err := ω.mutate(ctx, id, s, nil, w) - if b == nil || err != nil { - return err - } - if ω.Ctx() == 0 { - return nil - } - ctxID := uint32(GetState(s).GLXContexts().Get(ω.Ctx()).Identifier()) - cb := CommandBuilder{Thread: ω.Thread(), Arena: s.Arena} - return cb.ReplayBindRenderer(ctxID, false).Mutate(ctx, id, s, b, nil) -} - -// Force all attributes to use the capture-observed locations during replay. -func bindAttribLocations(ctx context.Context, cmd api.Cmd, id api.CmdID, s *api.GlobalState, b *builder.Builder, pid ProgramId) error { - pi := FindLinkProgramExtra(s.Arena, cmd.Extras()) - if !pi.IsNil() && b != nil && !pi.ActiveResources().IsNil() { - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - for _, attr := range pi.ActiveResources().ProgramInputs().All() { - if int32(attr.Locations().Get(0)) != -1 { - tmp := s.AllocDataOrPanic(ctx, attr.Name()) - defer tmp.Free() - cmd := cb.GlBindAttribLocation(pid, AttributeLocation(attr.Locations().Get(0)), tmp.Ptr()). - AddRead(tmp.Data()) - if strings.HasPrefix(attr.Name(), "gl_") { - // Active built-in mush have location of -1 - log.E(ctx, "Can not set location for built-in attribute: %v", cmd) - continue - } - if err := cmd.Mutate(ctx, id, s, b, nil); err != nil { - return err - } - } - } - } - return nil -} - -// Remap uniform block indices -func bindUniformBlocks(ctx context.Context, cmd api.Cmd, id api.CmdID, s *api.GlobalState, b *builder.Builder, pid ProgramId) error { - pi := FindLinkProgramExtra(s.Arena, cmd.Extras()) - if !pi.IsNil() && b != nil && !pi.ActiveResources().IsNil() { - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - for i, ub := range pi.ActiveResources().UniformBlocks().All() { - // Query replay-time uniform block index so that the remapping is established - tmp := s.AllocDataOrPanic(ctx, ub.Name()) - defer tmp.Free() - cmd := cb.GlGetUniformBlockIndex(pid, tmp.Ptr(), UniformBlockIndex(i)). - AddRead(tmp.Data()) - if err := cmd.Mutate(ctx, id, s, b, nil); err != nil { - return err - } - } - } - return nil -} - -func (cmd *GlProgramBinaryOES) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - if err := bindAttribLocations(ctx, cmd, id, s, b, cmd.Program()); err != nil { - return err - } - if err := cmd.mutate(ctx, id, s, b, w); err != nil { - return err - } - return bindUniformBlocks(ctx, cmd, id, s, b, cmd.Program()) -} - -func (cmd *GlLinkProgram) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - if err := bindAttribLocations(ctx, cmd, id, s, b, cmd.Program()); err != nil { - return err - } - if err := cmd.mutate(ctx, id, s, b, w); err != nil { - return err - } - return bindUniformBlocks(ctx, cmd, id, s, b, cmd.Program()) -} - -func (cmd *GlProgramBinary) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, b *builder.Builder, w api.StateWatcher) error { - if err := bindAttribLocations(ctx, cmd, id, s, b, cmd.Program()); err != nil { - return err - } - if err := cmd.mutate(ctx, id, s, b, w); err != nil { - return err - } - return bindUniformBlocks(ctx, cmd, id, s, b, cmd.Program()) -} diff --git a/gapis/api/gles/datatypes.go b/gapis/api/gles/datatypes.go deleted file mode 100644 index 8aaabdd726..0000000000 --- a/gapis/api/gles/datatypes.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import "fmt" - -// DataTypeSize returns the size in bytes of the the specified data type. -func DataTypeSize(t GLenum) int { - switch t { - case GLenum_GL_BYTE, - GLenum_GL_UNSIGNED_BYTE: - return 1 - case GLenum_GL_SHORT, - GLenum_GL_UNSIGNED_SHORT, - GLenum_GL_HALF_FLOAT_ARB, - GLenum_GL_HALF_FLOAT_OES: - return 2 - case GLenum_GL_FIXED, - GLenum_GL_FLOAT, - GLenum_GL_INT, - GLenum_GL_UNSIGNED_INT, - GLenum_GL_UNSIGNED_INT_2_10_10_10_REV: - return 4 - default: - panic(fmt.Errorf("Unknown data type %v", t)) - } -} diff --git a/gapis/api/gles/dead_code_elimination_test.go b/gapis/api/gles/dead_code_elimination_test.go deleted file mode 100644 index 1cde27834b..0000000000 --- a/gapis/api/gles/dead_code_elimination_test.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles_test - -import ( - "context" - "fmt" - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/resolve/dependencygraph" -) - -func TestDeadCommandRemoval(t *testing.T) { - ctx := log.Testing(t) - ctx = bind.PutRegistry(ctx, bind.NewRegistry()) - ctx = database.Put(ctx, database.NewInMemory(ctx)) - - a := arena.New() - defer a.Dispose() - - // Keep the given command alive in the optimization. - isLive := map[api.Cmd]bool{} - live := func(cmd api.Cmd) api.Cmd { isLive[cmd] = true; return cmd } - - // Expect the command to be removed by the optimization. - isDead := map[api.Cmd]bool{} - dead := func(cmd api.Cmd) api.Cmd { isDead[cmd] = true; return cmd } - - programUniformsA := gles.MakeProgramResourceʳ(a) - programUniformsA.SetName("uniforms") - programUniformsA.SetType(gles.GLenum_GL_FLOAT_VEC4) - programUniformsA.SetArraySize(10) - programUniformsA.SetLocations(gles.NewU32ːGLintᵐ(a). - Add(0, 0).Add(1, 1).Add(2, 2).Add(3, 3).Add(4, 4). - Add(5, 5).Add(6, 6).Add(7, 7).Add(8, 8).Add(9, 9)) - programResourcesA := gles.MakeActiveProgramResourcesʳ(a) - programResourcesA.SetDefaultUniformBlock(gles.NewUniformIndexːProgramResourceʳᵐ(a).Add(0, programUniformsA)) - programInfoA := gles.MakeLinkProgramExtra(a) - programInfoA.SetLinkStatus(gles.GLboolean_GL_TRUE) - programInfoA.SetActiveResources(programResourcesA) - - programSamplerB := gles.MakeProgramResourceʳ(a) - programSamplerB.SetName("sampler") - programSamplerB.SetType(gles.GLenum_GL_SAMPLER_CUBE) - programSamplerB.SetLocations(gles.NewU32ːGLintᵐ(a).Add(0, 0)) - programSamplerB.SetArraySize(1) - programResourcesB := gles.MakeActiveProgramResourcesʳ(a) - programResourcesB.SetDefaultUniformBlock(gles.NewUniformIndexːProgramResourceʳᵐ(a).Add(0, programSamplerB)) - programInfoB := gles.MakeLinkProgramExtra(a) - programInfoB.SetLinkStatus(gles.GLboolean_GL_TRUE) - programInfoB.SetActiveResources(programResourcesB) - - ctxHandle1 := memory.BytePtr(1) - ctxHandle2 := memory.BytePtr(2) - displayHandle := memory.BytePtr(3) - surfaceHandle := memory.BytePtr(4) - cb := gles.CommandBuilder{Thread: 0, Arena: a} - prologue := []api.Cmd{ - cb.EglCreateContext(displayHandle, surfaceHandle, surfaceHandle, memory.Nullptr, ctxHandle1), - api.WithExtras( - cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle1, 0), - gles.NewStaticContextStateForTest(a), gles.NewDynamicContextStateForTest(a, 64, 64, false)), - cb.GlCreateProgram(1), - cb.GlCreateProgram(2), - cb.GlCreateProgram(3), - } - allBuffers := gles.GLbitfield_GL_COLOR_BUFFER_BIT | gles.GLbitfield_GL_DEPTH_BUFFER_BIT | gles.GLbitfield_GL_STENCIL_BUFFER_BIT - tests := map[string][]api.Cmd{ - "Draw calls up to the requested point are preserved": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 1, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 2, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 3, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 4, 0)), - }, - "No request in frame kills draw calls": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - dead(cb.GlClear(allBuffers)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 1, 0)), - dead(cb.EglSwapBuffers(displayHandle, surfaceHandle, gles.EGLBoolean(1))), - cb.GlClear(allBuffers), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Multiple requests": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Simple overwrite": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - dead(cb.GlUniform4fv(0, 1, memory.Nullptr)), - cb.GlUniform4fv(1, 1, memory.Nullptr), - cb.GlUniform4fv(0, 1, memory.Nullptr), - dead(cb.GlVertexAttribPointer(0, 4, gles.GLenum_GL_FLOAT, gles.GLboolean_GL_FALSE, 0, memory.Nullptr)), - cb.GlVertexAttribPointer(1, 4, gles.GLenum_GL_FLOAT, gles.GLboolean_GL_FALSE, 0, memory.Nullptr), - cb.GlVertexAttribPointer(0, 4, gles.GLenum_GL_FLOAT, gles.GLboolean_GL_FALSE, 0, memory.Nullptr), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Overwrites should be tracked per program": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - dead(cb.GlUseProgram(1)), - api.WithExtras(cb.GlLinkProgram(2), programInfoA), - dead(cb.GlUseProgram(1)), - dead(cb.GlUniform4fv(0, 1, memory.Nullptr)), - cb.GlUseProgram(2), - cb.GlUniform4fv(0, 1, memory.Nullptr), - cb.GlUseProgram(1), - cb.GlUniform4fv(0, 1, memory.Nullptr), - cb.GlUseProgram(1), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - cb.GlUseProgram(2), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Arrays should not interact with scalars": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - cb.GlUniform4fv(0, 10, memory.Nullptr), - cb.GlUniform4fv(0, 1, memory.Nullptr), // Unaffected - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Arrays should not interact with scalars (2)": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - cb.GlUniform4fv(0, 1, memory.Nullptr), - cb.GlUniform4fv(0, 10, memory.Nullptr), // Unaffected - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Re-linking a program drops uniform settings": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - dead(cb.GlUniform4fv(0, 1, memory.Nullptr)), - dead(cb.GlUniform1f(0, 3.14)), - cb.GlLinkProgram(1), - cb.GlUniform4fv(0, 1, memory.Nullptr), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Multiple contexts": { - // Draw in context 1 - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - dead(cb.GlUniform4fv(0, 1, memory.Nullptr)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - cb.GlClear(allBuffers), - cb.GlUniform4fv(0, 1, memory.Nullptr), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - // Draw in context 2 - cb.EglCreateContext(displayHandle, memory.Nullptr, memory.Nullptr, memory.Nullptr, ctxHandle2), - api.WithExtras( - cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle2, 0), gles.NewStaticContextStateForTest(a), gles.NewDynamicContextStateForTest(a, 64, 64, false)), - cb.GlCreateProgram(1), - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - cb.GlUseProgram(1), - dead(cb.GlUniform4fv(0, 1, memory.Nullptr)), - dead(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - cb.GlClear(allBuffers), - cb.GlUniform4fv(0, 1, memory.Nullptr), - cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0), - // Request from both contexts - cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle1, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle2, 0), - live(cb.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 0)), - }, - "Clear layers and read texture": { - api.WithExtras(cb.GlLinkProgram(1), programInfoA), - api.WithExtras(cb.GlLinkProgram(3), programInfoB), - cb.GlUseProgram(1), - - cb.GlActiveTexture(gles.GLenum_GL_TEXTURE3), - cb.GlBindTexture(gles.GLenum_GL_TEXTURE_CUBE_MAP, 4), - cb.GlTexStorage2D(gles.GLenum_GL_TEXTURE_CUBE_MAP, 10, gles.GLenum_GL_RGBA8, 512, 512), - cb.GlActiveTexture(gles.GLenum_GL_TEXTURE0), - - cb.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, 1), - cb.GlFramebufferTexture2D(gles.GLenum_GL_FRAMEBUFFER, gles.GLenum_GL_COLOR_ATTACHMENT0, gles.GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 4, 0), - cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - cb.GlDrawArrays(gles.GLenum_GL_POINTS, 0, 1), - - cb.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, 1), - cb.GlFramebufferTexture2D(gles.GLenum_GL_FRAMEBUFFER, gles.GLenum_GL_COLOR_ATTACHMENT0, gles.GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 4, 1), - cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - cb.GlDrawArrays(gles.GLenum_GL_POINTS, 0, 1), - - cb.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, 1), - cb.GlFramebufferTexture2D(gles.GLenum_GL_FRAMEBUFFER, gles.GLenum_GL_COLOR_ATTACHMENT0, gles.GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 4, 2), - cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - cb.GlDrawArrays(gles.GLenum_GL_POINTS, 0, 1), - - cb.GlUseProgram(3), - cb.GlUniform1i(0, 3), - cb.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, 0), - cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - live(cb.GlDrawArrays(gles.GLenum_GL_POINTS, 0, 1)), - }, - "Generate mipmaps": { - dead(api.WithExtras(cb.GlLinkProgram(1), programInfoA)), - dead(cb.GlUseProgram(1)), - cb.GlActiveTexture(gles.GLenum_GL_TEXTURE0), - cb.GlBindTexture(gles.GLenum_GL_TEXTURE_2D, 10), - cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 0, gles.GLint(gles.GLenum_GL_RGB), 64, 64, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr), - dead(cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 1, gles.GLint(gles.GLenum_GL_RGB), 32, 32, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr)), - dead(cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 2, gles.GLint(gles.GLenum_GL_RGB), 16, 16, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr)), - dead(cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 3, gles.GLint(gles.GLenum_GL_RGB), 8, 8, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr)), - dead(cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 4, gles.GLint(gles.GLenum_GL_RGB), 4, 4, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr)), - dead(cb.GlTexImage2D(gles.GLenum_GL_TEXTURE_2D, 5, gles.GLint(gles.GLenum_GL_RGB), 2, 2, 0, gles.GLenum_GL_RGB, gles.GLenum_GL_UNSIGNED_SHORT_5_6_5, memory.Nullptr)), - live(cb.GlGenerateMipmap(gles.GLenum_GL_TEXTURE_2D)), - }, - } - - for name, testCmds := range tests { - cmds := append(prologue, testCmds...) - - h := &capture.Header{ABI: device.WindowsX86_64} - cap, err := capture.NewGraphicsCapture(ctx, a, name, h, nil, cmds) - if err != nil { - panic(err) - } - capturePath, err := cap.Path(ctx) - if err != nil { - panic(err) - } - ctx = capture.Put(ctx, capturePath) - - // First verify the commands mutate without errors - uc, _ := capture.Resolve(ctx) - c := uc.(*capture.GraphicsCapture) - s := c.NewState(ctx) - err = api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - if err := cmd.Mutate(ctx, id, s, nil, nil); err != nil { - return fmt.Errorf("%v: %v: %v", id, cmd, err) - } - return nil - }) - if !assert.For(ctx, "Test '%v' errors", name).ThatError(err).Succeeded() { - continue - } - - dependencyGraph, err := dependencygraph.GetDependencyGraph(ctx, nil) - if err != nil { - t.Fatalf("%v", err) - } - dce := dependencygraph.NewDeadCodeElimination(ctx, dependencyGraph) - - expectedCmds := []api.Cmd{} - api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - if isLive[cmd] { - dce.Request(id) - } - if !isDead[cmd] { - expectedCmds = append(expectedCmds, cmd) - } - return nil - }) - - r := &transform.Recorder{} - dce.Flush(ctx, r) - assert.For(ctx, "Test '%v'", name).ThatSlice(r.Cmds).Equals(expectedCmds) - } -} diff --git a/gapis/api/gles/dependency_graph_behaviour_provider.go b/gapis/api/gles/dependency_graph_behaviour_provider.go deleted file mode 100644 index 1a1b81274d..0000000000 --- a/gapis/api/gles/dependency_graph_behaviour_provider.go +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/resolve/dependencygraph" -) - -type shaderProgramKeyKind int - -const ( - everything shaderProgramKeyKind = iota - uniforms - binding - linkstate - compilestate - source -) - -type programKey struct { - program Programʳ - kind shaderProgramKeyKind -} - -func (k programKey) Parent() dependencygraph.StateKey { - switch k.kind { - case uniforms, binding, linkstate: - return programKey{k.program, everything} - } - return nil -} - -type shaderKey struct { - shader Shaderʳ - kind shaderProgramKeyKind -} - -func (k shaderKey) Parent() dependencygraph.StateKey { - switch k.kind { - case compilestate, source: - return shaderKey{k.shader, everything} - } - return nil -} - -type uniformKey struct { - program Programʳ - location UniformLocation - count GLsizei -} - -func (k uniformKey) Parent() dependencygraph.StateKey { return programKey{k.program, uniforms} } - -type vertexAttribKey struct { - vertexArray VertexArrayʳ - location AttributeLocation -} - -func (k vertexAttribKey) Parent() dependencygraph.StateKey { - return vertexAttribGroupKey{k.vertexArray} -} - -type vertexAttribGroupKey struct { - vertexArray VertexArrayʳ -} - -func (k vertexAttribGroupKey) Parent() dependencygraph.StateKey { return nil } - -type renderbufferDataKey struct { - renderbuffer Renderbufferʳ -} - -func (k renderbufferDataKey) Parent() dependencygraph.StateKey { return nil } - -type renderbufferSubDataKey struct { - renderbuffer Renderbufferʳ - regionX, regionY GLint - regionW, regionH GLsizei -} - -func (k renderbufferSubDataKey) Parent() dependencygraph.StateKey { - return renderbufferDataKey{k.renderbuffer} -} - -type textureDataKey struct { - texture Textureʳ - id TextureId // For debugging, as 0 is not unique identifier. - level GLint - layer GLint -} - -func (k textureDataKey) Parent() dependencygraph.StateKey { - return textureDataGroupKey{k.texture, k.id} -} - -// represents data for all levels and layers in texture -type textureDataGroupKey struct { - texture Textureʳ - id TextureId // For debugging, as 0 is not unique identifier. -} - -func (k textureDataGroupKey) Parent() dependencygraph.StateKey { return nil } - -type textureSizeKey struct { - texture Textureʳ - id TextureId // For debugging, as 0 is not unique identifier. - layer GLint - level GLint -} - -func (k textureSizeKey) Parent() dependencygraph.StateKey { return nil } - -type eglImageDataKey struct { - image EGLImageʳ -} - -func (k eglImageDataKey) Parent() dependencygraph.StateKey { return nil } - -type eglImageSizeKey struct { - image EGLImageʳ -} - -func (k eglImageSizeKey) Parent() dependencygraph.StateKey { return nil } - -type GlesDependencyGraphBehaviourProvider struct{} - -func newGlesDependencyGraphBehaviourProvider() *GlesDependencyGraphBehaviourProvider { - return &GlesDependencyGraphBehaviourProvider{} -} - -// GetBehaviourForCommand returns state reads/writes that the given command -// performs. -// -// Writes: Write dependencies keep commands alive. Each command must correctly -// report all its writes or it must set the keep-alive flag. If a write is -// missing then the liveness analysis will remove the command since it seems -// unneeded. -// It is fine to omit related/overloaded commands that write to the same state -// as long as they are marked as keep-alive. -// -// Reads: For each state write, all commands that could possibly read it must be -// implemented. This makes it more difficult to do only partial implementations. -// It is fine to overestimate reads, or to read parent state (i.e. superset). -// -func (*GlesDependencyGraphBehaviourProvider) GetBehaviourForCommand( - ctx context.Context, s *api.GlobalState, id api.CmdID, cmd api.Cmd, g *dependencygraph.DependencyGraph) dependencygraph.CmdBehaviour { - b := dependencygraph.CmdBehaviour{} - c := GetContext(s, cmd.Thread()) - if err := cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */); err != nil { - log.W(ctx, "Command %v %v: %v", id, cmd, err) - return dependencygraph.CmdBehaviour{Aborted: true} - } - if !c.IsNil() && c.Other().Initialized() { - _, isEglSwapBuffers := cmd.(*EglSwapBuffers) - // TODO: We should also be considering eglSwapBuffersWithDamageKHR here - // too, but this is nearly exculsively used by the Android framework, - // which also loves to do partial framebuffer updates. Unfortunately - // we do not currently know whether the framebuffer is invalidated - // between calls to eglSwapBuffersWithDamageKHR as the OS now uses - // the EGL_EXT_buffer_age extension, which we do not track. For now, - // assume that eglSwapBuffersWithDamageKHR calls are coming from the - // framework, and that the framebuffer is reused between calls. - // BUG: https://github.com/google/gapid/issues/846. - if isEglSwapBuffers { - // Get default renderbuffers - fb := c.Objects().Framebuffers().Get(0) - color := fb.ColorAttachments().Get(0).Renderbuffer() - depth := fb.DepthAttachment().Renderbuffer() - stencil := fb.StencilAttachment().Renderbuffer() - if !c.Other().PreserveBuffersOnSwap() { - b.Write(g, renderbufferDataKey{color}) - } - b.Write(g, renderbufferDataKey{depth}) - b.Write(g, renderbufferDataKey{stencil}) - } else if cmd.CmdFlags(ctx, id, s).IsDrawCall() { - switch { - case !c.Bound().Program().IsNil(): - b.Read(g, programKey{c.Bound().Program(), everything}) - case !c.Bound().Pipeline().IsNil(): - p := c.Bound().Pipeline() - b.Read(g, programKey{p.VertexShader(), everything}) - b.Read(g, programKey{p.TessControlShader(), everything}) - b.Read(g, programKey{p.TessEvaluationShader(), everything}) - b.Read(g, programKey{p.GeometryShader(), everything}) - b.Read(g, programKey{p.FragmentShader(), everything}) - b.Read(g, programKey{p.ComputeShader(), everything}) - } - b.Read(g, vertexAttribGroupKey{c.Bound().VertexArray()}) - for _, stateKey := range getAllUsedTextureData(ctx, cmd, id, s, c) { - b.Read(g, stateKey) - } - c.Bound().DrawFramebuffer().ForEachAttachment(func(name GLenum, att FramebufferAttachment) { - data, size := att.dataAndSize(g, c) - b.Read(g, size) - b.Modify(g, data) - }) - // TODO: Write transform feedback buffers. - } else if cmd.CmdFlags(ctx, id, s).IsClear() { - switch cmd := cmd.(type) { - case *GlClearBufferfi: - clearBuffer(g, &b, cmd.Buffer(), cmd.Drawbuffer(), c) - case *GlClearBufferfv: - clearBuffer(g, &b, cmd.Buffer(), cmd.Drawbuffer(), c) - case *GlClearBufferiv: - clearBuffer(g, &b, cmd.Buffer(), cmd.Drawbuffer(), c) - case *GlClearBufferuiv: - clearBuffer(g, &b, cmd.Buffer(), cmd.Drawbuffer(), c) - case *GlClear: - if (cmd.Mask() & GLbitfield_GL_COLOR_BUFFER_BIT) != 0 { - for i := range c.Bound().DrawFramebuffer().ColorAttachments().All() { - clearBuffer(g, &b, GLenum_GL_COLOR, i, c) - } - } - if (cmd.Mask() & GLbitfield_GL_DEPTH_BUFFER_BIT) != 0 { - clearBuffer(g, &b, GLenum_GL_DEPTH, 0, c) - } - if (cmd.Mask() & GLbitfield_GL_STENCIL_BUFFER_BIT) != 0 { - clearBuffer(g, &b, GLenum_GL_STENCIL, 0, c) - } - default: - log.E(ctx, "Unknown clear command: %v", cmd) - } - } else { - switch cmd := cmd.(type) { - case *GlCopyImageSubData: - // TODO: This assumes whole-image copy. Handle sub-range copies. - if cmd.SrcTarget() == GLenum_GL_RENDERBUFFER { - b.Read(g, renderbufferDataKey{c.Objects().Renderbuffers().Get(RenderbufferId(cmd.SrcName()))}) - } else { - for layer := GLsizei(0); layer < cmd.SrcDepth(); layer++ { - data, size := c.Objects().Textures().Get(TextureId(cmd.SrcName())).dataAndSize(cmd.SrcLevel(), GLint(layer)+cmd.SrcZ()) - b.Read(g, data) - b.Read(g, size) - } - } - if cmd.DstTarget() == GLenum_GL_RENDERBUFFER { - b.Write(g, - renderbufferDataKey{c.Objects().Renderbuffers().Get(RenderbufferId(cmd.DstName()))}) - } else { - for layer := GLsizei(0); layer < cmd.SrcDepth(); layer++ { - data, size := c.Objects().Textures().Get(TextureId(cmd.DstName())).dataAndSize(cmd.DstLevel(), GLint(layer)+cmd.DstZ()) - b.Write(g, data) - b.Write(g, size) - } - } - case *GlFramebufferTexture2D: - var layer GLint - switch target := cmd.TextureTarget(); target { - case GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - layer = GLint(target - GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X) - } - b.Read(g, textureSizeKey{c.Objects().Textures().Get(cmd.Texture()), cmd.Texture(), cmd.Level(), layer}) - b.KeepAlive = true // Changes untracked state - case *GlFramebufferTexture: - if t := c.Objects().Textures().Get(cmd.Texture()); !t.IsNil() { - for layer := range t.Levels().Get(cmd.Level()).Layers().All() { - b.Read(g, textureSizeKey{t, cmd.Texture(), cmd.Level(), layer}) - } - } - b.KeepAlive = true // Changes untracked state - case *GlFramebufferTextureLayer: - b.Read(g, textureSizeKey{c.Objects().Textures().Get(cmd.Texture()), cmd.Texture(), cmd.Level(), cmd.Layer()}) - b.KeepAlive = true // Changes untracked state - case *GlCompressedTexImage2D: - texData, texSize := getTextureDataAndSize(ctx, cmd, id, s, c.Bound().TextureUnit(), cmd.Target(), cmd.Level()) - b.Modify(g, texData) - b.Write(g, texSize) - case *GlCompressedTexSubImage2D: - texData, _ := getTextureDataAndSize(ctx, cmd, id, s, c.Bound().TextureUnit(), cmd.Target(), cmd.Level()) - b.Modify(g, texData) - case *GlTexImage2D: - texData, texSize := getTextureDataAndSize(ctx, cmd, id, s, c.Bound().TextureUnit(), cmd.Target(), cmd.Level()) - b.Modify(g, texData) - b.Write(g, texSize) - case *GlTexSubImage2D: - texData, _ := getTextureDataAndSize(ctx, cmd, id, s, c.Bound().TextureUnit(), cmd.Target(), cmd.Level()) - b.Modify(g, texData) - case *GlGenerateMipmap: - tex, err := subGetBoundTextureOrErrorInvalidEnum(ctx, cmd, id, nil, s, GetState(s), cmd.Thread(), nil, nil, cmd.Target()) - if err != nil { - log.E(ctx, "Can not find bound texture %v", cmd.Target()) - } - if baseLevel, ok := tex.Levels().Lookup(0); ok { - for layerIndex := range baseLevel.Layers().All() { - data, size := tex.dataAndSize(0, layerIndex) - b.Read(g, data) - b.Read(g, size) - // Overestimate the number of levels to 31 - for levelIndex := GLint(1); levelIndex < 32; levelIndex++ { - data, size := tex.dataAndSize(levelIndex, layerIndex) - b.Write(g, size) - b.Write(g, data) - } - } - } - case *GlShaderSource: - b.Write(g, shaderKey{c.Objects().Shaders().Get(cmd.Shader()), source}) - case *GlCompileShader: - s := c.Objects().Shaders().Get(cmd.Shader()) - b.Read(g, shaderKey{s, source}) - b.Write(g, shaderKey{s, compilestate}) - case *GlLinkProgram: - p := c.Objects().Programs().Get(cmd.Program()) - for _, s := range p.Shaders().All() { - b.Read(g, shaderKey{s, compilestate}) - } - b.Write(g, programKey{p, linkstate}) - case *GlGetUniformLocation: - // Treat this as a modify so it is coupled with the glLinkProgram call. - b.Modify(g, programKey{c.Objects().Programs().Get(cmd.Program()), linkstate}) - case *GlUseProgram: - p := c.Objects().Programs().Get(cmd.Program()) - b.Read(g, programKey{p, linkstate}) - b.Write(g, programKey{p, binding}) - case *GlBindProgramPipeline: - p := c.Objects().Pipelines().Get(cmd.Pipeline()) - b.Read(g, programKey{p.VertexShader(), linkstate}) - b.Read(g, programKey{p.TessControlShader(), linkstate}) - b.Read(g, programKey{p.TessEvaluationShader(), linkstate}) - b.Read(g, programKey{p.GeometryShader(), linkstate}) - b.Read(g, programKey{p.FragmentShader(), linkstate}) - b.Read(g, programKey{p.ComputeShader(), linkstate}) - b.KeepAlive = true // TODO: complete separable shader support - case *GlUniform1f: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform2f: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform3f: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform4f: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform1i: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform2i: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform3i: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform4i: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform1ui: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform2ui: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform3ui: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform4ui: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), 1}) - case *GlUniform1fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform2fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform3fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform4fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform1iv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform2iv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform3iv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform4iv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform1uiv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform2uiv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform3uiv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniform4uiv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix2fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix3fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix4fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix2x3fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix3x2fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix2x4fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix4x2fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix3x4fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlUniformMatrix4x3fv: - p := getBoundProgram(c) - b.Read(g, programKey{p, binding}) - b.Write(g, uniformKey{p, cmd.Location(), cmd.Count()}) - case *GlVertexAttribPointer: - b.Write(g, vertexAttribKey{c.Bound().VertexArray(), cmd.Location()}) - case *GlEGLImageTargetTexture2DOES: - img := GetState(s).EGLImages().Get(EGLImageKHR(cmd.Image())) - if !img.IsNil() && img.Target() == EGLenum_EGL_GL_TEXTURE_2D { - if sc := GetState(s).EGLContexts().Get(img.Context()); !sc.IsNil() { - data, size := sc.Objects().Textures().Get(TextureId(img.Buffer())).dataAndSize(0, 0) - b.Read(g, data) - b.Read(g, size) - } - } - data, size := getTextureDataAndSize(ctx, cmd, id, s, c.Bound().TextureUnit(), cmd.Target(), 0) - b.Write(g, data) - b.Write(g, size) - default: - // Force all unhandled commands to be kept alive. - b.KeepAlive = true - } - } - } else /* c == nil */ { - b.KeepAlive = true - } - return b -} - -func getBoundProgram(c Contextʳ) Programʳ { - switch { - case !c.Bound().Program().IsNil(): - return c.Bound().Program() - case !c.Bound().Pipeline().IsNil(): - return c.Bound().Pipeline().ActiveProgram() - default: - return NilProgramʳ - } -} - -func clearBuffer(g *dependencygraph.DependencyGraph, b *dependencygraph.CmdBehaviour, buffer GLenum, index GLint, c Contextʳ) { - var data, size dependencygraph.StateKey - switch buffer { - case GLenum_GL_COLOR: - data, size = c.Bound().DrawFramebuffer().ColorAttachments().Get(index).dataAndSize(g, c) - case GLenum_GL_DEPTH: - data, size = c.Bound().DrawFramebuffer().DepthAttachment().dataAndSize(g, c) - case GLenum_GL_STENCIL: - data, size = c.Bound().DrawFramebuffer().StencilAttachment().dataAndSize(g, c) - case GLenum_GL_DEPTH_STENCIL: - data, size = c.Bound().DrawFramebuffer().DepthAttachment().dataAndSize(g, c) - b.Read(g, size) - b.Write(g, data) - data, size = c.Bound().DrawFramebuffer().StencilAttachment().dataAndSize(g, c) - } - b.Read(g, size) - b.Write(g, data) -} - -func (pipeline Pipelineʳ) Uniforms() []Uniform { - var uniforms []Uniform - if pipeline.IsNil() { - return uniforms - } - // TODO: These might not all be necessary. - uniforms = append(uniforms, pipeline.VertexShader().Uniforms()...) - uniforms = append(uniforms, pipeline.TessControlShader().Uniforms()...) - uniforms = append(uniforms, pipeline.TessEvaluationShader().Uniforms()...) - uniforms = append(uniforms, pipeline.GeometryShader().Uniforms()...) - uniforms = append(uniforms, pipeline.FragmentShader().Uniforms()...) - uniforms = append(uniforms, pipeline.ComputeShader().Uniforms()...) - return uniforms -} - -func (program Programʳ) Uniforms() []Uniform { - if program.IsNil() { - return nil - } - uniforms := make([]Uniform, 0, len(program.UniformLocations().All())) - for _, u := range program.UniformLocations().All() { - uniforms = append(uniforms, u) - } - return uniforms -} - -func getAllUsedTextureData(ctx context.Context, cmd api.Cmd, id api.CmdID, s *api.GlobalState, c Contextʳ) (stateKeys []dependencygraph.StateKey) { - - // Look for samplers used by the current program/pipeline. - - // Get the uniforms in use. - var uniforms []Uniform - - if !c.Bound().Program().IsNil() { - // The bound Program is used if present. - uniforms = c.Bound().Program().Uniforms() - } else if !c.Bound().Pipeline().IsNil() { - // Otherwise, the bound Pipeline is used, if present. - uniforms = c.Bound().Pipeline().Uniforms() - } else { - // Otherwise, there is no bound Program nor Pipeline; no texture reads. - return - } - - for _, uniform := range uniforms { - if uniform.Type() == GLenum_GL_FLOAT_VEC4 || uniform.Type() == GLenum_GL_FLOAT_MAT4 { - continue // Optimization - skip the two most common types which we know are not samplers. - } - target, _ := subGetTextureTargetFromSamplerType(ctx, cmd, id, nil, s, GetState(s), cmd.Thread(), nil, nil, uniform.Type()) - if target == GLenum_GL_NONE { - continue // Not a sampler type - } - units := AsU32ˢ(s.Arena, uniform.Values(), s.MemoryLayout).MustRead(ctx, cmd, s, nil) - for _, unit := range units { - if tu := c.Objects().TextureUnits().Get(TextureUnitId(unit)); !tu.IsNil() { - tex, err := subGetBoundTextureForUnit(ctx, cmd, id, nil, s, GetState(s), cmd.Thread(), nil, nil, tu, target) - if !tex.IsNil() && err == nil { - if !tex.EGLImage().IsNil() { - stateKeys = append(stateKeys, eglImageDataKey{tex.EGLImage()}) - } else { - stateKeys = append(stateKeys, textureDataGroupKey{tex, tex.ID()}) - } - } - } - } - } - return -} - -func getTextureDataAndSize( - ctx context.Context, - cmd api.Cmd, - id api.CmdID, - s *api.GlobalState, - unit TextureUnitʳ, - target GLenum, - level GLint) (dependencygraph.StateKey, dependencygraph.StateKey) { - - tex, err := subGetBoundTextureForUnit(ctx, cmd, id, nil, s, GetState(s), cmd.Thread(), nil, nil, unit, target) - if tex.IsNil() || err != nil { - log.E(ctx, "Can not find texture %v in unit %v", target, unit) - return nil, nil - } - layer := cubemapFaceToLayer(target) - return tex.dataAndSize(level, layer) -} - -func (tex Textureʳ) dataAndSize(level, layer GLint) (dependencygraph.StateKey, dependencygraph.StateKey) { - if !tex.EGLImage().IsNil() { - return eglImageDataKey{tex.EGLImage()}, eglImageSizeKey{tex.EGLImage()} - } - return textureDataKey{tex, tex.ID(), level, layer}, textureSizeKey{tex, tex.ID(), layer, level} -} - -func (att FramebufferAttachment) dataAndSize(g *dependencygraph.DependencyGraph, c Contextʳ) (dataKey dependencygraph.StateKey, sizeKey dependencygraph.StateKey) { - if att.Type() == GLenum_GL_RENDERBUFFER { - rb := att.Renderbuffer() - if !rb.IsNil() && !rb.Image().IsNil() && rb.Image().SizedFormat() != GLenum_GL_NONE { - scissor := c.Pixel().Scissor() - box := scissor.Box() - if scissor.Test() == GLboolean_GL_TRUE && !box.EqualTo(0, 0, rb.Image().Width(), rb.Image().Height()) { - box := scissor.Box() - x, y, w, h := box.X(), box.Y(), box.Width(), box.Height() - dataKey, sizeKey = renderbufferSubDataKey{rb, x, y, w, h}, nil - } else { - dataKey, sizeKey = renderbufferDataKey{rb}, nil - } - } - } - if att.Type() == GLenum_GL_TEXTURE { - if tex := att.Texture(); !tex.IsNil() { - // TODO: We should handle scissor here as well. - dataKey, sizeKey = tex.dataAndSize(att.TextureLevel(), att.TextureLayer()) - } - } - if dataKey != nil { - g.SetRoot(dataKey) - } - return -} diff --git a/gapis/api/gles/dependencygraph2_test.go b/gapis/api/gles/dependencygraph2_test.go deleted file mode 100644 index 7fee12ba71..0000000000 --- a/gapis/api/gles/dependencygraph2_test.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles_test - -import ( - "context" - "fmt" - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/resolve/dependencygraph2" -) - -// Test helpers - -// testDependencyCmdName is used as a map key to easily express -// expected dependencies -type testDependencyCmdName struct { - sourceCmdName, targetCmdName string -} - -// getCommandName return the command name of a graph node -func getCommandName(graph dependencygraph2.DependencyGraph, nodeId dependencygraph2.NodeID) string { - node := graph.GetNode(nodeId) - if cmdNode, ok := node.(dependencygraph2.CmdNode); ok { - cmdId := cmdNode.Index[0] - if api.CmdID(cmdId).IsReal() { - command := graph.GetCommand(api.CmdID(cmdId)) - return command.CmdName() - } - } - return "" -} - -// testCaptureAndGraph abstracts the boilerplate for creating a capture -// programmatically, check expected dependencies in its graph, and -// clean out -type testCaptureAndGraph struct { - ctx context.Context - arena arena.Arena - cb gles.CommandBuilder - cmds []api.Cmd -} - -// init runs the boilerplate up to being able to add commands to tc.cmds -func (tc *testCaptureAndGraph) init(t *testing.T) { - tc.ctx = log.Testing(t) - tc.ctx = bind.PutRegistry(tc.ctx, bind.NewRegistry()) - tc.ctx = database.Put(tc.ctx, database.NewInMemory(tc.ctx)) - tc.arena = arena.New() - ctxHandle := memory.BytePtr(1) - displayHandle := memory.BytePtr(2) - surfaceHandle := memory.BytePtr(3) - tc.cb = gles.CommandBuilder{Thread: 0, Arena: tc.arena} - - // Common prologue: make an EGL context - tc.cmds = []api.Cmd{ - tc.cb.EglCreateContext(displayHandle, surfaceHandle, surfaceHandle, memory.Nullptr, ctxHandle), - api.WithExtras( - tc.cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle, 0), - gles.NewStaticContextStateForTest(tc.arena), gles.NewDynamicContextStateForTest(tc.arena, 64, 64, false)), - } -} - -// terminate cleans up what need to be -func (tc *testCaptureAndGraph) terminate() { - tc.arena.Dispose() -} - -// checkDependenciesArePresent generate the graph and check if -// expected dependencies present -func (tc *testCaptureAndGraph) checkDependenciesArePresent(t *testing.T, expected, unexpected []testDependencyCmdName) { - // Compute dependency graph - header := &capture.Header{ABI: device.AndroidARM64v8a} - cap, err := capture.NewGraphicsCapture(tc.ctx, tc.arena, t.Name(), header, nil, tc.cmds) - if err != nil { - panic(err) - } - capturePath, err := cap.Path(tc.ctx) - if err != nil { - panic(err) - } - tc.ctx = capture.Put(tc.ctx, capturePath) - - cfg := dependencygraph2.DependencyGraphConfig{ - MergeSubCmdNodes: true, - IncludeInitialCommands: false, - } - graph, err := dependencygraph2.GetDependencyGraph(tc.ctx, capturePath, cfg) - if err != nil { - panic(err) - } - - // Check dependencies - mapExpected := map[testDependencyCmdName]bool{} - for _, dep := range expected { - mapExpected[dep] = false - } - mapUnexpected := map[testDependencyCmdName]bool{} - for _, dep := range unexpected { - mapUnexpected[dep] = false - } - - graph.ForeachDependency( - func(src, tgt dependencygraph2.NodeID) error { - srcCmdName := getCommandName(graph, src) - tgtCmdName := getCommandName(graph, tgt) - dep := testDependencyCmdName{srcCmdName, tgtCmdName} - if _, ok := mapExpected[dep]; ok { - mapExpected[dep] = true - } - if _, ok := mapUnexpected[dep]; ok { - mapUnexpected[dep] = true - } - return nil - }) - - for dep, present := range mapExpected { - assert.For(tc.ctx, fmt.Sprintf("Dependency: %v", dep)).ThatBoolean(present).IsTrue() - } - for dep, present := range mapUnexpected { - assert.For(tc.ctx, fmt.Sprintf("Dependency: %v", dep)).ThatBoolean(present).IsFalse() - } -} - -// Actual tests - -// glClear(GL_COLOR_BUFFER_BIT) depends on glClearColor() -func TestDependencyGlClearColor(t *testing.T) { - var tc testCaptureAndGraph - tc.init(t) - defer tc.terminate() - - tc.cmds = append(tc.cmds, - tc.cb.GlClearColor(1, 1, 1, 1), - tc.cb.GlClearDepthf(1), - tc.cb.GlClearStencil(1), - tc.cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT)) - - expected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearColor"}, - } - - unexpected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearDepthf"}, - testDependencyCmdName{"glClear", "glClearStencil"}, - } - - tc.checkDependenciesArePresent(t, expected, unexpected) -} - -// glClear(GL_DEPTH_BUFFER_BIT) depends on glClearDepthf() -func TestDependencyGlClearDepthf(t *testing.T) { - var tc testCaptureAndGraph - tc.init(t) - defer tc.terminate() - - tc.cmds = append(tc.cmds, - tc.cb.GlClearColor(1, 1, 1, 1), - tc.cb.GlClearDepthf(1), - tc.cb.GlClearStencil(1), - tc.cb.GlClear(gles.GLbitfield_GL_DEPTH_BUFFER_BIT)) - - expected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearDepthf"}, - } - - unexpected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearColor"}, - testDependencyCmdName{"glClear", "glClearStencil"}, - } - - tc.checkDependenciesArePresent(t, expected, unexpected) -} - -// glClear(GL_STENCIL_BUFFER_BIT) depends on glClearStencil() -func TestDependencyGlClearStencil(t *testing.T) { - var tc testCaptureAndGraph - tc.init(t) - defer tc.terminate() - - tc.cmds = append(tc.cmds, - tc.cb.GlClearColor(1, 1, 1, 1), - tc.cb.GlClearDepthf(1), - tc.cb.GlClearStencil(1), - tc.cb.GlClear(gles.GLbitfield_GL_STENCIL_BUFFER_BIT)) - - expected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearStencil"}, - } - - unexpected := []testDependencyCmdName{ - testDependencyCmdName{"glClear", "glClearColor"}, - testDependencyCmdName{"glClear", "glClearDepthf"}, - } - - tc.checkDependenciesArePresent(t, expected, unexpected) -} diff --git a/gapis/api/gles/doc.go b/gapis/api/gles/doc.go deleted file mode 100644 index 4036b420cd..0000000000 --- a/gapis/api/gles/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package gles implementes the API interface for the OpenGL ES graphics library. -package gles diff --git a/gapis/api/gles/draw_call.go b/gapis/api/gles/draw_call.go deleted file mode 100644 index b880cb1b40..0000000000 --- a/gapis/api/gles/draw_call.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/data/binary" - "github.com/google/gapid/core/math/u64" - "github.com/google/gapid/gapis/api" -) - -type drawCallIndices struct { - indices []uint32 - drawMode GLenum - indexed bool -} - -// drawCall is the interface implemented by all GLES draw call commands. -type drawCall interface { - api.Cmd - getIndices(ctx context.Context, c Contextʳ, s *api.GlobalState) (drawCallIndices, error) - getDrawMode() GLenum -} - -func (a *GlDrawArrays) getIndices(ctx context.Context, c Contextʳ, s *api.GlobalState) (drawCallIndices, error) { - indices := make([]uint32, a.IndicesCount()) - for i := range indices { - indices[i] = uint32(a.FirstIndex()) + uint32(i) - } - return drawCallIndices{indices, a.DrawMode(), false}, nil -} - -func (a *GlDrawArrays) getDrawMode() GLenum { - return a.DrawMode() -} - -func (a *GlDrawElements) getIndices(ctx context.Context, c Contextʳ, s *api.GlobalState) (drawCallIndices, error) { - return getIndices(ctx, c, s, a.IndicesType(), a.DrawMode(), 0, a.IndicesCount(), a.Indices()) -} - -func (a *GlDrawElements) getDrawMode() GLenum { - return a.DrawMode() -} - -func (a *GlDrawRangeElements) getIndices(ctx context.Context, c Contextʳ, s *api.GlobalState) (drawCallIndices, error) { - return getIndices(ctx, c, s, a.IndicesType(), a.DrawMode(), 0, a.IndicesCount(), a.Indices()) -} - -func (a *GlDrawRangeElements) getDrawMode() GLenum { - return a.DrawMode() -} - -func getIndices( - ctx context.Context, - c Contextʳ, - s *api.GlobalState, - ty, drawMode GLenum, - first, count GLsizei, - ptr IndicesPointer) (drawCallIndices, error) { - - indexSize := uint64(DataTypeSize(ty)) - indexBuffer := c.Bound().VertexArray().ElementArrayBuffer() - size := uint64(count) * indexSize - offset := uint64(first) * indexSize - - var reader binary.Reader - if indexBuffer.IsNil() { - // Get the index buffer data from pointer - reader = ptr.Slice(offset, size, s.MemoryLayout).Reader(ctx, s) - } else { - // Get the index buffer data from buffer, offset by the 'indices' pointer. - offset += ptr.Address() - count := indexBuffer.Data().Count() - start := u64.Min(offset, count) - end := u64.Min(offset+size, count) - reader = indexBuffer.Data().Slice(start, end).Reader(ctx, s) - } - - indices, err := decodeIndices(reader, ty) - if err != nil { - return drawCallIndices{}, err - } - return drawCallIndices{indices, drawMode, true}, err -} - -// decodeIndices assumes little endian encoding -func decodeIndices(r binary.Reader, indicesType GLenum) ([]uint32, error) { - var indices []uint32 - switch indicesType { - case GLenum_GL_UNSIGNED_BYTE: - for { - if val := r.Uint8(); r.Error() == nil { - indices = append(indices, uint32(val)) - } else { - return indices, nil - } - } - - case GLenum_GL_UNSIGNED_SHORT: - for { - if val := r.Uint16(); r.Error() == nil { - indices = append(indices, uint32(val)) - } else { - return indices, nil - } - } - - case GLenum_GL_UNSIGNED_INT: - for { - if val := r.Uint32(); r.Error() == nil { - indices = append(indices, val) - } else { - return indices, nil - } - } - - default: - return nil, fmt.Errorf("Invalid index type: %v", indicesType) - } -} - -// The draw calls below are stubbed. -func (GlDrawArraysIndirect) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysIndirect.getIndices() not implemented") -} -func (a *GlDrawArraysIndirect) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawArraysInstanced) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysInstanced.getIndices() not implemented") -} -func (a *GlDrawArraysInstanced) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawArraysInstancedANGLE) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysInstancedANGLE.getIndices() not implemented") -} -func (a *GlDrawArraysInstancedANGLE) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawArraysInstancedBaseInstanceEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysInstancedBaseInstanceEXT.getIndices() not implemented") -} -func (a *GlDrawArraysInstancedBaseInstanceEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawArraysInstancedEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysInstancedEXT.getIndices() not implemented") -} -func (a *GlDrawArraysInstancedEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawArraysInstancedNV) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawArraysInstancedNV.getIndices() not implemented") -} -func (a *GlDrawArraysInstancedNV) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsBaseVertex) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsBaseVertex.getIndices() not implemented") -} -func (a *GlDrawElementsBaseVertex) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawElementsBaseVertexEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsBaseVertexEXT.getIndices() not implemented") -} -func (a *GlDrawElementsBaseVertexEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsBaseVertexOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsBaseVertexOES.getIndices() not implemented") -} -func (a *GlDrawElementsBaseVertexOES) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsIndirect) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsIndirect.getIndices() not implemented") -} -func (a *GlDrawElementsIndirect) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawElementsInstanced) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstanced.getIndices() not implemented") -} -func (a *GlDrawElementsInstanced) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawElementsInstancedANGLE) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedANGLE.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedANGLE) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedBaseInstanceEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedBaseInstanceEXT.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedBaseInstanceEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedBaseVertex) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedBaseVertex.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedBaseVertex) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawElementsInstancedBaseVertexBaseInstanceEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedBaseVertexBaseInstanceEXT.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedBaseVertexBaseInstanceEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedBaseVertexEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedBaseVertexEXT.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedBaseVertexEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedBaseVertexOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedBaseVertexOES.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedBaseVertexOES) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedEXT.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawElementsInstancedNV) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawElementsInstancedNV.getIndices() not implemented") -} -func (a *GlDrawElementsInstancedNV) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawRangeElementsBaseVertex) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawRangeElementsBaseVertex.getIndices() not implemented") -} -func (a *GlDrawRangeElementsBaseVertex) getDrawMode() GLenum { - return a.DrawMode() -} - -func (GlDrawRangeElementsBaseVertexEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawRangeElementsBaseVertexEXT.getIndices() not implemented") -} -func (a *GlDrawRangeElementsBaseVertexEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawRangeElementsBaseVertexOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawRangeElementsBaseVertexOES.getIndices() not implemented") -} -func (a *GlDrawRangeElementsBaseVertexOES) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawTexfOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexfOES.getIndices() not implemented") -} -func (a *GlDrawTexfOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexfvOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexfvOES.getIndices() not implemented") -} -func (a *GlDrawTexfvOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexiOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexiOES.getIndices() not implemented") -} -func (a *GlDrawTexiOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexivOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexivOES.getIndices() not implemented") -} -func (a *GlDrawTexivOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexsOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexsOES.getIndices() not implemented") -} -func (a *GlDrawTexsOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexsvOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexsvOES.getIndices() not implemented") -} -func (a *GlDrawTexsvOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexxOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexxOES.getIndices() not implemented") -} -func (a *GlDrawTexxOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTexxvOES) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTexxvOES.getIndices() not implemented") -} -func (a *GlDrawTexxvOES) getDrawMode() GLenum { - return GLenum_GL_TRIANGLES -} - -func (GlDrawTransformFeedbackEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTransformFeedbackEXT.getIndices() not implemented") -} -func (a *GlDrawTransformFeedbackEXT) getDrawMode() GLenum { - return a.Mode() -} - -func (GlDrawTransformFeedbackInstancedEXT) getIndices(context.Context, Contextʳ, *api.GlobalState) (drawCallIndices, error) { - return drawCallIndices{}, fmt.Errorf("GlDrawTransformFeedbackInstancedEXT.getIndices() not implemented") -} -func (a *GlDrawTransformFeedbackInstancedEXT) getDrawMode() GLenum { - return a.Mode() -} diff --git a/gapis/api/gles/draw_call_mesh.go b/gapis/api/gles/draw_call_mesh.go deleted file mode 100644 index 479a42cde0..0000000000 --- a/gapis/api/gles/draw_call_mesh.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/math/sint" - "github.com/google/gapid/core/math/u64" - "github.com/google/gapid/core/stream" - "github.com/google/gapid/core/stream/fmts" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/messages" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" - "github.com/google/gapid/gapis/vertex" -) - -// drawCallMesh builds a mesh for dc at p. -func drawCallMesh(ctx context.Context, dc drawCall, p *path.Mesh, r *path.ResolveConfig) (*api.Mesh, error) { - cmdPath := path.FindCommand(p) - if cmdPath == nil { - log.W(ctx, "Couldn't find command at path '%v'", p) - return nil, nil - } - - s, err := resolve.GlobalState(ctx, cmdPath.GlobalStateAfter(), r) - if err != nil { - return nil, err - } - - c := GetContext(s, dc.Thread()) - - noData := p.GetOptions().GetExcludeData() - - var dci drawCallIndices - if noData { - dci = drawCallIndices{nil, dc.getDrawMode(), false} - } else { - dci, err = dc.getIndices(ctx, c, s) - if err != nil { - return nil, err - } - } - - drawPrimitive, err := translateDrawPrimitive(dci.drawMode) - if err != nil { - // There are extensions like GL_QUADS_OES that do not translate directly - // to a api.DrawPrimitive. For now, log the error, and return - // (nil, nil) (no mesh available). See b/29416809. - log.E(ctx, "Couldn't translate GL primitive to api.DrawPrimitive: %v", err) - return nil, nil - } - - // Look at the indices to find the number of vertices we're dealing with. - count, uniqueIndices := 0, make(map[uint32]bool) - for _, i := range dci.indices { - if count <= int(i) { - count = int(i) + 1 - } - uniqueIndices[i] = true - } - - if count == 0 && !noData { - return nil, &service.ErrDataUnavailable{Reason: messages.ErrMeshHasNoVertices()} - } - - program := c.Bound().Program() - if program.IsNil() { - return nil, &service.ErrDataUnavailable{Reason: messages.ErrNoProgramBound()} - } - - if program.ActiveResources().IsNil() { - return nil, &service.ErrDataUnavailable{Reason: messages.ErrProgramNotLinked()} - } - - vb := &vertex.Buffer{} - va := c.Bound().VertexArray() - for _, attr := range program.ActiveResources().ProgramInputs().All() { - vaa := va.VertexAttributeArrays().Get(AttributeLocation(attr.Locations().Get(0))) - if vaa.IsNil() || vaa.Enabled() == GLboolean_GL_FALSE { - continue - } - vbb := vaa.Binding() - - format, err := translateVertexFormat(vaa) - if err != nil { - return nil, err - } - - var data []byte - if !noData { - var slice U8ˢ - if vbb.Buffer().IsNil() { - // upper bound doesn't really matter here, so long as it's big. - slice = U8ˢ(vaa.Pointer().Slice(0, 1<<30, s.MemoryLayout)) - } else { - slice = vbb.Buffer().Data() - } - data, err = vertexStreamData(ctx, vaa, vbb, count, slice, s) - if err != nil { - return nil, err - } - } - - vb.Streams = append(vb.Streams, - &vertex.Stream{ - Name: attr.Name(), - Data: data, - Format: format, - Semantic: &vertex.Semantic{}, - }, - ) - } - - guessSemantics(vb, p.Options.Hints()) - - ib := &api.IndexBuffer{Indices: dci.indices} - - mesh := &api.Mesh{ - DrawPrimitive: drawPrimitive, - VertexBuffer: vb, - IndexBuffer: ib, - Stats: &api.Mesh_Stats{ - Vertices: uint32(len(uniqueIndices)), - Primitives: drawPrimitive.Count(uint32(len(dci.indices))), - }, - } - if dci.indexed { - mesh.Stats.Indices = uint32(len(dci.indices)) - } - - if p.Options != nil && p.Options.Faceted { - return mesh.Faceted(ctx) - } - - return mesh, nil -} - -func vertexStreamData( - ctx context.Context, - vaa VertexAttributeArrayʳ, - vbb VertexBufferBindingʳ, - vectorCount int, - slice U8ˢ, - s *api.GlobalState) ([]byte, error) { - - if vbb.Divisor() != 0 { - return nil, fmt.Errorf("Instanced draw calls not currently supported") - } - - elementsPerVector := int(vaa.Size()) - vectorSize := elementsPerVector * DataTypeSize(vaa.Type()) - vectorStride := int(vaa.Stride()) - if vectorStride == 0 { - vectorStride = vectorSize - } - gap := vectorStride - vectorSize // number of bytes between each vector - - compactSize := vectorSize * vectorCount - out := make([]byte, compactSize) - - base := uint64(vaa.RelativeOffset()) + uint64(vbb.Offset()) - if base >= slice.Size() { - // First vertex sits beyond the end of the buffer. - // Instead of erroring just return a 0-initialized buffer so other - // streams can be visualized. The report should display an error to - // alert the user to the bad data. - // TODO: Actually add this as a report error. - return out, nil - } - - // Only read as much data as we actually have. - size := u64.Min(uint64(compactSize+ /* total size of gaps */ gap*(vectorCount-1)), slice.Size()-base) - data, err := slice.Slice(base, base+size).Read(ctx, nil, s, nil) - if err != nil { - return nil, err - } - if gap > 0 { - // Adjust vectorCount to the number of complete vectors found in data. - vectorCount := sint.Min((gap+len(data))/vectorStride, vectorCount) - // Copy the vector elements to out removing any gaps. - for i := 0; i < vectorCount; i++ { - copy(out[i*vectorSize:(i+1)*vectorSize], data[i*vectorStride:]) - } - } else { - // No gaps between vector elements. Simple copy. - copy(out, data) - } - - return out, nil -} - -func translateDrawPrimitive(e GLenum) (api.DrawPrimitive, error) { - switch e { - case GLenum_GL_POINTS: - return api.DrawPrimitive_Points, nil - case GLenum_GL_LINES: - return api.DrawPrimitive_Lines, nil - case GLenum_GL_LINE_STRIP: - return api.DrawPrimitive_LineStrip, nil - case GLenum_GL_LINE_LOOP: - return api.DrawPrimitive_LineLoop, nil - case GLenum_GL_TRIANGLES: - return api.DrawPrimitive_Triangles, nil - case GLenum_GL_TRIANGLE_STRIP: - return api.DrawPrimitive_TriangleStrip, nil - case GLenum_GL_TRIANGLE_FAN: - return api.DrawPrimitive_TriangleFan, nil - default: - return 0, fmt.Errorf("Invalid draw mode %v", e) - } -} - -func translateVertexFormat(vaa VertexAttributeArrayʳ) (*stream.Format, error) { - switch vaa.Type() { - case GLenum_GL_INT_2_10_10_10_REV: - return fmts.XYZW_S10S10S10S2, nil - case GLenum_GL_UNSIGNED_INT_2_10_10_10_REV: - return fmts.XYZW_U10U10U10U2, nil - } - - var dt stream.DataType - switch vaa.Type() { - case GLenum_GL_BYTE: - dt = stream.S8 - case GLenum_GL_UNSIGNED_BYTE: - dt = stream.U8 - case GLenum_GL_SHORT: - dt = stream.S16 - case GLenum_GL_UNSIGNED_SHORT: - dt = stream.U16 - case GLenum_GL_INT: - dt = stream.S32 - case GLenum_GL_UNSIGNED_INT: - dt = stream.U32 - case GLenum_GL_HALF_FLOAT, GLenum_GL_HALF_FLOAT_OES: - dt = stream.F16 - case GLenum_GL_FLOAT: - dt = stream.F32 - case GLenum_GL_FIXED: - dt = stream.S16_16 - default: - return nil, fmt.Errorf("Unsupported vertex type: %v", vaa.Type()) - } - - sampling := stream.Linear - if vaa.Normalized() != 0 { - sampling = stream.LinearNormalized - } - - fmt := &stream.Format{ - Components: make([]*stream.Component, vaa.Size()), - } - - xyzw := stream.Channels{ - stream.Channel_X, - stream.Channel_Y, - stream.Channel_Z, - stream.Channel_W, - } - for i := range fmt.Components { - fmt.Components[i] = &stream.Component{ - DataType: &dt, - Sampling: sampling, - Channel: xyzw[i], - } - } - return fmt, nil -} diff --git a/gapis/api/gles/externs.go b/gapis/api/gles/externs.go deleted file mode 100644 index 0c5630f927..0000000000 --- a/gapis/api/gles/externs.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay" - rb "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service/path" - "github.com/google/gapid/gapis/stringtable" - "github.com/pkg/errors" -) - -type externs struct { - ctx context.Context // Allowed because the externs struct is only a parameter proxy for a single call - cmd api.Cmd - cmdID api.CmdID - s *api.GlobalState - b *rb.Builder - w api.StateWatcher -} - -func (e externs) mapMemory(slice memory.Slice) { - ctx := e.ctx - if b := e.b; b != nil { - switch e.cmd.(type) { - case *GlMapBufferRange, *GlMapBufferRangeEXT, *GlMapBufferOES, *GlMapBuffer: - // Base address is on the stack. - b.MapMemory(memory.Range{Base: slice.Base(), Size: slice.Size()}) - - default: - log.E(ctx, "mapBuffer extern called for unsupported command: %v", e.cmd) - } - } -} - -func (e externs) unmapMemory(slice memory.Slice) { - if b := e.b; b != nil { - b.UnmapMemory(memory.Range{Base: slice.Base(), Size: slice.Size()}) - } -} - -func (e externs) GetEGLStaticContextState(EGLDisplay, EGLContext) StaticContextStateʳ { - return FindStaticContextState(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetEGLDynamicContextState(EGLDisplay, EGLSurface, EGLContext) DynamicContextStateʳ { - return FindDynamicContextState(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetAndroidNativeBufferExtra(Voidᵖ) AndroidNativeBufferExtraʳ { - return FindAndroidNativeBufferExtra(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetEGLImageData(id EGLImageKHR, _ GLsizei, _ GLsizei) { - if d := FindEGLImageData(e.cmd.Extras()); d != nil { - if GetState(e.s).EGLImages().Contains(id) { - ei := GetState(e.s).EGLImages().Get(id) - for _, img := range ei.Images().All() { - poolID, pool := e.s.Memory.New() - pool.Write(0, memory.Resource(d.ID, d.Size)) - data := NewU8ˢ(e.s.Arena, 0, 0, d.Size, d.Size, poolID) - img.SetWidth(GLsizei(d.Width)) - img.SetHeight(GLsizei(d.Height)) - img.SetData(data) - img.SetDataFormat(d.Format) - img.SetDataType(d.Type) - break // TODO: Support image arrays. - } - } - } -} - -func (e externs) calcIndexLimits(data U8ˢ, indexSize int) resolve.IndexRange { - id := data.ResourceID(e.ctx, e.s) - count := int(data.Size()) / int(indexSize) - littleEndian := e.s.MemoryLayout.GetEndian() == device.LittleEndian - limits, err := resolve.IndexLimits(e.ctx, id, count, indexSize, littleEndian) - if err != nil { - if errors.Cause(err) == context.Canceled { - // TODO: Propagate error - return resolve.IndexRange{} - } - panic(fmt.Errorf("Could not calculate index limits: %v", err)) - } - return *limits -} - -func (e externs) IndexLimits(data U8ˢ, indexSize int32) U32Limits { - limits := e.calcIndexLimits(data, int(indexSize)) - return NewU32Limits(e.s.Arena, limits.First, limits.Count) -} - -func (e externs) substr(str string, start, end int32) string { - return str[start:end] -} - -func (e externs) GetCompileShaderExtra(ctx Contextʳ, obj Shaderʳ, bin BinaryExtraʳ) CompileShaderExtraʳ { - return FindCompileShaderExtra(e.s.Arena, e.cmd.Extras(), obj).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetLinkProgramExtra(ctx Contextʳ, obj Programʳ, bin BinaryExtraʳ) LinkProgramExtraʳ { - return FindLinkProgramExtra(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetValidateProgramExtra(ctx Contextʳ, obj Programʳ) ValidateProgramExtraʳ { - return FindValidateProgramExtra(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) GetValidateProgramPipelineExtra(ctx Contextʳ, obj Pipelineʳ) ValidateProgramPipelineExtraʳ { - return FindValidateProgramPipelineExtra(e.s.Arena, e.cmd.Extras()).Clone(e.s.Arena, api.CloneContext{}) -} - -func (e externs) onGlError(err GLenum) { - // Call the state's callback function for API error. - if f := e.s.OnError; f != nil { - f(err) - } -} - -func (e externs) newMsg(severity Severity, message *stringtable.Msg) uint32 { - // Call the state's callback function for message. - if f := e.s.NewMessage; f != nil { - return f(severityFromEnum(severity), message) - } - return 0 -} - -// Maps generated Severity to one of the const values defined in log. -func severityFromEnum(enumValue Severity) log.Severity { - switch enumValue { - case Severity_SEVERITY_DEBUG: - return log.Debug - case Severity_SEVERITY_INFO: - return log.Info - case Severity_SEVERITY_WARNING: - return log.Warning - case Severity_SEVERITY_ERROR: - return log.Error - case Severity_SEVERITY_FATAL: - return log.Fatal - default: - panic(fmt.Errorf("Bad Severity value %v", enumValue)) - } -} - -func (e externs) addTag(msgID uint32, message *stringtable.Msg) { - // Call the state's callback function for message. - if f := e.s.AddTag; f != nil { - f(msgID, message) - } -} - -func (e externs) ReadGPUTextureData(texture Textureʳ, level, layer GLint) U8ˢ { - poolID, dst := e.s.Memory.New() - img := texture.Levels().Get(level).Layers().Get(layer) - dataFormat, dataType := img.getUnsizedFormatAndType() - format, err := getImageFormat(dataFormat, dataType) - if err != nil { - panic(err) - } - size := format.Size(int(img.Width()), int(img.Height()), 1) - device := replay.GetDevice(e.ctx) - if device == nil { - log.W(e.ctx, "No device bound for GPU texture read") - return NewU8ˢ(e.s.Arena, 0, 0, uint64(size), uint64(size), poolID) - } - dataID, err := database.Store(e.ctx, &ReadGPUTextureDataResolveable{ - Capture: path.NewCapture(capture.Get(e.ctx).ID.ID()), - Device: device, - After: uint64(e.cmdID), - Thread: e.cmd.Thread(), - Texture: uint32(texture.ID()), - Level: uint32(level), - Layer: uint32(layer), - DataFormat: uint32(dataFormat), - DataType: uint32(dataType), - }) - if err != nil { - panic(err) - } - data := memory.Resource(dataID, uint64(size)) - dst.Write(0, data) - return NewU8ˢ(e.s.Arena, 0, 0, uint64(size), uint64(size), poolID) -} diff --git a/gapis/api/gles/extras.go b/gapis/api/gles/extras.go deleted file mode 100644 index ad422aba60..0000000000 --- a/gapis/api/gles/extras.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/core/data/protoconv" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles/gles_pb" -) - -// ErrorState is a command extra used to describe the GLES error state after -// the command has been executed. It is optional - we use it only for testing. -type ErrorState struct { - TraceDriversGlError GLenum - InterceptorsGlError GLenum -} - -// EGLImageData is an extra used to store snapshot of external image source. -type EGLImageData struct { - ID id.ID - Size uint64 - Width GLsizei - Height GLsizei - Format GLenum - Type GLenum -} - -func init() { - protoconv.Register( - func(ctx context.Context, o *ErrorState) (*gles_pb.ErrorState, error) { - return &gles_pb.ErrorState{ - TraceDriversGlError: uint32(o.TraceDriversGlError), - InterceptorsGlError: uint32(o.InterceptorsGlError), - }, nil - }, func(ctx context.Context, p *gles_pb.ErrorState) (*ErrorState, error) { - return &ErrorState{ - TraceDriversGlError: GLenum(p.TraceDriversGlError), - InterceptorsGlError: GLenum(p.InterceptorsGlError), - }, nil - }, - ) - protoconv.Register( - func(ctx context.Context, o *EGLImageData) (*gles_pb.EGLImageData, error) { - resIndex, err := id.GetRemapper(ctx).RemapID(ctx, o.ID) - if err != nil { - return nil, err - } - return &gles_pb.EGLImageData{ - ResIndex: resIndex, - Size: int32(o.Size), - Width: int32(o.Width), - Height: int32(o.Height), - Format: int32(o.Format), - Type: int32(o.Type), - }, nil - }, func(ctx context.Context, p *gles_pb.EGLImageData) (*EGLImageData, error) { - id, err := id.GetRemapper(ctx).RemapIndex(ctx, p.ResIndex) - if err != nil { - return nil, err - } - return &EGLImageData{ - ID: id, - Size: uint64(p.Size), - Width: GLsizei(p.Width), - Height: GLsizei(p.Height), - Format: GLenum(p.Format), - Type: GLenum(p.Type), - }, nil - }, - ) -} - -// FindErrorState searches for the ErrorState in the extras, returning the -// ErrorState if found, otherwise nil. -func FindErrorState(extras *api.CmdExtras) *ErrorState { - for _, e := range extras.All() { - if pi, ok := e.(*ErrorState); ok { - return pi - } - } - return nil -} - -// FindEGLImageData searches for the EGLImageData in the extras, returning the -// EGLImageData if found, otherwise nil. -func FindEGLImageData(extras *api.CmdExtras) *EGLImageData { - for _, e := range extras.All() { - if res, ok := e.(*EGLImageData); ok { - return res - } - } - return nil -} - -// FindCompileShaderExtra searches for the CompileShaderExtra in the extras, -// returning the CompileShaderExtra if found, otherwise nil. -func FindCompileShaderExtra(a arena.Arena, extras *api.CmdExtras, forShader Shaderʳ) CompileShaderExtraʳ { - for _, e := range extras.All() { - if pi, ok := e.(CompileShaderExtra); ok { - // There can be several of those extras - pick the right one. - if pi.ID() == forShader.ID() { - return MakeCompileShaderExtraʳ(a).Set(pi) - } - } - } - return NilCompileShaderExtraʳ -} - -// FindLinkProgramExtra searches for the LinkProgramExtra in the extras, -// returning the LinkProgramExtra if found, otherwise nil. -func FindLinkProgramExtra(a arena.Arena, extras *api.CmdExtras) LinkProgramExtraʳ { - for _, e := range extras.All() { - if pi, ok := e.(LinkProgramExtra); ok { - return MakeLinkProgramExtraʳ(a).Set(pi) - } - } - return NilLinkProgramExtraʳ -} - -// FindValidateProgramExtra searches for the ValidateProgramExtra in the extras, -// returning the ValidateProgramExtra if found, otherwise nil. -func FindValidateProgramExtra(a arena.Arena, extras *api.CmdExtras) ValidateProgramExtraʳ { - for _, e := range extras.All() { - if pi, ok := e.(ValidateProgramExtra); ok { - return MakeValidateProgramExtraʳ(a).Set(pi) - } - } - return NilValidateProgramExtraʳ -} - -// FindValidateProgramPipelineExtra searches for the ValidateProgramPipelineExtra in the extras, -// returning the ValidateProgramPipelineExtra if found, otherwise nil. -func FindValidateProgramPipelineExtra(a arena.Arena, extras *api.CmdExtras) ValidateProgramPipelineExtraʳ { - for _, e := range extras.All() { - if pi, ok := e.(ValidateProgramPipelineExtra); ok { - return MakeValidateProgramPipelineExtraʳ(a).Set(pi) - } - } - return NilValidateProgramPipelineExtraʳ -} - -// FindStaticContextState searches for the StaticContextState in the extras, -// returning the StaticContextState if found, otherwise nil. -func FindStaticContextState(a arena.Arena, extras *api.CmdExtras) StaticContextStateʳ { - for _, e := range extras.All() { - if cs, ok := e.(StaticContextState); ok { - return MakeStaticContextStateʳ(a).Set(cs) - } - } - return NilStaticContextStateʳ -} - -// FindDynamicContextState searches for the DynamicContextState in the extras, -// returning the DynamicContextState if found, otherwise nil. -func FindDynamicContextState(a arena.Arena, extras *api.CmdExtras) DynamicContextStateʳ { - for _, e := range extras.All() { - if cs, ok := e.(DynamicContextState); ok { - return MakeDynamicContextStateʳ(a).Set(cs) - } - } - return NilDynamicContextStateʳ -} - -// FindAndroidNativeBufferExtra searches for the AndroidNativeBufferExtra in the extras, -// returning the AndroidNativeBufferExtra if found, otherwise nil. -func FindAndroidNativeBufferExtra(a arena.Arena, extras *api.CmdExtras) AndroidNativeBufferExtraʳ { - for _, e := range extras.All() { - if di, ok := e.(AndroidNativeBufferExtra); ok { - return MakeAndroidNativeBufferExtraʳ(a).Set(di) - } - } - return NilAndroidNativeBufferExtraʳ -} diff --git a/gapis/api/gles/find_issues.go b/gapis/api/gles/find_issues.go deleted file mode 100644 index 66b222be46..0000000000 --- a/gapis/api/gles/find_issues.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "strings" - - "github.com/google/gapid/core/data/binary" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/text" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/replay/value" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/shadertools" -) - -// findIssues is a command transform that detects issues when replaying the -// stream of commands. Any issues that are found are written to all the chans in -// the slice out. Once the last issue is sent (if any) all the chans in out are -// closed. -type findIssues struct { - replay.EndOfReplay - state *api.GlobalState - device *device.Instance - targetVersion *Version - issues []replay.Issue - lastGlError GLenum -} - -func newFindIssues(ctx context.Context, c *capture.GraphicsCapture, device *device.Instance) *findIssues { - targetVersion, _ := ParseVersion(device.Configuration.Drivers.Opengl.Version) - transform := &findIssues{ - state: c.NewState(ctx), - device: device, - targetVersion: targetVersion, - } - transform.state.OnError = func(err interface{}) { - if glenum, ok := err.(GLenum); ok { - transform.lastGlError = glenum - } - } - return transform -} - -func (t *findIssues) onIssue(cmd api.Cmd, id api.CmdID, s service.Severity, e error) { - if s == service.Severity_FatalLevel && isIssueWhitelisted(cmd, e) { - s = service.Severity_ErrorLevel - } - t.issues = append(t.issues, replay.Issue{Command: id, Severity: s, Error: e}) -} - -// The value 0 is used for many enums - prefer GL_NO_ERROR in this case. -func (e GLenum) ErrorString() string { - if e == GLenum_GL_NO_ERROR { - return "GL_NO_ERROR" - } - return e.String() -} - -type ErrUnexpectedDriverTraceError struct { - DriverError GLenum - ExpectedError GLenum -} - -func (e ErrUnexpectedDriverTraceError) Error() string { - return fmt.Sprintf("%s in trace driver, but we expected %s", - e.DriverError.ErrorString(), e.ExpectedError.ErrorString()) -} - -func (t *findIssues) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - ctx = log.Enter(ctx, "findIssues") - cb := CommandBuilder{Thread: cmd.Thread(), Arena: t.state.Arena} - t.lastGlError = GLenum_GL_NO_ERROR - mutateErr := cmd.Mutate(ctx, id, t.state, nil /* no builder */, nil /* no watcher */) - - mutatorsGlError := t.lastGlError - if e := FindErrorState(cmd.Extras()); e != nil { - // Check that our API file agrees with the driver which we used for tracking. - if (e.TraceDriversGlError != GLenum_GL_NO_ERROR) != (mutatorsGlError != GLenum_GL_NO_ERROR) { - errorMsg := ErrUnexpectedDriverTraceError{ - DriverError: e.TraceDriversGlError, - ExpectedError: mutatorsGlError, - } - t.onIssue(cmd, id, service.Severity_FatalLevel, errorMsg) - } - // Check that the C++ and Go versions of the generated code precisely agree. - if e.InterceptorsGlError != mutatorsGlError { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("%s in interceptor, but we expected %s", - e.InterceptorsGlError.ErrorString(), mutatorsGlError.ErrorString())) - } - } - - if mutateErr != nil { - // Ignore since downstream transform layers can only consume valid commands - // This transform want to see all possible errors, but won't propagate them up - return nil - } - - out.MutateAndWrite(ctx, id, cmd) - - dID := id.Derived() - s := GetState(t.state) - c := s.GetContext(cmd.Thread()) - if c.IsNil() { - return nil - } - - // Check the result of glGetError after every command. - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - ptr := b.AllocateTemporaryMemory(4) - b.Call(funcInfoGlGetError) - b.Store(ptr) - b.Post(ptr, 4, builder.Postback(func(r binary.Reader, err error) { - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetError postback: %v", err)) - return - } - v := GLenum(r.Uint32()) - err = r.Error() - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetError postback: %v", err)) - return - } - if v != GLenum_GL_NO_ERROR { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("%v in replay driver", v)) - } - })) - return nil - })) - - // null-terminated byte slice to string - ntbs := func(b []byte) string { - s := string(b) - for i, r := range s { - if r == 0 { - return strings.TrimSpace(s[:i]) - } - } - return strings.TrimSpace(s) - } - - switch cmd := cmd.(type) { - case *GlCompileShader: - shader := c.Objects().Shaders().Get(cmd.Shader()) - st, err := shader.Type().ShaderType() - if err != nil { - t.onIssue(cmd, id, service.Severity_ErrorLevel, err) - return nil - } - - if !t.targetVersion.IsES { - // Check we are able to convert this GLES shader to desktop GL. - opts := shadertools.ConvertOptions{ - ShaderType: st, - CheckAfterChanges: true, - Disassemble: true, - TargetGLSLVersion: 430, - } - - if _, err := shadertools.ConvertGlsl(shader.Source(), &opts); err != nil { - t.onIssue(cmd, id, service.Severity_ErrorLevel, err) - } - } - - const buflen = 8192 - tmp := t.state.AllocOrPanic(ctx, buflen) - - infoLog := make([]byte, buflen) - out.MutateAndWrite(ctx, dID, cb.GlGetShaderInfoLog(cmd.Shader(), buflen, memory.Nullptr, tmp.Ptr())) - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - b.ReserveMemory(tmp.Range()) - b.Post(value.ObservedPointer(tmp.Address()), buflen, func(r binary.Reader, err error) { - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderInfoLog postback: %v", err)) - return - } - r.Data(infoLog) - if r.Error() != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderInfoLog postback: %v", r.Error())) - } - }) - return nil - })) - - source := make([]byte, buflen) - out.MutateAndWrite(ctx, dID, cb.GlGetShaderSource(cmd.Shader(), buflen, memory.Nullptr, tmp.Ptr())) - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - b.ReserveMemory(tmp.Range()) - b.Post(value.ObservedPointer(tmp.Address()), buflen, func(r binary.Reader, err error) { - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderSource postback: %v", err)) - return - } - r.Data(source) - if r.Error() != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderSource postback: %v", r.Error())) - } - }) - return nil - })) - - out.MutateAndWrite(ctx, dID, cb.GlGetShaderiv(cmd.Shader(), GLenum_GL_COMPILE_STATUS, tmp.Ptr())) - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - b.ReserveMemory(tmp.Range()) - b.Post(value.ObservedPointer(tmp.Address()), 4, func(r binary.Reader, err error) { - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderiv postback: %v", err)) - return - } - if r.Uint32() != uint32(GLboolean_GL_TRUE) { - originalSource := "" - if shader := c.Objects().Shaders().Get(cmd.Shader()); !shader.IsNil() { - originalSource = shader.Source() - } - t.onIssue(cmd, id, service.Severity_ErrorLevel, fmt.Errorf("Shader %d failed to compile. Error:\n%v\nOriginal source:\n%s\nTranslated source:\n%s", - cmd.Shader(), ntbs(infoLog), text.LineNumber(originalSource), text.LineNumber(ntbs(source)))) - } - if r.Error() != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetShaderiv postback: %v", r.Error())) - } - }) - return nil - })) - tmp.Free() - - case *GlLinkProgram: - const buflen = 2048 - tmp := t.state.AllocOrPanic(ctx, 4+buflen) - out.MutateAndWrite(ctx, dID, cb.GlGetProgramiv(cmd.Program(), GLenum_GL_LINK_STATUS, tmp.Ptr())) - out.MutateAndWrite(ctx, dID, cb.GlGetProgramInfoLog(cmd.Program(), buflen, memory.Nullptr, tmp.Offset(4))) - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - b.ReserveMemory(tmp.Range()) - b.Post(value.ObservedPointer(tmp.Address()), 4+buflen, func(r binary.Reader, err error) { - if err != nil { - t.onIssue(cmd, id, service.Severity_FatalLevel, fmt.Errorf("Failed to decode glGetProgramiv+glGetProgrameInfoLog postback: %v", err)) - return - } - msg := make([]byte, buflen) - res := r.Uint32() - r.Data(msg) - if res != uint32(GLboolean_GL_TRUE) { - vss, fss := "", "" - if program := c.Objects().Programs().Get(cmd.Program()); !program.IsNil() { - if shader := program.Shaders().Get(GLenum_GL_VERTEX_SHADER); !shader.IsNil() { - vss = shader.Source() - } - if shader := program.Shaders().Get(GLenum_GL_FRAGMENT_SHADER); !shader.IsNil() { - fss = shader.Source() - } - } - logLevel := service.Severity_ErrorLevel - if pi := FindLinkProgramExtra(s.Arena, cmd.Extras()); !pi.IsNil() && pi.LinkStatus() == GLboolean_GL_TRUE { - // Increase severity if the program linked successfully during trace. - logLevel = service.Severity_FatalLevel - } - t.onIssue(cmd, id, logLevel, fmt.Errorf("Program %d failed to link. Error:\n%v\n"+ - "Vertex shader source:\n%sFragment shader source:\n%s", cmd.Program(), ntbs(msg), - text.LineNumber(vss), text.LineNumber(fss))) - } - }) - return nil - })) - tmp.Free() - - case *GlProgramBinary, *GlProgramBinaryOES, *GlShaderBinary: - glDev := t.device.Configuration.Drivers.Opengl - if !canUsePrecompiledShader(c, glDev) { - t.onIssue(cmd, id, service.Severity_WarningLevel, fmt.Errorf("Pre-compiled binaries cannot be used across on different devices. Capture: %s-%s, Replay: %s-%s", - c.Constants().Vendor(), c.Constants().Version(), glDev.Vendor, glDev.Version)) - } - } - return nil -} - -func (t *findIssues) Flush(ctx context.Context, out transform.Writer) error { - t.AddNotifyInstruction(ctx, out, func() interface{} { return t.issues }) - return nil -} diff --git a/gapis/api/gles/gles.api b/gapis/api/gles/gles.api deleted file mode 100644 index db30436980..0000000000 --- a/gapis/api/gles/gles.api +++ /dev/null @@ -1,933 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -api_index 1 - -import "api/android_extension_pack.api" -import "api/android_native.api" -import "api/asynchronous_queries.api" -import "api/buffer_objects.api" -import "api/constants.api" -import "api/egl.api" -import "api/eglenum.api" -import "api/errors.api" -import "api/debug.api" -import "api/draw_commands.api" -import "api/extensions.api" -import "api/extras.api" -import "api/fragment_operations.api" -import "api/framebuffer.api" -import "api/glbitfield.api" -import "api/gl.api" -import "api/glenum.api" -import "api/other.api" -import "api/image_format.api" -import "api/programs_and_shaders.api" -import "api/rasterization.api" -import "api/state_queries.api" -import "api/synchronization.api" -import "api/textures_and_samplers.api" -import "api/transform_feedback.api" -import "api/util.api" -import "api/vertex_arrays.api" -import "types.api" -import "synthetic.api" -import "gles10.api" -import "../../messages/messages.api" - -extern void mapMemory(u8[] slice) -extern void unmapMemory(u8[] slice) - -// Flags which are set if the context supports given GLES version -@internal -class SupportedVersions { - bool GLES10 = true - bool GLES20 = true - bool GLES30 = true - bool GLES31 = true - bool GLES32 = true -} - -sub ref!SupportedVersions InitSupportedVersions(ref!Context ctx) { - return new!SupportedVersions( - GLES10: VersionGreaterOrEqual(ctx, 1, 0), - GLES20: VersionGreaterOrEqual(ctx, 2, 0), - GLES30: VersionGreaterOrEqual(ctx, 3, 0), - GLES31: VersionGreaterOrEqual(ctx, 3, 1), - GLES32: VersionGreaterOrEqual(ctx, 3, 2), - ) -} - -// VersionGreaterOrEqual returns true if the context's version is greater or -// equal to the specified major-minor version. -sub bool VersionGreaterOrEqual(ref!Context ctx, GLint major, GLint minor) { - return (ctx.Constants.MajorVersion > major) || ((ctx.Constants.MajorVersion == major) && (ctx.Constants.MinorVersion >= minor)) -} - -// Flags which are set if the context supports given GLES extension -@internal -class SupportedExtensions { - bool EGL_ANDROID_create_native_client_buffer = true - bool EGL_ANDROID_image_native_buffer = true - bool EGL_ANDROID_native_fence_sync = true - bool EGL_KHR_image_base = true - bool EGL_KHR_wait_sync = true - bool GL_AMD_compressed_ATC_texture = true - bool GL_AMD_performance_monitor = true - bool GL_ANGLE_framebuffer_blit = true - bool GL_ANGLE_framebuffer_multisample = true - bool GL_ANGLE_instanced_arrays = true - bool GL_ANGLE_translated_shader_source = true - bool GL_APPLE_copy_texture_levels = true - bool GL_APPLE_framebuffer_multisample = true - bool GL_APPLE_sync = true - bool GL_EXT_base_instance = true - bool GL_EXT_blend_func_extended = true - bool GL_EXT_buffer_storage = true - bool GL_EXT_clear_texture = true - bool GL_EXT_clip_cull_distance = true - bool GL_EXT_copy_image = true - bool GL_EXT_debug_label = true - bool GL_EXT_debug_marker = true - bool GL_EXT_direct_state_access = true - bool GL_EXT_discard_framebuffer = true - bool GL_EXT_disjoint_timer_query = true - bool GL_EXT_draw_buffers = true - bool GL_EXT_draw_buffers_indexed = true - bool GL_EXT_draw_elements_base_vertex = true - bool GL_EXT_draw_instanced = true - bool GL_EXT_draw_transform_feedback = true - bool GL_EXT_EGL_image_array = true - bool GL_EXT_geometry_shader = true - bool GL_EXT_instanced_arrays = true - bool GL_EXT_map_buffer_range = true - bool GL_EXT_multi_draw_arrays = true - bool GL_EXT_multi_draw_indirect = true - bool GL_EXT_multisampled_render_to_texture = true - bool GL_EXT_multiview_draw_buffers = true - bool GL_EXT_occlusion_query_boolean = true - bool GL_EXT_polygon_offset_clamp = true - bool GL_EXT_primitive_bounding_box = true - bool GL_EXT_raster_multisample = true - bool GL_EXT_robustness = true - bool GL_EXT_separate_shader_objects = true - bool GL_EXT_shader_pixel_local_storage2 = true - bool GL_EXT_shadow_samplers = true - bool GL_EXT_sparse_texture = true - bool GL_EXT_sRGB_write_control = true - bool GL_EXT_tessellation_shader = true - bool GL_EXT_texture_border_clamp = true - bool GL_EXT_texture_buffer = true - bool GL_EXT_texture_compression_s3tc = true - bool GL_EXT_texture_filter_anisotropic = true - bool GL_EXT_texture_filter_minmax = true - bool GL_EXT_texture_format_BGRA8888 = true - bool GL_EXT_texture_norm16 = true - bool GL_EXT_texture_rg = true - bool GL_EXT_texture_sRGB_decode = true - bool GL_EXT_texture_storage = true - bool GL_EXT_texture_type_2_10_10_10_REV = true - bool GL_EXT_texture_view = true - bool GL_EXT_window_rectangles = true - bool GL_IMG_bindless_texture = true - bool GL_IMG_framebuffer_downsample = true - bool GL_IMG_multisampled_render_to_texture = true - bool GL_IMG_user_clip_plane = true - bool GL_INTEL_framebuffer_CMAA = true - bool GL_INTEL_performance_query = true - bool GL_KHR_blend_equation_advanced = true - bool GL_KHR_debug = true - bool GL_KHR_robustness = true - bool GL_NV_bindless_texture = true - bool GL_NV_blend_equation_advanced = true - bool GL_NV_conditional_render = true - bool GL_NV_conservative_raster = true - bool GL_NV_conservative_raster_pre_snap_triangles = true - bool GL_NV_copy_buffer = true - bool GL_NV_coverage_sample = true - bool GL_NV_draw_buffers = true - bool GL_NV_draw_instanced = true - bool GL_NV_fence = true - bool GL_NV_fragment_coverage_to_color = true - bool GL_NV_framebuffer_blit = true - bool GL_NV_framebuffer_mixed_samples = true - bool GL_NV_framebuffer_multisample = true - bool GL_NV_gpu_shader5 = true - bool GL_NV_instanced_arrays = true - bool GL_NV_internalformat_sample_query = true - bool GL_NV_non_square_matrices = true - bool GL_NV_path_rendering = true - bool GL_NV_polygon_mode = true - bool GL_NV_read_buffer = true - bool GL_NV_sample_locations = true - bool GL_NV_viewport_array = true - bool GL_NV_viewport_swizzle = true - bool GL_OES_EGL_image = true - bool GL_OES_EGL_image_external = true - bool GL_OES_blend_equation_separate = true - bool GL_OES_blend_func_separate = true - bool GL_OES_blend_subtract = true - bool GL_OES_compressed_ETC1_RGB8_texture = true - bool GL_OES_copy_image = true - bool GL_OES_depth_texture = true - bool GL_OES_draw_buffers_indexed = true - bool GL_OES_draw_elements_base_vertex = true - bool GL_OES_draw_texture = true - bool GL_OES_fixed_point = true - bool GL_OES_framebuffer_object = true - bool GL_OES_geometry_shader = true - bool GL_OES_get_program_binary = true - bool GL_OES_mapbuffer = true - bool GL_OES_matrix_palette = true - bool GL_OES_packed_depth_stencil = true - bool GL_OES_point_size_array = true - bool GL_OES_primitive_bounding_box = true - bool GL_OES_query_matrix = true - bool GL_OES_sample_shading = true - bool GL_OES_single_precision = true - bool GL_OES_tessellation_shader = true - bool GL_OES_texture_3D = true - bool GL_OES_texture_border_clamp = true - bool GL_OES_texture_buffer = true - bool GL_OES_texture_cube_map = true - bool GL_OES_texture_float = true - bool GL_OES_texture_half_float = true - bool GL_OES_texture_stencil8 = true - bool GL_OES_texture_storage_multisample_2d_array = true - bool GL_OES_texture_view = true - bool GL_OES_vertex_array_object = true - bool GL_OES_vertex_half_float = true - bool GL_OES_viewport_array = true - bool GL_OVR_multiview = true - bool GL_OVR_multiview_multisampled_render_to_texture = true - bool GL_QCOM_alpha_test = true - bool GL_QCOM_driver_control = true - bool GL_QCOM_extended_get = true - bool GL_QCOM_extended_get2 = true - bool GL_QCOM_tiled_rendering = true -} - -sub ref!SupportedExtensions InitSupportedExtensions(ref!Context ctx) { - set := StringSet() - for _ , _ , ext in ctx.Constants.Extensions { - set.Strings[ext] = true - } - return new!SupportedExtensions( - EGL_ANDROID_create_native_client_buffer: set.Strings["EGL_ANDROID_create_native_client_buffer"], - EGL_ANDROID_image_native_buffer: set.Strings["EGL_ANDROID_image_native_buffer"], - EGL_KHR_image_base: set.Strings["EGL_KHR_image_base"], - GL_AMD_compressed_ATC_texture: set.Strings["GL_AMD_compressed_ATC_texture"], - GL_AMD_performance_monitor: set.Strings["GL_AMD_performance_monitor"], - GL_ANGLE_framebuffer_blit: set.Strings["GL_ANGLE_framebuffer_blit"], - GL_ANGLE_framebuffer_multisample: set.Strings["GL_ANGLE_framebuffer_multisample"], - GL_ANGLE_instanced_arrays: set.Strings["GL_ANGLE_instanced_arrays"], - GL_ANGLE_translated_shader_source: set.Strings["GL_ANGLE_translated_shader_source"], - GL_APPLE_copy_texture_levels: set.Strings["GL_APPLE_copy_texture_levels"], - GL_APPLE_framebuffer_multisample: set.Strings["GL_APPLE_framebuffer_multisample"], - GL_APPLE_sync: set.Strings["GL_APPLE_sync"], - GL_EXT_base_instance: set.Strings["GL_EXT_base_instance"], - GL_EXT_blend_func_extended: set.Strings["GL_EXT_blend_func_extended"], - GL_EXT_buffer_storage: set.Strings["GL_EXT_buffer_storage"], - GL_EXT_clear_texture: set.Strings["GL_EXT_clear_texture"], - GL_EXT_clip_cull_distance: set.Strings["GL_EXT_clip_cull_distance"], - GL_EXT_copy_image: set.Strings["GL_EXT_copy_image"], - GL_EXT_debug_label: set.Strings["GL_EXT_debug_label"], - GL_EXT_debug_marker: set.Strings["GL_EXT_debug_marker"], - GL_EXT_direct_state_access: set.Strings["GL_EXT_direct_state_access"], - GL_EXT_discard_framebuffer: set.Strings["GL_EXT_discard_framebuffer"], - GL_EXT_disjoint_timer_query: set.Strings["GL_EXT_disjoint_timer_query"], - GL_EXT_draw_buffers: set.Strings["GL_EXT_draw_buffers"], - GL_EXT_draw_buffers_indexed: set.Strings["GL_EXT_draw_buffers_indexed"], - GL_EXT_draw_elements_base_vertex: set.Strings["GL_EXT_draw_elements_base_vertex"], - GL_EXT_draw_instanced: set.Strings["GL_EXT_draw_instanced"], - GL_EXT_draw_transform_feedback: set.Strings["GL_EXT_draw_transform_feedback"], - GL_EXT_EGL_image_array: set.Strings["GL_EXT_EGL_image_array"], - GL_EXT_geometry_shader: set.Strings["GL_EXT_geometry_shader"], - GL_EXT_instanced_arrays: set.Strings["GL_EXT_instanced_arrays"], - GL_EXT_map_buffer_range: set.Strings["GL_EXT_map_buffer_range"], - GL_EXT_multi_draw_arrays: set.Strings["GL_EXT_multi_draw_arrays"], - GL_EXT_multi_draw_indirect: set.Strings["GL_EXT_multi_draw_indirect"], - GL_EXT_multisampled_render_to_texture: set.Strings["GL_EXT_multisampled_render_to_texture"], - GL_EXT_multiview_draw_buffers: set.Strings["GL_EXT_multiview_draw_buffers"], - GL_EXT_occlusion_query_boolean: set.Strings["GL_EXT_occlusion_query_boolean"], - GL_EXT_polygon_offset_clamp: set.Strings["GL_EXT_polygon_offset_clamp"], - GL_EXT_primitive_bounding_box: set.Strings["GL_EXT_primitive_bounding_box"], - GL_EXT_raster_multisample: set.Strings["GL_EXT_raster_multisample"], - GL_EXT_robustness: set.Strings["GL_EXT_robustness"], - GL_EXT_sRGB_write_control: set.Strings["GL_EXT_sRGB_write_control"], - GL_EXT_separate_shader_objects: set.Strings["GL_EXT_separate_shader_objects"], - GL_EXT_shader_pixel_local_storage2: set.Strings["GL_EXT_shader_pixel_local_storage2"], - GL_EXT_shadow_samplers: set.Strings["GL_EXT_shadow_samplers"], - GL_EXT_sparse_texture: set.Strings["GL_EXT_sparse_texture"], - GL_EXT_tessellation_shader: set.Strings["GL_EXT_tessellation_shader"], - GL_EXT_texture_border_clamp: set.Strings["GL_EXT_texture_border_clamp"], - GL_EXT_texture_buffer: set.Strings["GL_EXT_texture_buffer"], - GL_EXT_texture_compression_s3tc: set.Strings["GL_EXT_texture_compression_s3tc"], - GL_EXT_texture_filter_anisotropic: set.Strings["GL_EXT_texture_filter_anisotropic"], - GL_EXT_texture_filter_minmax: set.Strings["GL_EXT_texture_filter_minmax"], - GL_EXT_texture_format_BGRA8888: set.Strings["GL_EXT_texture_format_BGRA8888"], - GL_EXT_texture_norm16: set.Strings["GL_EXT_texture_norm16"], - GL_EXT_texture_rg: set.Strings["GL_EXT_texture_rg"], - GL_EXT_texture_sRGB_decode: set.Strings["GL_EXT_texture_sRGB_decode"], - GL_EXT_texture_storage: set.Strings["GL_EXT_texture_storage"], - GL_EXT_texture_type_2_10_10_10_REV: set.Strings["GL_EXT_texture_type_2_10_10_10_REV"], - GL_EXT_texture_view: set.Strings["GL_EXT_texture_view"], - GL_EXT_window_rectangles: set.Strings["GL_EXT_window_rectangles"], - GL_IMG_bindless_texture: set.Strings["GL_IMG_bindless_texture"], - GL_IMG_framebuffer_downsample: set.Strings["GL_IMG_framebuffer_downsample"], - GL_IMG_multisampled_render_to_texture: set.Strings["GL_IMG_multisampled_render_to_texture"], - GL_IMG_user_clip_plane: set.Strings["GL_IMG_user_clip_plane"], - GL_INTEL_framebuffer_CMAA: set.Strings["GL_INTEL_framebuffer_CMAA"], - GL_INTEL_performance_query: set.Strings["GL_INTEL_performance_query"], - GL_KHR_blend_equation_advanced: set.Strings["GL_KHR_blend_equation_advanced"], - GL_KHR_debug: set.Strings["GL_KHR_debug"], - GL_KHR_robustness: set.Strings["GL_KHR_robustness"], - GL_NV_bindless_texture: set.Strings["GL_NV_bindless_texture"], - GL_NV_blend_equation_advanced: set.Strings["GL_NV_blend_equation_advanced"], - GL_NV_conditional_render: set.Strings["GL_NV_conditional_render"], - GL_NV_conservative_raster: set.Strings["GL_NV_conservative_raster"], - GL_NV_conservative_raster_pre_snap_triangles: set.Strings["GL_NV_conservative_raster_pre_snap_triangles"], - GL_NV_copy_buffer: set.Strings["GL_NV_copy_buffer"], - GL_NV_coverage_sample: set.Strings["GL_NV_coverage_sample"], - GL_NV_draw_buffers: set.Strings["GL_NV_draw_buffers"], - GL_NV_draw_instanced: set.Strings["GL_NV_draw_instanced"], - GL_NV_fence: set.Strings["GL_NV_fence"], - GL_NV_fragment_coverage_to_color: set.Strings["GL_NV_fragment_coverage_to_color"], - GL_NV_framebuffer_blit: set.Strings["GL_NV_framebuffer_blit"], - GL_NV_framebuffer_mixed_samples: set.Strings["GL_NV_framebuffer_mixed_samples"], - GL_NV_framebuffer_multisample: set.Strings["GL_NV_framebuffer_multisample"], - GL_NV_gpu_shader5: set.Strings["GL_NV_gpu_shader5"], - GL_NV_instanced_arrays: set.Strings["GL_NV_instanced_arrays"], - GL_NV_internalformat_sample_query: set.Strings["GL_NV_internalformat_sample_query"], - GL_NV_non_square_matrices: set.Strings["GL_NV_non_square_matrices"], - GL_NV_path_rendering: set.Strings["GL_NV_path_rendering"], - GL_NV_polygon_mode: set.Strings["GL_NV_polygon_mode"], - GL_NV_read_buffer: set.Strings["GL_NV_read_buffer"], - GL_NV_sample_locations: set.Strings["GL_NV_sample_locations"], - GL_NV_viewport_array: set.Strings["GL_NV_viewport_array"], - GL_NV_viewport_swizzle: set.Strings["GL_NV_viewport_swizzle"], - GL_OES_EGL_image: set.Strings["GL_OES_EGL_image"], - GL_OES_EGL_image_external: set.Strings["GL_OES_EGL_image_external"], - GL_OES_blend_equation_separate: set.Strings["GL_OES_blend_equation_separate"], - GL_OES_blend_func_separate: set.Strings["GL_OES_blend_func_separate"], - GL_OES_blend_subtract: set.Strings["GL_OES_blend_subtract"], - GL_OES_compressed_ETC1_RGB8_texture: set.Strings["GL_OES_compressed_ETC1_RGB8_texture"], - GL_OES_copy_image: set.Strings["GL_OES_copy_image"], - GL_OES_depth_texture: set.Strings["GL_OES_depth_texture"], - GL_OES_draw_buffers_indexed: set.Strings["GL_OES_draw_buffers_indexed"], - GL_OES_draw_elements_base_vertex: set.Strings["GL_OES_draw_elements_base_vertex"], - GL_OES_draw_texture: set.Strings["GL_OES_draw_texture"], - GL_OES_fixed_point: set.Strings["GL_OES_fixed_point"], - GL_OES_framebuffer_object: set.Strings["GL_OES_framebuffer_object"], - GL_OES_geometry_shader: set.Strings["GL_OES_geometry_shader"], - GL_OES_get_program_binary: set.Strings["GL_OES_get_program_binary"], - GL_OES_mapbuffer: set.Strings["GL_OES_mapbuffer"], - GL_OES_matrix_palette: set.Strings["GL_OES_matrix_palette"], - GL_OES_packed_depth_stencil: set.Strings["GL_OES_packed_depth_stencil"], - GL_OES_point_size_array: set.Strings["GL_OES_point_size_array"], - GL_OES_primitive_bounding_box: set.Strings["GL_OES_primitive_bounding_box"], - GL_OES_query_matrix: set.Strings["GL_OES_query_matrix"], - GL_OES_sample_shading: set.Strings["GL_OES_sample_shading"], - GL_OES_single_precision: set.Strings["GL_OES_single_precision"], - GL_OES_tessellation_shader: set.Strings["GL_OES_tessellation_shader"], - GL_OES_texture_3D: set.Strings["GL_OES_texture_3D"], - GL_OES_texture_border_clamp: set.Strings["GL_OES_texture_border_clamp"], - GL_OES_texture_buffer: set.Strings["GL_OES_texture_buffer"], - GL_OES_texture_cube_map: set.Strings["GL_OES_texture_cube_map"], - GL_OES_texture_float: set.Strings["GL_OES_texture_float"], - GL_OES_texture_half_float: set.Strings["GL_OES_texture_half_float"], - GL_OES_texture_stencil8: set.Strings["GL_OES_texture_stencil8"], - GL_OES_texture_storage_multisample_2d_array: set.Strings["GL_OES_texture_storage_multisample_2d_array"], - GL_OES_texture_view: set.Strings["GL_OES_texture_view"], - GL_OES_vertex_array_object: set.Strings["GL_OES_vertex_array_object"], - GL_OES_vertex_half_float: set.Strings["GL_OES_vertex_half_float"], - GL_OES_viewport_array: set.Strings["GL_OES_viewport_array"], - GL_OVR_multiview: set.Strings["GL_OVR_multiview"], - GL_OVR_multiview_multisampled_render_to_texture: set.Strings["GL_OVR_multiview_multisampled_render_to_texture"], - GL_QCOM_alpha_test: set.Strings["GL_QCOM_alpha_test"], - GL_QCOM_driver_control: set.Strings["GL_QCOM_driver_control"], - GL_QCOM_extended_get: set.Strings["GL_QCOM_extended_get"], - GL_QCOM_extended_get2: set.Strings["GL_QCOM_extended_get2"], - GL_QCOM_tiled_rendering: set.Strings["GL_QCOM_tiled_rendering"], - ) -} - -@internal -class StringSet { - map!(string, bool) Strings -} - -@internal -class Color { - GLfloat Red - GLfloat Green - GLfloat Blue - GLfloat Alpha -} - -@internal -class Rect { - GLint X - GLint Y - GLsizei Width - GLsizei Height -} - -@internal type GLboolean[4] Vec4b -@internal type GLint[1] Vec1i -@internal type GLint[2] Vec2i -@internal type GLint[3] Vec3i -@internal type GLint[4] Vec4i -@internal type GLuint[2] Vec2u -@internal type GLuint[3] Vec3u -@internal type GLuint[4] Vec4u -@internal type GLfloat[1] Vec1f -@internal type GLfloat[2] Vec2f -@internal type GLfloat[3] Vec3f -@internal type GLfloat[4] Vec4f -@internal type Vec2f[2] Mat2f -@internal type Vec3f[2] Mat2x3f -@internal type Vec4f[2] Mat2x4f -@internal type Vec2f[3] Mat3x2f -@internal type Vec3f[3] Mat3f -@internal type Vec4f[3] Mat3x4f -@internal type Vec2f[4] Mat4x2f -@internal type Vec3f[4] Mat4x3f -@internal type Vec4f[4] Mat4f - -///////////////////////////////////////////////////////////////// -// State -///////////////////////////////////////////////////////////////// - -@replay_remap type GLuint RenderbufferId -@replay_remap type GLuint TextureId -@replay_remap type GLuint FramebufferId -@replay_remap type GLuint BufferId -@replay_remap type GLuint ShaderId -@replay_remap type GLuint ProgramId -@replay_remap type GLuint VertexArrayId -@replay_remap type GLuint QueryId -@replay_remap type GLint UniformLocation -type GLuint UniformIndex -type GLuint AttributeLocation -type GLuint AttributeIndex -type GLuint TextureUnitId -type GLuint ImageUnitId -@replay_remap type GLuint SamplerId -@replay_remap type GLuint PipelineId -@replay_remap type GLuint UniformBlockIndex -@replay_remap type GLuint TransformFeedbackId -@replay_remap type GLuint SrcImageId -@replay_remap type GLuint DstImageId - -@replay_custom_value type const void* IndicesPointer -@replay_custom_value type const void* VertexPointer -@replay_custom_value type const void* TexturePointer -@replay_custom_value type const void* BufferDataPointer - -@internal -class DefaultObjects { - ref!Framebuffer Framebuffer - ref!VertexArray VertexArray - ref!TransformFeedback TransformFeedback - ref!Texture Texture2d - ref!Texture Texture2dArray - ref!Texture Texture2dMultisample - ref!Texture Texture2dMultisampleArray - ref!Texture Texture3d - ref!Texture TextureBuffer - ref!Texture TextureCubeMap - ref!Texture TextureCubeMapArray - ref!Texture TextureExternalOes -} - -// Objects which are never shared between contexts. -@internal -class Objects { - GeneratedObjectNames GeneratedNames - DefaultObjects Default - @handleMap map!(BufferId, ref!Buffer) Buffers - @handleMap map!(FramebufferId, ref!Framebuffer) Framebuffers - @handleMap map!(ImageUnitId, ref!ImageUnit) ImageUnits - @handleMap map!(PipelineId, ref!Pipeline) Pipelines - @handleMap map!(ProgramId, ref!Program) Programs - @handleMap map!(QueryId, ref!Query) Queries - @handleMap map!(RenderbufferId, ref!Renderbuffer) Renderbuffers - @handleMap map!(SamplerId, ref!Sampler) Samplers - @handleMap map!(ShaderId, ref!Shader) Shaders - @handleMap map!(GLsync, ref!SyncObject) SyncObjects - @handleMap map!(TextureUnitId, ref!TextureUnit) TextureUnits - @handleMap map!(TextureId, ref!Texture) Textures - @handleMap map!(TransformFeedbackId, ref!TransformFeedback) TransformFeedbacks - @handleMap map!(VertexArrayId, ref!VertexArray) VertexArrays -} - -@internal -class GeneratedObjectNames { - map!(BufferId, bool) Buffers - map!(FramebufferId, bool) Framebuffers - map!(PipelineId, bool) Pipelines - map!(QueryId, bool) Queries - map!(RenderbufferId, bool) Renderbuffers - map!(SamplerId, bool) Samplers - map!(TextureId, bool) Textures - map!(TransformFeedbackId, bool) TransformFeedbacks - map!(VertexArrayId, bool) VertexArrays -} - -@internal type s32 ContextID - -// ShareList represents a set of contexts which share some of the objects. -// NB: Sharing does not form a tree. Any of the contexts can be destroyed. -@internal -class ShareList { - map!(ContextID, ref!Context) Contexts -} - -@internal -class Bindings { - ref!Buffer ArrayBuffer - ref!Buffer AtomicCounterBuffer - map!(GLuint, BufferBinding) AtomicCounterBuffers - ref!Buffer CopyReadBuffer - ref!Buffer CopyWriteBuffer - ref!Buffer DispatchIndirectBuffer - ref!Framebuffer DrawFramebuffer - ref!Buffer DrawIndirectBuffer - ref!Buffer PixelPackBuffer - ref!Buffer PixelUnpackBuffer - ref!Pipeline Pipeline - ref!Program Program - ref!Framebuffer ReadFramebuffer - ref!Renderbuffer Renderbuffer - ref!Buffer ShaderStorageBuffer - map!(GLuint, BufferBinding) ShaderStorageBuffers - ref!Buffer TextureBuffer - ref!TextureUnit TextureUnit - ref!TransformFeedback TransformFeedback - ref!Buffer TransformFeedbackBuffer - ref!Buffer UniformBuffer - map!(GLuint, BufferBinding) UniformBuffers - ref!VertexArray VertexArray -} - -@internal -class BufferBinding { - ref!Buffer Binding - GLintptr Start - GLsizeiptr Size -} - -@internal -class VertexState { - @unused map!(AttributeLocation, VertexAttributeValue) Attributes - - // Table 21.2: Current Values and Associated Data - @unused GLint PatchVertices = 3 - - // Table 21.4: Vertex Array Data (not in vertex array objects) - GLboolean PrimitiveRestartFixedIndex = GL_FALSE -} - -@internal -class OtherState { - ref!SupportedVersions SupportedVersions - ref!SupportedExtensions SupportedExtensions - - bool Initialized - u64 BoundOnThread - string ThreadName - @unused bool PreserveBuffersOnSwap - ref!ShareList ShareList - bool Destroyed - - DebugState Debug - map!(GLenum, ref!Query) ActiveQueries - PixelStorageState Pack - PixelStorageState Unpack - - // Table 21.38: Hints - GLenum GenerateMipmapHint = GL_DONT_CARE - @unused GLenum FragmentShaderDerivativeHint = GL_DONT_CARE - - @hidden ref!StaticContextState StaticStateExtra // Internal. - @hidden ref!DynamicContextState DynamicStateExtra // Internal. -} - -@internal -class Context { - ContextID Identifier - Constants Constants - Bindings Bound - Objects Objects - VertexState Vertex - RasterizationState Rasterization - PixelState Pixel - OtherState Other -} - - -// Globals -ContextID NextContextID -map!(u64, ref!Context) Contexts - -// Internal "thread-local" globals for quick access the current context. -// They are set in the preMutate() function before any command is mutated. -// TODO: We also need to set them in gapii (i.e. native mutate) -ref!Context CurrentContext // = Contexts[$Thread] -ref!SupportedVersions Version // = Contexts[$Thread].Other.SupportedVersions -ref!SupportedExtensions Extension // = Contexts[$Thread].Other.SupportedExtensions - -sub ref!Context GetContext() { - context := Contexts[$Thread] - if context == null { - _ = newMsg(SEVERITY_ERROR, new!ERR_NO_CONTEXT_BOUND(thread: $Thread)) - abort - } - return context -} - -sub void SetContext(ref!Context newContext) { - oldContext := Contexts[$Thread] - if oldContext != null { - oldContext.Other.BoundOnThread = 0 - } - Contexts[$Thread] = newContext - CurrentContext = newContext - if newContext != null { - newContext.Other.BoundOnThread = $Thread - } -} - -sub ref!Context CreateContext(ref!Context sharedContext) { - identifier := NextContextID - NextContextID = NextContextID + 1 - - ctx := new!Context(Identifier: identifier) - - if sharedContext != null { - ctx.Other.ShareList = sharedContext.Other.ShareList - } else { - ctx.Other.ShareList = new!ShareList() - } - ctx.Other.ShareList.Contexts[identifier] = ctx - - // Objects which can be shared between contexts. - // See: Chapter 5 - "Shared Objects and Multiple Contexts" - // We implement it by sharing reference to the object maps. - if sharedContext != null { - ctx.Objects.GeneratedNames.Renderbuffers = sharedContext.Objects.GeneratedNames.Renderbuffers - ctx.Objects.GeneratedNames.Textures = sharedContext.Objects.GeneratedNames.Textures - ctx.Objects.GeneratedNames.Buffers = sharedContext.Objects.GeneratedNames.Buffers - ctx.Objects.GeneratedNames.Samplers = sharedContext.Objects.GeneratedNames.Samplers - - ctx.Objects.Renderbuffers = sharedContext.Objects.Renderbuffers - ctx.Objects.Textures = sharedContext.Objects.Textures - ctx.Objects.Buffers = sharedContext.Objects.Buffers - ctx.Objects.Samplers = sharedContext.Objects.Samplers - ctx.Objects.Shaders = sharedContext.Objects.Shaders - ctx.Objects.Programs = sharedContext.Objects.Programs - ctx.Objects.SyncObjects = sharedContext.Objects.SyncObjects - } - - return ctx -} - -sub void ApplyStaticContextState(ref!Context ctx, ref!StaticContextState staticState) { - if (staticState != null) { - // First initialization for the context. - ctx.Constants = staticState.Constants - ctx.Other.ThreadName = staticState.ThreadName - ctx.Other.SupportedVersions = InitSupportedVersions(ctx) - ctx.Other.SupportedExtensions = InitSupportedExtensions(ctx) - Version = ctx.Other.SupportedVersions - Extension = ctx.Other.SupportedExtensions - - ctx.Objects.Default.Framebuffer = new!Framebuffer(ID: 0,ReadBuffer: GL_BACK) - ctx.Objects.Framebuffers[0] = ctx.Objects.Default.Framebuffer - ctx.Bound.DrawFramebuffer = ctx.Objects.Default.Framebuffer - ctx.Bound.ReadFramebuffer = ctx.Objects.Default.Framebuffer - - ctx.Objects.Default.TransformFeedback = new!TransformFeedback(ID: 0) - for i in as!GLuint(0) .. as!GLuint(ctx.Constants.MaxTransformFeedbackSeparateAttribs) { - ctx.Objects.Default.TransformFeedback.Buffers[i] = BufferBinding() - } - ctx.Objects.TransformFeedbacks[0] = ctx.Objects.Default.TransformFeedback - ctx.Bound.TransformFeedback = ctx.Objects.Default.TransformFeedback - - ctx.Objects.Default.VertexArray = NewVertexArray(0) - ctx.Objects.VertexArrays[0] = ctx.Objects.Default.VertexArray - ctx.Bound.VertexArray = ctx.Objects.Default.VertexArray - - ctx.Objects.Default.Texture2d = new!Texture(ID: 0,Kind: GL_TEXTURE_2D) - ctx.Objects.Default.Texture2dArray = new!Texture(ID: 0,Kind: GL_TEXTURE_2D_ARRAY) - ctx.Objects.Default.Texture2dMultisample = new!Texture(ID: 0,Kind: GL_TEXTURE_2D_MULTISAMPLE) - ctx.Objects.Default.Texture2dMultisampleArray = new!Texture(ID: 0,Kind: GL_TEXTURE_2D_MULTISAMPLE_ARRAY) - ctx.Objects.Default.Texture3d = new!Texture(ID: 0,Kind: GL_TEXTURE_3D) - ctx.Objects.Default.TextureBuffer = new!Texture(ID: 0,Kind: GL_TEXTURE_BUFFER) - ctx.Objects.Default.TextureCubeMap = new!Texture(ID: 0,Kind: GL_TEXTURE_CUBE_MAP) - ctx.Objects.Default.TextureCubeMapArray = new!Texture(ID: 0,Kind: GL_TEXTURE_CUBE_MAP_ARRAY) - ctx.Objects.Default.TextureExternalOes = new!Texture(ID: 0,Kind: GL_TEXTURE_EXTERNAL_OES) - - backbuffer := ctx.Objects.Framebuffers[0] - backbuffer.ColorAttachments[0] = FramebufferAttachment( - Type: GL_RENDERBUFFER, - Renderbuffer: new!Renderbuffer(ID: 0), - ) - backbuffer.DrawBuffer[0] = GL_BACK // TODO: Or NONE if there is no draw surface - for i in (as!GLint(1) .. ctx.Constants.MaxDrawBuffers) { - backbuffer.DrawBuffer[i] = GL_NONE - } - backbuffer.ReadBuffer = GL_BACK // TODO: Or NONE if there is no draw surface - - backbuffer.DepthAttachment = FramebufferAttachment( - Type: GL_RENDERBUFFER, - Renderbuffer: new!Renderbuffer(ID: 0), - ) - - backbuffer.StencilAttachment = FramebufferAttachment( - Type: GL_RENDERBUFFER, - Renderbuffer: new!Renderbuffer(ID: 0), - ) - - for i in 0 .. as!AttributeLocation(staticState.Constants.MaxVertexAttribs) { - v := make!Vec4f(1) - v[0] = Vec4f(0.0, 0.0, 0.0, 1.0) - ctx.Vertex.Attributes[i] = VertexAttributeValue(Value: as!u8[](v)) - } - - for i in 0 .. as!TextureUnitId(staticState.Constants.MaxCombinedTextureImageUnits) { - ctx.Objects.TextureUnits[i] = NewTextureUnit(i) - } - ctx.Bound.TextureUnit = ctx.Objects.TextureUnits[0] - - for i in 0 .. as!ImageUnitId(staticState.Constants.MaxImageUnits) { - ctx.Objects.ImageUnits[i] = new!ImageUnit(ID: i) - } - - for i in 0 .. as!GLuint(ctx.Constants.MaxSampleMaskWords) { - ctx.Rasterization.SampleMaskValue[i] = as!GLbitfield(as!GLuint(0xFFFFFFFF)) - } - - for i in (0 .. as!DrawBufferIndex(ctx.Constants.MaxDrawBuffers)) { - ctx.Pixel.Blend[i] = new!BlendState() - ctx.Pixel.ColorWritemask[i] = Mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) - } - - for i in (0 .. as!GLuint(ctx.Constants.MaxAtomicCounterBufferBindings)) { - ctx.Bound.AtomicCounterBuffers[i] = BufferBinding() - } - for i in (0 .. as!GLuint(ctx.Constants.MaxShaderStorageBufferBindings)) { - ctx.Bound.ShaderStorageBuffers[i] = BufferBinding() - } - for i in (0 .. as!GLuint(ctx.Constants.MaxUniformBufferBindings)) { - ctx.Bound.UniformBuffers[i] = BufferBinding() - } - - ctx.Other.Initialized = true - ctx.Other.StaticStateExtra = staticState - } -} - -sub void ApplyDynamicContextState(ref!Context ctx, ref!DynamicContextState dynamicState, bool resetViewportScissor) { - if (dynamicState != null) { - backbuffer := ctx.Objects.Framebuffers[0] - - width := dynamicState.BackbufferWidth - height := dynamicState.BackbufferHeight - - backbuffer.ColorAttachments[0].Renderbuffer.Image = new!Image( - Width: dynamicState.BackbufferWidth, - Height: dynamicState.BackbufferHeight, - SizedFormat: dynamicState.BackbufferColorFmt, - ) - colorFmtInfo := GetSizedFormatInfo(dynamicState.BackbufferColorFmt) - colorImageSize := uncompressedImageSize(width, height, colorFmtInfo.UnsizedFormat, colorFmtInfo.DataType) - backbuffer.ColorAttachments[0].Renderbuffer.Image.Data = make!u8(colorImageSize) - - backbuffer.DepthAttachment.Renderbuffer.Image = new!Image( - Width: dynamicState.BackbufferWidth, - Height: dynamicState.BackbufferHeight, - SizedFormat: dynamicState.BackbufferDepthFmt, - ) - depthFmtInfo := GetSizedFormatInfo(dynamicState.BackbufferDepthFmt) - depthImageSize := uncompressedImageSize(width, height, depthFmtInfo.UnsizedFormat, depthFmtInfo.DataType) - backbuffer.DepthAttachment.Renderbuffer.Image.Data = make!u8(depthImageSize) - - backbuffer.StencilAttachment.Renderbuffer.Image = new!Image( - Width: dynamicState.BackbufferWidth, - Height: dynamicState.BackbufferHeight, - SizedFormat: dynamicState.BackbufferStencilFmt, - ) - stencilFmtInfo := GetSizedFormatInfo(dynamicState.BackbufferStencilFmt) - stencilImageSize := uncompressedImageSize(width, height, stencilFmtInfo.UnsizedFormat, stencilFmtInfo.DataType) - backbuffer.StencilAttachment.Renderbuffer.Image.Data = make!u8(stencilImageSize) - - if resetViewportScissor { - ctx.Pixel.Scissor.Box.Width = dynamicState.BackbufferWidth - ctx.Pixel.Scissor.Box.Height = dynamicState.BackbufferHeight - ctx.Rasterization.Viewport.Width = dynamicState.BackbufferWidth - ctx.Rasterization.Viewport.Height = dynamicState.BackbufferHeight - } - - ctx.Other.PreserveBuffersOnSwap = dynamicState.PreserveBuffersOnSwap - ctx.Other.DynamicStateExtra = dynamicState - } -} - -///////////////////////////////////////////////////////////////// -// GLX APIs -///////////////////////////////////////////////////////////////// -type void* GLXContext -type void* GLXDrawable -type int Bool - -map!(GLXContext, ref!Context) GLXContexts - -@custom @no_replay -cmd GLXContext glXCreateContext(void* dpy, void* vis, GLXContext shareList, bool direct) { - context := ? - GLXContexts[context] = CreateContext(GLXContexts[shareList]) - return context -} - -@custom @no_replay -cmd GLXContext glXCreateNewContext(void* display, void* fbconfig, u32 type, GLXContext shared, bool direct) { - context := ? - GLXContexts[context] = CreateContext(GLXContexts[shared]) - return context -} - -@custom @no_replay -cmd Bool glXMakeContextCurrent(void* display, GLXDrawable draw, GLXDrawable read, GLXContext ctx) { - SetContext(GLXContexts[ctx]) - return ? -} - -@no_replay -cmd Bool glXMakeCurrent(void* display, GLXDrawable drawable, GLXContext ctx) { - SetContext(GLXContexts[ctx]) - return ? -} - -@no_replay -@frame_start -cmd void glXSwapBuffers(void* display, GLXDrawable drawable) { -} - -@no_replay -cmd int glXQueryDrawable(void* display, GLXDrawable draw, int attribute, int* value) { - value[0] = ? - return ? -} - -///////////////////////////////////////////////////////////////// -// WGL APIs -///////////////////////////////////////////////////////////////// -type void* HGLRC -type void* HDC -type int BOOL - -map!(HGLRC, ref!Context) WGLContexts - -@custom @no_replay -///http://msdn.microsoft.com/en-us/library/windows/desktop/dd374379(v=vs.85).aspx -cmd HGLRC wglCreateContext(HDC hdc) { - context := ? - WGLContexts[context] = CreateContext(null) - return context -} - -@custom @no_replay -///http://www.opengl.org/registry/specs/ARB/wgl_create_context.txt -cmd HGLRC wglCreateContextAttribsARB(HDC hdc, HGLRC hShareContext, int* attribList) { - context := ? - WGLContexts[context] = CreateContext(WGLContexts[hShareContext]) - return context -} - -@custom @no_replay -///http://msdn.microsoft.com/en-us/library/windows/desktop/dd374387(v=vs.85).aspx -cmd BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc) { - SetContext(WGLContexts[hglrc]) - return ? -} - -@no_replay -@frame_start -///http://msdn.microsoft.com/en-us/library/dd369060(v=vs.85) -cmd void wglSwapBuffers(HDC hdc) { } - -///////////////////////////////////////////////////////////////// -// CGL APIs -///////////////////////////////////////////////////////////////// -type int CGLError -type void* CGLTexelFormatObj -type void* CGLContextObj -type void* CGSConnectionID -type s32 CGSWindowID -type s32 CGSSurfaceID - -map!(CGLContextObj, ref!Context) CGLContexts - -@custom @no_replay -///http://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGL_OpenGL/index.html#//apple_ref/c/func/CGLCreateContext -cmd CGLError CGLCreateContext(CGLTexelFormatObj pix, CGLContextObj share, CGLContextObj* ctx) { - context := ? - CGLContexts[context] = CreateContext(CGLContexts[share]) - ctx[0] = context - return ? -} - -@custom @no_replay -cmd CGLError CGLSetCurrentContext(CGLContextObj ctx) { - SetContext(CGLContexts[ctx]) - return ? -} - -@no_replay -cmd int CGLGetSurface(CGLContextObj ctx, CGSConnectionID* cid, CGSWindowID* wid, CGSSurfaceID* sid) { - cid[0] = ? - wid[0] = ? - sid[0] = ? - return ? -} - -@no_replay -cmd int CGSGetSurfaceBounds(CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid, f64* bounds) { - write(bounds[0:4]) - return ? -} - -@no_replay -@frame_start -cmd CGLError CGLFlushDrawable(CGLContextObj ctx) { - return ? -} - - -///////////////////////////////////////////////////////////////// -// GLES 2 APIs -///////////////////////////////////////////////////////////////// - -sub u32 IndexSize(GLenum indices_type) { - return switch (indices_type) { - case GL_UNSIGNED_BYTE: 1 - case GL_UNSIGNED_SHORT: 2 - case GL_UNSIGNED_INT: 4 - } -} - -@internal class u32Limits { u32 first u32 count } -extern u32Limits IndexLimits(u8[] indices, s32 sizeof_index) diff --git a/gapis/api/gles/gles.go b/gapis/api/gles/gles.go deleted file mode 100644 index b7e76a8b1b..0000000000 --- a/gapis/api/gles/gles.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "strings" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/stream" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/messages" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/resolve/dependencygraph" - "github.com/google/gapid/gapis/service/path" -) - -type customState struct{} - -func (customState) init(*State) {} - -func GetContext(s *api.GlobalState, thread uint64) Contextʳ { - return GetState(s).GetContext(thread) -} - -func (s *State) GetContext(thread uint64) Contextʳ { - return s.Contexts().Get(thread) -} - -// Root returns the path to the root of the state to display. It can vary based -// on filtering mode. Returning nil, nil indicates there is no state to show at -// this point in the capture. -func (s *State) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) (path.Node, error) { - if p.Context == nil || !p.Context.IsValid() { - return p, nil - } - c, err := resolve.Context(ctx, p.After.Capture.Context(p.Context.ID()), r) - if err != nil { - return nil, err - } - for thread, context := range s.Contexts().All() { - if c.ID == context.ID() { - return s.contextRoot(p.After, thread), nil - } - } - return nil, nil -} - -// SetupInitialState sanitizes deserialized state to make it valid. -// It can fill in any derived data which we choose not to serialize, or it can -// apply backward-compatibility fixes for older traces. -func (s *State) SetupInitialState(ctx context.Context) { - a := s.Arena() - contexts := NewU64ːContextʳᵐ(a) - contexts.Add(0, NilContextʳ) - s.SetContexts(contexts) - s.SetGLXContexts(NewGLXContextːContextʳᵐ(a)) - s.SetWGLContexts(NewHGLRCːContextʳᵐ(a)) - s.SetCGLContexts(NewCGLContextObjːContextʳᵐ(a)) - for _, c := range s.EGLContexts().All() { - if t := c.Other().BoundOnThread(); t != 0 { - s.Contexts().Add(t, c) // Current thread bindings. - } - if id := c.Identifier(); id >= s.NextContextID() { - s.SetNextContextID(id + 1) - } - } -} - -func (s *State) contextRoot(p *path.Command, thread uint64) *path.MapIndex { - return path.NewField("Contexts", resolve.APIStateAfter(p, ID)).MapIndex(thread) -} - -func (s *State) objectsRoot(p *path.Command, thread uint64) *path.Field { - return s.contextRoot(p, thread).Field("Objects") -} - -func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error { - c.SetCurrentContext(c.GetContext(cmd.Thread())) - // TODO: Find better way to separate GL and EGL commands. - if c.CurrentContext().IsNil() && strings.HasPrefix(cmd.CmdName(), "gl") { - if f := s.NewMessage; f != nil { - f(log.Error, messages.ErrNoContextBound(cmd.Thread())) - } - return &api.ErrCmdAborted{Reason: "No context bound"} - } - if !c.CurrentContext().IsNil() { - c.SetVersion(c.CurrentContext().Other().SupportedVersions()) - c.SetExtension(c.CurrentContext().Other().SupportedExtensions()) - } else { - c.SetVersion(NilSupportedVersionsʳ) - c.SetExtension(NilSupportedExtensionsʳ) - } - return nil -} - -func (b Bufferʳ) GetID() BufferId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (b Framebufferʳ) GetID() FramebufferId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (b Renderbufferʳ) GetID() RenderbufferId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (b Programʳ) GetID() ProgramId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (o Shaderʳ) GetID() ShaderId { - if !o.IsNil() { - return o.ID() - } - return 0 -} - -func (b VertexArrayʳ) GetID() VertexArrayId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (b Textureʳ) GetID() TextureId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (b ImageUnitʳ) GetID() ImageUnitId { - if !b.IsNil() { - return b.ID() - } - return 0 -} - -func (o Samplerʳ) GetID() SamplerId { - if !o.IsNil() { - return o.ID() - } - return 0 -} - -func (o Queryʳ) GetID() QueryId { - if !o.IsNil() { - return o.ID() - } - return 0 -} - -func (o Pipelineʳ) GetID() PipelineId { - if !o.IsNil() { - return o.ID() - } - return 0 -} - -func (o TransformFeedbackʳ) GetID() TransformFeedbackId { - if !o.IsNil() { - return o.ID() - } - return 0 -} - -// GetFramebufferAttachmentInfo returns the width, height and format of the -// specified attachment of the currently bound framebuffer. -func (API) GetFramebufferAttachmentInfo( - ctx context.Context, - after []uint64, - state *api.GlobalState, - thread uint64, - attachment api.FramebufferAttachment) (inf api.FramebufferAttachmentInfo, err error) { - - return GetFramebufferAttachmentInfoByID(state, thread, attachment, 0) -} - -// GetFramebufferAttachmentInfoByID returns the width, height and format of the -// specified attachment of the framebuffer with the given id. -// If fb is 0 then the currently bound framebuffer is used. -func GetFramebufferAttachmentInfoByID( - state *api.GlobalState, - thread uint64, - attachment api.FramebufferAttachment, - fb FramebufferId) (inf api.FramebufferAttachmentInfo, err error) { - - s := GetState(state) - - if fb == 0 { - c := s.GetContext(thread) - if c.IsNil() { - return api.FramebufferAttachmentInfo{}, fmt.Errorf("No context bound") - } - if !c.Other().Initialized() { - return api.FramebufferAttachmentInfo{}, fmt.Errorf("Context not initialized") - } - fb = c.Bound().DrawFramebuffer().GetID() - } - - glAtt, err := attachmentToEnum(attachment) - if err != nil { - return api.FramebufferAttachmentInfo{}, err - } - - fbai, err := s.getFramebufferAttachmentInfo(thread, fb, glAtt) - if fbai.sizedFormat == 0 { - return api.FramebufferAttachmentInfo{}, fmt.Errorf("No format set") - } - if err != nil { - return api.FramebufferAttachmentInfo{}, err - } - fmt, ty := getUnsizedFormatAndType(fbai.sizedFormat) - f, err := getImageFormat(fmt, ty) - if err != nil { - return api.FramebufferAttachmentInfo{}, err - } - switch { - case attachment.IsDepth(): - f = filterUncompressedImageFormat(f, stream.Channel.IsDepth) - case attachment.IsStencil(): - f = filterUncompressedImageFormat(f, stream.Channel.IsStencil) - } - return api.FramebufferAttachmentInfo{fbai.width, fbai.height, 0, f, true}, nil -} - -// Context returns the active context for the given state and thread. -func (API) Context(ctx context.Context, s *api.GlobalState, thread uint64) api.Context { - if c := GetContext(s, thread); !c.IsNil() { - return c - } - return nil -} - -// Mesh implements the api.MeshProvider interface. -func (API) Mesh(ctx context.Context, o interface{}, p *path.Mesh, r *path.ResolveConfig) (*api.Mesh, error) { - if dc, ok := o.(drawCall); ok { - return drawCallMesh(ctx, dc, p, r) - } - return nil, nil -} - -// GetDependencyGraphBehaviourProvider implements dependencygraph.DependencyGraphBehaviourProvider interface -func (API) GetDependencyGraphBehaviourProvider(ctx context.Context) dependencygraph.BehaviourProvider { - return newGlesDependencyGraphBehaviourProvider() -} diff --git a/gapis/api/gles/gles10.api b/gapis/api/gles/gles10.api deleted file mode 100644 index 9b32be967b..0000000000 --- a/gapis/api/gles/gles10.api +++ /dev/null @@ -1,1287 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -sub void errorGLES10notSupported() { - onGlError(GL_INVALID_OPERATION) - abort -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glAlphaFunc.xml", Version.GLES10) -@ignore_unreachables -cmd void glAlphaFunc(GLenum func, GLfloat ref) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glAlphaFunc.xml", Version.GLES10) -@ignore_unreachables -cmd void glAlphaFuncx(GLenum func, GLfixed ref) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glAlphaFuncxOES(GLenum func, GLfixed ref) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glBindFramebufferOES(GLenum target, GLuint framebuffer) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glBindRenderbufferOES(GLenum target, GLuint renderbuffer) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_blend_subtract) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_blend_subtract.txt", Extension.GL_OES_blend_subtract) -@ignore_unreachables -cmd void glBlendEquationOES(GLenum mode) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_blend_equation_separate) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_blend_equation_separate.txt", Extension.GL_OES_blend_equation_separate) -@ignore_unreachables -cmd void glBlendEquationSeparateOES(GLenum modeRGB, GLenum modeAlpha) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_blend_func_separate) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_blend_func_separate.txt", Extension.GL_OES_blend_func_separate) -@ignore_unreachables -cmd void glBlendFuncSeparateOES(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd GLenum glCheckFramebufferStatusOES(GLenum target) { - errorGLES10notSupported() - return ? -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glClearColor.xml", Version.GLES10) -@ignore_unreachables -cmd void glClearColorx(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glClearColorxOES(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glClearDepthfOES(GLclampf depth) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glClearDepth.xml", Version.GLES10) -@ignore_unreachables -cmd void glClearDepthx(GLfixed depth) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glClearDepthxOES(GLfixed depth) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glClientActiveTexture.xml", Version.GLES10) -@ignore_unreachables -cmd void glClientActiveTexture(GLenum texture) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glClipPlane.xml", Version.GLES10) -@ignore_unreachables -cmd void glClipPlanef(GLenum p, const GLfloat* eqn) { - errorGLES10notSupported() -} - -@if(Extension.GL_IMG_user_clip_plane) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_user_clip_plane.txt", Extension.GL_IMG_user_clip_plane) -@ignore_unreachables -cmd void glClipPlanefIMG(GLenum p, const GLfloat* eqn) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glClipPlanefOES(GLenum plane, const GLfloat* equation) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glClipPlane.xml", Version.GLES10) -@ignore_unreachables -cmd void glClipPlanex(GLenum plane, const GLfixed* equation) { - errorGLES10notSupported() -} - -@if(Extension.GL_IMG_user_clip_plane) -@doc("https://www.khronos.org/registry/gles/extensions/IMG/IMG_user_clip_plane.txt", Extension.GL_IMG_user_clip_plane) -@ignore_unreachables -cmd void glClipPlanexIMG(GLenum p, const GLfixed* eqn) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glClipPlanexOES(GLenum plane, const GLfixed* equation) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glColor.xml", Version.GLES10) -@ignore_unreachables -cmd void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glColor.xml", Version.GLES10) -@ignore_unreachables -cmd void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glColor.xml", Version.GLES10) -@ignore_unreachables -cmd void glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glColor4xOES(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glColorPointer.xml", Version.GLES10) -@ignore_unreachables -cmd void glColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_matrix_palette.txt", Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glCurrentPaletteMatrixOES(GLuint matrixpaletteindex) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glDepthRangefOES(GLclampf n, GLclampf f) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glDepthRange.xml", Version.GLES10) -@ignore_unreachables -cmd void glDepthRangex(GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glDepthRangexOES(GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glEnableClientState.xml", Version.GLES10) -@ignore_unreachables -cmd void glDisableClientState(GLenum array) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexfvOES(const GLfloat* coords) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexivOES(const GLint* coords) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexsvOES(const GLshort* coords) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_draw_texture) -@draw_call -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_draw_texture.txt", Extension.GL_OES_draw_texture) -@ignore_unreachables -cmd void glDrawTexxvOES(const GLfixed* coords) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glEnableClientState.xml", Version.GLES10) -@ignore_unreachables -cmd void glEnableClientState(GLenum array) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFog.xml", Version.GLES10) -@ignore_unreachables -cmd void glFogf(GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFog.xml", Version.GLES10) -@ignore_unreachables -cmd void glFogfv(GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFog.xml", Version.GLES10) -@ignore_unreachables -cmd void glFogx(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glFogxOES(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFog.xml", Version.GLES10) -@ignore_unreachables -cmd void glFogxv(GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glFogxvOES(GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, TextureId texture, GLint level) { - FramebufferTexture2D(target, attachment, textarget, texture, level) -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFrustum.xml", Version.GLES10) -@ignore_unreachables -cmd void glFrustumf(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glFrustumfOES(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glFrustum.xml", Version.GLES10) -@ignore_unreachables -cmd void glFrustumx(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glFrustumxOES(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glGenFramebuffersOES(GLsizei n, GLuint* framebuffers) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glGenerateMipmapOES(GLenum target) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetClipPlane.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetClipPlanef(GLenum plane, GLfloat* equation) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glGetClipPlanefOES(GLenum plane, GLfloat* equation) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetClipPlane.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetClipPlanex(GLenum plane, GLfixed* equation) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetClipPlanexOES(GLenum plane, GLfixed* equation) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGet.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetFixedv(GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetFixedvOES(GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetLightfv(GLenum light, GLenum pname, GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetLightxv(GLenum light, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetLightxvOES(GLenum light, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetMaterialfv(GLenum face, GLenum pname, GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetMaterialxv(GLenum face, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetMaterialxvOES(GLenum face, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetTexEnvfv(GLenum target, GLenum pname, GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetTexEnviv(GLenum target, GLenum pname, GLint* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetTexEnvxv(GLenum target, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetTexEnvxvOES(GLenum target, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glGetTexGenfvOES(GLenum coord, GLenum pname, GLfloat* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glGetTexGenivOES(GLenum coord, GLenum pname, GLint* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glGetTexGenxvOES(GLenum coord, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glGetTexParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glGetTexParameterxv(GLenum target, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glGetTexParameterxvOES(GLenum target, GLenum pname, GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd GLboolean glIsFramebufferOES(GLuint framebuffer) { - errorGLES10notSupported() - return ? -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd GLboolean glIsRenderbufferOES(GLuint renderbuffer) { - errorGLES10notSupported() - return ? -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLightModel.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightModelf(GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLightModel.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightModelfv(GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLightModel.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightModelx(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLightModelxOES(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLightModel.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightModelxv(GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLightModelxvOES(GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightf(GLenum light, GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightfv(GLenum light, GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightx(GLenum light, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLightxOES(GLenum light, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLight.xml", Version.GLES10) -@ignore_unreachables -cmd void glLightxv(GLenum light, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLightxvOES(GLenum light, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLineWidth.xml", Version.GLES10) -@ignore_unreachables -cmd void glLineWidthx(GLfixed width) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLineWidthxOES(GLfixed width) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLoadIdentity.xml", Version.GLES10) -@ignore_unreachables -cmd void glLoadIdentity() { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLoadMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glLoadMatrixf(const GLfloat* m) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLoadMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glLoadMatrixx(const GLfixed* m) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glLoadMatrixxOES(const GLfixed* m) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_matrix_palette.txt", Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glLoadPaletteFromModelViewMatrixOES() { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glLogicOp.xml", Version.GLES10) -@ignore_unreachables -cmd void glLogicOp(GLenum opcode) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glMaterialf(GLenum face, GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glMaterialfv(GLenum face, GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glMaterialx(GLenum face, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glMaterialxOES(GLenum face, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMaterial.xml", Version.GLES10) -@ignore_unreachables -cmd void glMaterialxv(GLenum face, GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glMaterialxvOES(GLenum face, GLenum pname, const GLfixed* param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_matrix_palette.txt", Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glMatrixIndexPointerOES(GLint size, GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMatrixMode.xml", Version.GLES10) -@ignore_unreachables -cmd void glMatrixMode(GLenum mode) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMultMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glMultMatrixf(const GLfloat* m) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMultMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glMultMatrixx(const GLfixed* m) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glMultMatrixxOES(const GLfixed* m) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMultiTexCoord.xml", Version.GLES10) -@ignore_unreachables -cmd void glMultiTexCoord4f(GLenum target, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glMultiTexCoord.xml", Version.GLES10) -@ignore_unreachables -cmd void glMultiTexCoord4x(GLenum texture, GLfixed v0, GLfixed v1, GLfixed v2, GLfixed v3) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glMultiTexCoord4xOES(GLenum texture, GLfixed v0, GLfixed v1, GLfixed v2, GLfixed v3) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glNormal.xml", Version.GLES10) -@ignore_unreachables -cmd void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glNormal.xml", Version.GLES10) -@ignore_unreachables -cmd void glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glNormal3xOES(GLfixed nx, GLfixed ny, GLfixed nz) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glNormalPointer.xml", Version.GLES10) -@ignore_unreachables -cmd void glNormalPointer(GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glOrtho.xml", Version.GLES10) -@ignore_unreachables -cmd void glOrthof(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_single_precision) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_single_precision.txt", Extension.GL_OES_single_precision) -@ignore_unreachables -cmd void glOrthofOES(GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glOrtho.xml", Version.GLES10) -@ignore_unreachables -cmd void glOrthox(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glOrthoxOES(GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointParameterf(GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointParameterfv(GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointParameterx(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glPointParameterxOES(GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointParameterxv(GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glPointParameterxvOES(GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointSize.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointSize(GLfloat size) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_point_size_array) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_point_size_array.txt", Extension.GL_OES_point_size_array) -@ignore_unreachables -cmd void glPointSizePointerOES(GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPointSize.xml", Version.GLES10) -@ignore_unreachables -cmd void glPointSizex(GLfixed size) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glPointSizexOES(GLfixed size) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPolygonOffset.xml", Version.GLES10) -@ignore_unreachables -cmd void glPolygonOffsetx(GLfixed factor, GLfixed units) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glPolygonOffsetxOES(GLfixed factor, GLfixed units) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPopMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glPopMatrix() { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glPushMatrix.xml", Version.GLES10) -@ignore_unreachables -cmd void glPushMatrix() { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_query_matrix) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_query_matrix.txt", Extension.GL_OES_query_matrix) -@ignore_unreachables -cmd GLbitfield glQueryMatrixxOES(GLfixed* mantissa, GLint* exponent) { - errorGLES10notSupported() - return ? -} - -@if(Extension.GL_OES_framebuffer_object) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_framebuffer_object.txt", Extension.GL_OES_framebuffer_object) -@ignore_unreachables -cmd void glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glRotate.xml", Version.GLES10) -@ignore_unreachables -cmd void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glRotate.xml", Version.GLES10) -@ignore_unreachables -cmd void glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glRotatexOES(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glSampleCoverage.xml", Version.GLES10) -@ignore_unreachables -cmd void glSampleCoveragex(GLclampx value, GLboolean invert) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glSampleCoveragexOES(GLclampx value, GLboolean invert) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glScale.xml", Version.GLES10) -@ignore_unreachables -cmd void glScalef(GLfloat x, GLfloat y, GLfloat z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glScale.xml", Version.GLES10) -@ignore_unreachables -cmd void glScalex(GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glScalexOES(GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glShadeModel.xml", Version.GLES10) -@ignore_unreachables -cmd void glShadeModel(GLenum mode) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexCoordPointer.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnvf(GLenum target, GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnvfv(GLenum target, GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnvi(GLenum target, GLenum pname, GLint param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnviv(GLenum target, GLenum pname, const GLint* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnvx(GLenum target, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glTexEnvxOES(GLenum target, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexEnv.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexEnvxv(GLenum target, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glTexEnvxvOES(GLenum target, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGenfOES(GLenum coord, GLenum pname, GLfloat param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGenfvOES(GLenum coord, GLenum pname, const GLfloat* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGeniOES(GLenum coord, GLenum pname, GLint param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGenivOES(GLenum coord, GLenum pname, const GLint* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGenxOES(GLenum coord, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_texture_cube_map) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_texture_cube_map.txt", Extension.GL_OES_texture_cube_map) -@ignore_unreachables -cmd void glTexGenxvOES(GLenum coord, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexParameterx(GLenum target, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glTexParameterxOES(GLenum target, GLenum pname, GLfixed param) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTexParameter.xml", Version.GLES10) -@ignore_unreachables -cmd void glTexParameterxv(GLenum target, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glTexParameterxvOES(GLenum target, GLenum pname, const GLfixed* params) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTranslate.xml", Version.GLES10) -@ignore_unreachables -cmd void glTranslatef(GLfloat x, GLfloat y, GLfloat z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glTranslate.xml", Version.GLES10) -@ignore_unreachables -cmd void glTranslatex(GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_fixed_point) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_fixed_point.txt", Extension.GL_OES_fixed_point) -@ignore_unreachables -cmd void glTranslatexOES(GLfixed x, GLfixed y, GLfixed z) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@doc("https://www.khronos.org/opengles/sdk/1.1/docs/man/glVertexPointer.xml", Version.GLES10) -@ignore_unreachables -cmd void glVertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@doc("https://www.khronos.org/registry/gles/extensions/OES/OES_matrix_palette.txt", Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glWeightPointerOES(GLint size, GLenum type, GLsizei stride, const void* pointer) { - errorGLES10notSupported() -} - -// ---------------------------------------------------------------------------- -// extensions for the framework -// ---------------------------------------------------------------------------- - -@if(Version.GLES10 && !Version.GLES20) -@ignore_unreachables -cmd void glColorPointerBounds(GLint size, GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@ignore_unreachables -cmd void glNormalPointerBounds(GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@ignore_unreachables -cmd void glTexCoordPointerBounds(GLint size, GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Version.GLES10 && !Version.GLES20) -@ignore_unreachables -cmd void glVertexPointerBounds(GLint size, GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_point_size_array) -@ignore_unreachables -cmd void glPointSizePointerOESBounds(GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glMatrixIndexPointerOESBounds(GLint size, GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} - -@if(Extension.GL_OES_matrix_palette) -@ignore_unreachables -cmd void glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride, const void* pointer, GLsizei count) { - errorGLES10notSupported() -} diff --git a/gapis/api/gles/gles_pb/BUILD.bazel b/gapis/api/gles/gles_pb/BUILD.bazel deleted file mode 100644 index a4c52e3253..0000000000 --- a/gapis/api/gles/gles_pb/BUILD.bazel +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("//tools/build:rules.bzl", "apic_template") - -apic_template( - name = "api_proto", - api = "//gapis/api/gles:api", - templates = ["//gapis/api/templates:proto"], - visibility = ["//visibility:public"], -) - -go_library( - name = "go_default_library", - srcs = ["doc.go"], - embed = [":gles_pb_go_proto"], - importpath = "github.com/google/gapid/gapis/api/gles/gles_pb", - visibility = ["//visibility:public"], -) - -proto_library( - name = "extras_proto", - srcs = ["extras.proto"], - visibility = ["//visibility:public"], - deps = ["//gapis/memory/memory_pb:memory_pb_proto"], # keep -) - -proto_library( - name = "gles_pb_proto", - srcs = [ - "extras.proto", - ":api_proto", # keep - ], - visibility = ["//visibility:public"], - deps = ["//gapis/memory/memory_pb:memory_pb_proto"], # keep -) - -cc_proto_library( - name = "extras_cc_proto", - visibility = ["//visibility:public"], - deps = [":extras_proto"], -) - -go_proto_library( - name = "gles_pb_go_proto", - importpath = "github.com/google/gapid/gapis/api/gles/gles_pb", - proto = ":gles_pb_proto", - visibility = ["//visibility:public"], - deps = ["//gapis/memory/memory_pb:go_default_library"], # keep -) diff --git a/gapis/api/gles/gles_pb/doc.go b/gapis/api/gles/gles_pb/doc.go deleted file mode 100644 index eaa209b6dd..0000000000 --- a/gapis/api/gles/gles_pb/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package gles_pb describes the serialization format for the gles api. -package gles_pb diff --git a/gapis/api/gles/gles_pb/extras.proto b/gapis/api/gles/gles_pb/extras.proto deleted file mode 100644 index e3b25476a5..0000000000 --- a/gapis/api/gles/gles_pb/extras.proto +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package gles_pb; -option go_package = "github.com/google/gapid/gapis/api/gles/gles_pb"; - -// ErrorState is a command extra used to describe the GLES error state after -// the command has been executed. It is optional - we use it only for testing. -message ErrorState { - uint32 trace_drivers_gl_error = 1; - uint32 interceptors_gl_error = 2; -} - -message EGLImageData { - sint64 res_index = 1; // Resource index of the image data (used on disk) - sint32 size = 2; - sint32 width = 3; - sint32 height = 4; - sint32 format = 5; // GLenum - sint32 type = 6; // GLenum -} diff --git a/gapis/api/gles/glsl.go b/gapis/api/gles/glsl.go deleted file mode 100644 index bb896682fe..0000000000 --- a/gapis/api/gles/glsl.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "fmt" - - "github.com/google/gapid/gapis/shadertools" -) - -// ShaderType returns the ShaderType for the given GLenum. -func (e GLenum) ShaderType() (shadertools.ShaderType, error) { - switch e { - case GLenum_GL_VERTEX_SHADER: - return shadertools.TypeVertex, nil - case GLenum_GL_TESS_CONTROL_SHADER: - return shadertools.TypeTessControl, nil - case GLenum_GL_TESS_EVALUATION_SHADER: - return shadertools.TypeTessEvaluation, nil - case GLenum_GL_GEOMETRY_SHADER: - return shadertools.TypeGeometry, nil - case GLenum_GL_FRAGMENT_SHADER: - return shadertools.TypeFragment, nil - case GLenum_GL_COMPUTE_SHADER: - return shadertools.TypeCompute, nil - } - return 0, fmt.Errorf("%v is not a shader", e) -} diff --git a/gapis/api/gles/graph_visualization.go b/gapis/api/gles/graph_visualization.go deleted file mode 100644 index 0537ceeba9..0000000000 --- a/gapis/api/gles/graph_visualization.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2019 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "bytes" - "fmt" - - "github.com/google/gapid/gapis/api" -) - -// Interface compliance test -var ( - _ = api.GraphVisualizationBuilder(&labelForGlesCommands{}) - _ = api.GraphVisualizationAPI(API{}) -) - -type labelForGlesCommands struct{} - -func (*labelForGlesCommands) GetCommandLabel(command api.Cmd, cmdId uint64) *api.Label { - label := &api.Label{} - commandName := command.CmdName() - var commandIndexName bytes.Buffer - fmt.Fprintf(&commandIndexName, "%s_%d", commandName, cmdId) - label.PushBack(commandIndexName.String(), int(cmdId)) - return label -} - -func (*labelForGlesCommands) GetSubCommandLabel(index api.SubCmdIdx, commandName string, cmdId uint64, subCommandName string) *api.Label { - // TODO(hevrard): understand and implement - panic("TODO gapis/api/gles:GetSubCommandLabel") - return nil -} - -func (API) GetGraphVisualizationBuilder() api.GraphVisualizationBuilder { - return &labelForGlesCommands{} -} diff --git a/gapis/api/gles/guess_semantics.go b/gapis/api/gles/guess_semantics.go deleted file mode 100644 index 66828a5472..0000000000 --- a/gapis/api/gles/guess_semantics.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "strings" - - "github.com/google/gapid/core/stream" - "github.com/google/gapid/core/stream/fmts" - "github.com/google/gapid/gapis/vertex" -) - -var semanticPatterns = []struct { - pattern string - semantic vertex.Semantic_Type -}{ - // Ordered from highest priority to lowest - {"position", vertex.Semantic_Position}, - {"normal", vertex.Semantic_Normal}, - {"tangent", vertex.Semantic_Tangent}, - {"bitangent", vertex.Semantic_Bitangent}, - {"binormal", vertex.Semantic_Bitangent}, - {"texcoord", vertex.Semantic_Texcoord}, - {"pos", vertex.Semantic_Position}, - {"uv", vertex.Semantic_Texcoord}, - {"vertex", vertex.Semantic_Position}, -} - -var semanticFormats = []struct { - format *stream.Format - semantic vertex.Semantic_Type -}{ - // Ordered from highest priority to lowest - {fmts.XYZ_F32, vertex.Semantic_Position}, - {fmts.XYZ_S8_NORM, vertex.Semantic_Normal}, -} - -// guessSemantics uses string and format matching to try and guess the semantic -// usage of a vertex stream. -// This is a big fat hack. See: https://github.com/google/gapid/issues/960 -func guessSemantics(vb *vertex.Buffer, hints map[string]vertex.Semantic_Type) { - taken := map[vertex.Semantic_Type]bool{} - if len(hints) > 0 { - for _, s := range vb.Streams { - if semantic, ok := hints[s.Name]; ok && !taken[semantic] { - taken[semantic] = true - s.Semantic.Type = semantic - } - } - } - - for _, p := range semanticPatterns { - if taken[p.semantic] { - continue - } - for _, s := range vb.Streams { - if needsGuess(s) && strings.Contains(strings.ToLower(s.Name), p.pattern) { - s.Semantic.Type = p.semantic - taken[p.semantic] = true - break - } - } - } - for _, p := range semanticFormats { - if taken[p.semantic] { - continue - } - for _, s := range vb.Streams { - if needsGuess(s) && s.Format.String() == p.format.String() { - s.Semantic.Type = p.semantic - taken[p.semantic] = true - break - } - } - } -} - -func needsGuess(s *vertex.Stream) bool { - return s.Semantic.Type == vertex.Semantic_Unknown -} diff --git a/gapis/api/gles/helpers.go b/gapis/api/gles/helpers.go deleted file mode 100644 index 91ce68ced0..0000000000 --- a/gapis/api/gles/helpers.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/gapis/api" -) - -// BuildProgram returns the commands to create a shader program with compiled -// vertex and fragment shaders. The returned program is not linked. -func BuildProgram(ctx context.Context, s *api.GlobalState, cb CommandBuilder, - vertexShaderID, fragmentShaderID ShaderId, programID ProgramId, - vertexShaderSource, fragmentShaderSource string) []api.Cmd { - return append([]api.Cmd{cb.GlCreateProgram(programID)}, - CompileProgram(ctx, s, cb, vertexShaderID, fragmentShaderID, programID, vertexShaderSource, fragmentShaderSource)..., - ) -} - -// CompileProgram returns the commands to compile and then attach vertex and -// fragment shaders to an existing shader program. -// The returned program is not linked. -func CompileProgram(ctx context.Context, s *api.GlobalState, cb CommandBuilder, - vertexShaderID, fragmentShaderID ShaderId, programID ProgramId, - vertexShaderSource, fragmentShaderSource string) []api.Cmd { - - tmpVertexSrcLen := s.AllocDataOrPanic(ctx, GLint(len(vertexShaderSource))) - tmpVertexSrc := s.AllocDataOrPanic(ctx, vertexShaderSource) - tmpPtrToVertexSrc := s.AllocDataOrPanic(ctx, tmpVertexSrc.Ptr()) - tmpFragmentSrcLen := s.AllocDataOrPanic(ctx, GLint(len(fragmentShaderSource))) - tmpFragmentSrc := s.AllocDataOrPanic(ctx, fragmentShaderSource) - tmpPtrToFragmentSrc := s.AllocDataOrPanic(ctx, tmpFragmentSrc.Ptr()) - - cmds := []api.Cmd{ - cb.GlCreateShader(GLenum_GL_VERTEX_SHADER, vertexShaderID), - cb.GlShaderSource(vertexShaderID, 1, tmpPtrToVertexSrc.Ptr(), tmpVertexSrcLen.Ptr()). - AddRead(tmpPtrToVertexSrc.Data()). - AddRead(tmpVertexSrcLen.Data()). - AddRead(tmpVertexSrc.Data()), - cb.GlCompileShader(vertexShaderID), - cb.GlCreateShader(GLenum_GL_FRAGMENT_SHADER, fragmentShaderID), - cb.GlShaderSource(fragmentShaderID, 1, tmpPtrToFragmentSrc.Ptr(), tmpFragmentSrcLen.Ptr()). - AddRead(tmpPtrToFragmentSrc.Data()). - AddRead(tmpFragmentSrcLen.Data()). - AddRead(tmpFragmentSrc.Data()), - cb.GlCompileShader(fragmentShaderID), - cb.GlAttachShader(programID, vertexShaderID), - cb.GlAttachShader(programID, fragmentShaderID), - // TODO: We should be able to delete the shaders here. - } - - tmpVertexSrc.Free() - tmpFragmentSrc.Free() - return cmds -} - -// GetUniformLocation returns the command to get a uniform location by name. -func GetUniformLocation(ctx context.Context, s *api.GlobalState, cb CommandBuilder, - programID ProgramId, name string, loc UniformLocation) api.Cmd { - - tmp := s.AllocDataOrPanic(ctx, name) - cmd := cb.GlGetUniformLocation(programID, tmp.Ptr(), loc). - AddRead(tmp.Data()) - - tmp.Free() - return cmd -} - -// GetAttribLocation returns the command to get an attribute location by name. -func GetAttribLocation(ctx context.Context, s *api.GlobalState, cb CommandBuilder, - programID ProgramId, name string, loc AttributeLocation) api.Cmd { - - tmp := s.AllocDataOrPanic(ctx, name) - cmd := cb.GlGetAttribLocation(programID, tmp.Ptr(), GLint(loc)). - AddRead(tmp.Data()) - - tmp.Free() - return cmd -} - -// DefaultConstants30 returns a Constants structure filled with default -// values for a vaild OpenGL ES 3.0 context. -func DefaultConstants30(a arena.Arena) Constants { - out := MakeConstants(a) - out.SetSubpixelBits(4) - out.SetMaxElementIndex(0xFFFFFF) - out.SetMax3dTextureSize(256) - out.SetMaxTextureSize(2048) - out.SetMaxArrayTextureLayers(256) - out.SetMaxTextureLodBias(2.0) - out.SetMaxCubeMapTextureSize(2048) - out.SetMaxRenderbufferSize(2048) - out.SetMaxDrawBuffers(4) - out.SetMaxFramebufferWidth(2048) - out.SetMaxFramebufferHeight(2048) - out.SetMaxFramebufferLayers(256) - out.SetMaxFramebufferSamples(4) - out.SetMaxColorAttachments(4) - out.SetMinFragmentInterpolationOffset(-0.5) - out.SetMaxFragmentInterpolationOffset(+0.5) - out.SetFragmentInterpolationOffsetBits(4) - out.SetMaxSampleMaskWords(1) - out.SetMaxColorTextureSamples(1) - out.SetMaxDepthTextureSamples(1) - out.SetMaxIntegerSamples(1) - out.SetMaxVertexAttribRelativeOffset(2047) - out.SetMaxVertexAttribBindings(16) - out.SetMaxVertexAttribStride(2048) - out.SetMaxTextureBufferSize(65536) - out.SetShaderCompiler(GLboolean_GL_TRUE) - out.SetTextureBufferOffsetAlignment(256) - out.SetMajorVersion(3) - out.SetVersion("OpenGL ES 3.0") - out.SetMaxVertexAttribs(16) - out.SetMaxVertexUniformComponents(1024) - out.SetMaxVertexUniformVectors(256) - out.SetMaxVertexUniformBlocks(12) - out.SetMaxVertexOutputComponents(64) - out.SetMaxVertexTextureImageUnits(16) - out.SetMaxTessGenLevel(64) - out.SetMaxPatchVertices(32) - out.SetMaxTessControlUniformComponents(1024) - out.SetMaxTessControlTextureImageUnits(16) - out.SetMaxTessControlOutputComponents(64) - out.SetMaxTessPatchComponents(120) - out.SetMaxTessControlTotalOutputComponents(4096) - out.SetMaxTessControlInputComponents(64) - out.SetMaxTessControlUniformBlocks(12) - out.SetMaxTessEvaluationUniformComponents(1024) - out.SetMaxTessEvaluationTextureImageUnits(16) - out.SetMaxTessEvaluationOutputComponents(64) - out.SetMaxTessEvaluationInputComponents(64) - out.SetMaxTessEvaluationUniformBlocks(12) - out.SetMaxGeometryUniformComponents(1024) - out.SetMaxGeometryUniformBlocks(12) - out.SetMaxGeometryInputComponents(64) - out.SetMaxGeometryOutputComponents(64) - out.SetMaxGeometryOutputVertices(256) - out.SetMaxGeometryTotalOutputComponents(1024) - out.SetMaxGeometryTextureImageUnits(16) - out.SetMaxGeometryShaderInvocations(32) - out.SetMaxFragmentUniformComponents(1024) - out.SetMaxFragmentUniformVectors(256) - out.SetMaxFragmentUniformBlocks(12) - out.SetMaxFragmentInputComponents(60) - out.SetMaxTextureImageUnits(16) - out.SetMaxFragmentAtomicCounterBuffers(1) - out.SetMaxFragmentAtomicCounters(8) - out.SetMaxFragmentShaderStorageBlocks(4) - out.SetMinProgramTexelOffset(-8) - out.SetMaxProgramTexelOffset(7) - out.SetMaxComputeWorkGroupInvocations(128) - out.SetMaxComputeUniformBlocks(12) - out.SetMaxComputeTextureImageUnits(16) - out.SetMaxComputeSharedMemorySize(16384) - out.SetMaxComputeUniformComponents(1024) - out.SetMaxComputeAtomicCounterBuffers(1) - out.SetMaxComputeAtomicCounters(8) - out.SetMaxComputeShaderStorageBlocks(4) - out.SetMaxUniformBufferBindings(72) - out.SetMaxUniformBlockSize(16384) - out.SetUniformBufferOffsetAlignment(256) - out.SetMaxCombinedUniformBlocks(60) - out.SetMaxVaryingComponents(60) - out.SetMaxVaryingVectors(15) - out.SetMaxCombinedTextureImageUnits(96) - out.SetMaxCombinedShaderOutputResources(4) - out.SetMaxUniformLocations(1024) - out.SetMaxAtomicCounterBufferBindings(1) - out.SetMaxAtomicCounterBufferSize(32) - out.SetMaxCombinedAtomicCounterBuffers(1) - out.SetMaxCombinedAtomicCounters(8) - out.SetMaxImageUnits(4) - out.SetMaxFragmentImageUniforms(4) - out.SetMaxComputeImageUniforms(4) - out.SetMaxCombinedImageUniforms(4) - out.SetMaxShaderStorageBufferBindings(4) - out.SetMaxShaderStorageBlockSize(0x8000000) - out.SetMaxCombinedShaderStorageBlocks(4) - out.SetShaderStorageBufferOffsetAlignment(256) - out.SetMaxDebugMessageLength(1) - out.SetMaxDebugLoggedMessages(1) - out.SetMaxDebugGroupStackDepth(64) - out.SetMaxLabelLength(256) - out.SetMaxTransformFeedbackInterleavedComponents(64) - out.SetMaxTransformFeedbackSeparateAttribs(4) - out.SetMaxTransformFeedbackSeparateComponents(4) - out.SetMaxTextureMaxAnisotropyExt(2.0) - out.SetMaxViewsExt(2) - out.SetCompressedTextureFormats(NewU32ːGLenumᵐ(a)) - out.SetProgramBinaryFormats(NewU32ːGLenumᵐ(a)) - out.SetShaderBinaryFormats(NewU32ːGLenumᵐ(a)) - out.SetExtensions(NewU32ːstringᵐ(a)) - return out -} - -func NewStaticContextStateForTest(a arena.Arena) StaticContextState { - constants := DefaultConstants30(a) - constants.SetVersion("OpenGL ES 2.0") - return NewStaticContextState(a, - constants, // Constants - "", // ThreadName - ) -} - -func NewDynamicContextStateForTest(a arena.Arena, width, height int, preserveBuffersOnSwap bool) DynamicContextState { - return NewDynamicContextState(a, - GLsizei(width), // BackbufferWidth - GLsizei(height), // BackbufferHeight - GLenum_GL_RGB565, // BackbufferColorFmt - GLenum_GL_DEPTH_COMPONENT16, // BackbufferDepthFmt - GLenum_GL_STENCIL_INDEX8, // BackbufferStencilFmt - preserveBuffersOnSwap, // PreserveBuffersOnSwap - 0, // RedSize - 0, // GreenSize - 0, // BlueSize - 0, // AlphaSize - 0, // DepthSize - 0, // StencilSize - ) -} diff --git a/gapis/api/gles/image.go b/gapis/api/gles/image.go deleted file mode 100644 index d052aff21f..0000000000 --- a/gapis/api/gles/image.go +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "fmt" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/image/astc" - "github.com/google/gapid/core/stream" - "github.com/google/gapid/core/stream/fmts" - "github.com/google/gapid/gapis/api" -) - -func isUnsizedFormat(fmt GLenum) bool { - switch fmt { - case GLenum_GL_RGB, GLenum_GL_RGBA, GLenum_GL_LUMINANCE_ALPHA, GLenum_GL_LUMINANCE, GLenum_GL_ALPHA, GLenum_GL_DEPTH_COMPONENT, GLenum_GL_DEPTH_STENCIL: - return true - default: - return false - } -} - -// getCorrectInternalFormat returns the correct format to use for texture data upload calls (e.g. glTexImage2d). -// See image_format.api:GetSizedFormatFromTuple. -func (img Imageʳ) getCorrectInternalFormat() GLenum { - internalFormat := img.InternalFormat() - if isUnsizedFormat(internalFormat) { - return internalFormat - } - - sizedFormat := img.SizedFormat() - switch sizedFormat { - case GLenum_GL_LUMINANCE8_ALPHA8_EXT, GLenum_GL_LUMINANCE_ALPHA16F_EXT, GLenum_GL_LUMINANCE_ALPHA32F_EXT: - return GLenum_GL_LUMINANCE_ALPHA - case GLenum_GL_LUMINANCE8_EXT, GLenum_GL_LUMINANCE16F_EXT, GLenum_GL_LUMINANCE32F_EXT: - return GLenum_GL_LUMINANCE - case GLenum_GL_ALPHA8_EXT, GLenum_GL_ALPHA16F_EXT, GLenum_GL_ALPHA32F_EXT: - return GLenum_GL_ALPHA - default: - return sizedFormat - } -} - -func (i Imageʳ) getUnsizedFormatAndType() (unsizedFormat, ty GLenum) { - if i.DataFormat() == 0 && i.DataType() == 0 { - return getUnsizedFormatAndType(i.SizedFormat()) - } - - dataType := i.DataType() - if i.InternalFormat() == GLenum_GL_DEPTH_COMPONENT && dataType == GLenum_GL_FLOAT { - dataType = GLenum_GL_UNSIGNED_INT - } - - return i.DataFormat(), dataType -} - -func cubemapFaceToLayer(target GLenum) GLint { - layer, _ := subCubemapFaceToLayer(nil, nil, api.CmdNoID, nil, &api.GlobalState{}, nil, 0, nil, nil, target) - return layer -} - -// getSizedFormatFromTuple returns sized format from unsized format and component type. -func getSizedFormatFromTuple(unsizedFormat, ty GLenum) (sizedFormat GLenum) { - sf, _ := subGetSizedFormatFromTuple(nil, nil, api.CmdNoID, nil, &api.GlobalState{}, nil, 0, nil, nil, unsizedFormat, ty) - if sf == GLenum_GL_NONE { - panic(fmt.Errorf("Unknown unsized format: %v, %v", unsizedFormat, ty)) - } - return sf -} - -// getUnsizedFormatAndType returns unsized format and component type from sized format. -func getUnsizedFormatAndType(sizedFormat GLenum) (unsizedFormat, ty GLenum) { - info := GetSizedFormatInfoOrPanic(sizedFormat) - return info.UnsizedFormat(), info.DataType() -} - -// GetSizedFormatInfoOrPanic is wrapper for the 'GetSizedFormatInfo' api subroutine. -func GetSizedFormatInfoOrPanic(sizedFormat GLenum) SizedFormatInfo { - info, _ := subGetSizedFormatInfo(nil, nil, api.CmdNoID, nil, &api.GlobalState{}, nil, 0, nil, nil, sizedFormat) - if info.SizedFormat() == GLenum_GL_NONE { - panic(fmt.Errorf("Unknown sized format: %v", sizedFormat)) - } - return info -} - -// getImageFormat returns the image.Format for the given format-type tuple. -// The tuple must be in one of the following two forms: -// (unsizedFormat, ty) - Uncompressed data. -// (sizedFormat, NONE) - Compressed data. -// (NONE, NONE) - Uninitialized content. -// Sized uncompressed format (e.g. GL_RGB565) is not a valid input. -func getImageFormat(format, ty GLenum) (*image.Format, error) { - if format != GLenum_GL_NONE { - if ty != GLenum_GL_NONE { - imgfmt, _ := getUncompressedStreamFormat(format, ty) - if imgfmt != nil { - return image.NewUncompressed(fmt.Sprintf("%v, %v", format, ty), imgfmt), nil - } - } else { - imgfmt, _ := getCompressedImageFormat(format) - if imgfmt != nil { - return imgfmt, nil - } - } - } else { - return image.NewUncompressed("", &stream.Format{}), nil - } - return nil, fmt.Errorf("Unsupported input format-type pair: (%s, %s)", format, ty) -} - -// filterUncompressedImageFormat returns a copy of f with only the components -// that have channels that pass the predicate p. -func filterUncompressedImageFormat(f *image.Format, p func(stream.Channel) bool) *image.Format { - u := f.GetUncompressed() - if u == nil { - panic(fmt.Errorf("Format %v is not uncompressed", f)) - } - - out := proto.Clone(f).(*image.Format) - filtered := out.GetUncompressed().Format - filtered.Components = filtered.Components[:0] - - names := []string{} - for _, c := range u.Format.Components { - if p(c.Channel) { - filtered.Components = append(filtered.Components, c) - names = append(names, c.Channel.String()) - } - } - out.Name = fmt.Sprintf("%v from %v", strings.Join(names, ", "), f.Name) - return out -} - -var glChannelToStreamChannel = map[GLenum]stream.Channel{ - GLenum_GL_RED: stream.Channel_Red, - GLenum_GL_GREEN: stream.Channel_Green, - GLenum_GL_BLUE: stream.Channel_Blue, - GLenum_GL_ALPHA: stream.Channel_Alpha, - GLenum_GL_LUMINANCE: stream.Channel_Luminance, - GLenum_GL_DEPTH_COMPONENT: stream.Channel_Depth, - GLenum_GL_STENCIL_INDEX: stream.Channel_Stencil, -} - -// getUncompressedStreamFormat returns the decoding format which can be used to read single pixel. -func getUncompressedStreamFormat(unsizedFormat, ty GLenum) (format *stream.Format, err error) { - info, _ := subGetUnsizedFormatInfo(nil, nil, api.CmdNoID, nil, &api.GlobalState{}, nil, 0, nil, nil, unsizedFormat) - if info.Count() == 0 { - return nil, fmt.Errorf("Unknown unsized format: %v", unsizedFormat) - } - glChannels := []GLenum{info.Channel0(), info.Channel1(), info.Channel2(), info.Channel3()} - channels := make(stream.Channels, info.Count()) - for i := range channels { - channel, ok := glChannelToStreamChannel[glChannels[i]] - if !ok { - return nil, fmt.Errorf("Unknown GL channel: %v", glChannels[i]) - } - channels[i] = channel - } - - // Helper method to build the format. - format = &stream.Format{} - addComponent := func(channelIndex int, datatype *stream.DataType) { - channel := stream.Channel_Undefined // Padding field - if 0 <= channelIndex && channelIndex < len(channels) { - channel = channels[channelIndex] - } - sampling := stream.Linear - var sampleAsFloat bool - if channel == stream.Channel_Depth { - sampleAsFloat = true - } else if channel == stream.Channel_Stencil { - sampleAsFloat = false - } else /* colour */ { - sampleAsFloat = !info.Integer() - } - if datatype.IsInteger() && sampleAsFloat { - sampling = stream.LinearNormalized // Convert int to float - } - format.Components = append(format.Components, &stream.Component{ - DataType: datatype, - Sampling: sampling, - Channel: channel, - }) - } - - // Read the components in increasing memory order (assuming little-endian architecture). - // Note that the GL names are based on big-endian, so the order is generally backwards. - switch ty { - case GLenum_GL_UNSIGNED_BYTE: - for i := range channels { - addComponent(i, &stream.U8) - } - case GLenum_GL_BYTE: - for i := range channels { - addComponent(i, &stream.S8) - } - case GLenum_GL_UNSIGNED_SHORT: - for i := range channels { - addComponent(i, &stream.U16) - } - case GLenum_GL_SHORT: - for i := range channels { - addComponent(i, &stream.S16) - } - case GLenum_GL_UNSIGNED_INT: - for i := range channels { - addComponent(i, &stream.U32) - } - case GLenum_GL_INT: - for i := range channels { - addComponent(i, &stream.S32) - } - case GLenum_GL_HALF_FLOAT, GLenum_GL_HALF_FLOAT_OES: - for i := range channels { - addComponent(i, &stream.F16) - } - case GLenum_GL_FLOAT: - for i := range channels { - addComponent(i, &stream.F32) - } - case GLenum_GL_UNSIGNED_SHORT_5_6_5: - addComponent(2, &stream.U5) - addComponent(1, &stream.U6) - addComponent(0, &stream.U5) - case GLenum_GL_UNSIGNED_SHORT_4_4_4_4: - addComponent(3, &stream.U4) - addComponent(2, &stream.U4) - addComponent(1, &stream.U4) - addComponent(0, &stream.U4) - case GLenum_GL_UNSIGNED_SHORT_5_5_5_1: - addComponent(3, &stream.U1) - addComponent(2, &stream.U5) - addComponent(1, &stream.U5) - addComponent(0, &stream.U5) - case GLenum_GL_UNSIGNED_INT_2_10_10_10_REV: - addComponent(0, &stream.U10) - addComponent(1, &stream.U10) - addComponent(2, &stream.U10) - addComponent(3, &stream.U2) - case GLenum_GL_UNSIGNED_INT_24_8: - addComponent(1, &stream.U8) - addComponent(0, &stream.U24) - case GLenum_GL_UNSIGNED_INT_10F_11F_11F_REV: - addComponent(0, &stream.F11) - addComponent(1, &stream.F11) - addComponent(2, &stream.F10) - case GLenum_GL_UNSIGNED_INT_5_9_9_9_REV: - return fmts.RGBE_U9U9U9U5, nil - case GLenum_GL_FLOAT_32_UNSIGNED_INT_24_8_REV: - addComponent(0, &stream.F32) - addComponent(1, &stream.U8) - addComponent(-1, &stream.U24) - default: - return nil, fmt.Errorf("Unsupported data type: %v", ty) - } - return format, nil -} - -// getCompressedImageFormat returns a pointer to an image.Format for the given -// compressed format. -func getCompressedImageFormat(format GLenum) (*image.Format, error) { - switch format { - // ETC1 - case GLenum_GL_ETC1_RGB8_OES: - return image.NewETC1_RGB_U8_NORM("GL_ETC1_RGB8_OES"), nil - - // ASTC - case GLenum_GL_COMPRESSED_RGBA_ASTC_4x4_KHR: - return astc.NewRGBA_4x4("GL_COMPRESSED_RGBA_ASTC_4x4_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_5x4_KHR: - return astc.NewRGBA_5x4("GL_COMPRESSED_RGBA_ASTC_5x4_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_5x5_KHR: - return astc.NewRGBA_5x5("GL_COMPRESSED_RGBA_ASTC_5x5_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_6x5_KHR: - return astc.NewRGBA_6x5("GL_COMPRESSED_RGBA_ASTC_6x5_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_6x6_KHR: - return astc.NewRGBA_6x6("GL_COMPRESSED_RGBA_ASTC_6x6_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_8x5_KHR: - return astc.NewRGBA_8x5("GL_COMPRESSED_RGBA_ASTC_8x5_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_8x6_KHR: - return astc.NewRGBA_8x6("GL_COMPRESSED_RGBA_ASTC_8x6_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_8x8_KHR: - return astc.NewRGBA_8x8("GL_COMPRESSED_RGBA_ASTC_8x8_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_10x5_KHR: - return astc.NewRGBA_10x5("GL_COMPRESSED_RGBA_ASTC_10x5_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_10x6_KHR: - return astc.NewRGBA_10x6("GL_COMPRESSED_RGBA_ASTC_10x6_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_10x8_KHR: - return astc.NewRGBA_10x8("GL_COMPRESSED_RGBA_ASTC_10x8_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_10x10_KHR: - return astc.NewRGBA_10x10("GL_COMPRESSED_RGBA_ASTC_10x10_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_12x10_KHR: - return astc.NewRGBA_12x10("GL_COMPRESSED_RGBA_ASTC_12x10_KHR"), nil - case GLenum_GL_COMPRESSED_RGBA_ASTC_12x12_KHR: - return astc.NewRGBA_12x12("GL_COMPRESSED_RGBA_ASTC_12x12_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: - return astc.NewSRGB8_ALPHA8_4x4("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: - return astc.NewSRGB8_ALPHA8_5x4("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: - return astc.NewSRGB8_ALPHA8_5x5("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: - return astc.NewSRGB8_ALPHA8_6x5("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: - return astc.NewSRGB8_ALPHA8_6x6("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: - return astc.NewSRGB8_ALPHA8_8x5("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: - return astc.NewSRGB8_ALPHA8_8x6("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: - return astc.NewSRGB8_ALPHA8_8x8("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: - return astc.NewSRGB8_ALPHA8_10x5("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: - return astc.NewSRGB8_ALPHA8_10x6("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: - return astc.NewSRGB8_ALPHA8_10x8("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: - return astc.NewSRGB8_ALPHA8_10x10("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: - return astc.NewSRGB8_ALPHA8_12x10("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: - return astc.NewSRGB8_ALPHA8_12x12("GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"), nil - - // ATC - case GLenum_GL_ATC_RGB_AMD: - return image.NewATC_RGB_AMD("GL_ATC_RGB_AMD"), nil - case GLenum_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: - return image.NewATC_RGBA_EXPLICIT_ALPHA_AMD("GL_ATC_RGBA_EXPLICIT_ALPHA_AMD"), nil - case GLenum_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: - return image.NewATC_RGBA_INTERPOLATED_ALPHA_AMD("GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD"), nil - - // ETC - case GLenum_GL_COMPRESSED_R11_EAC: - return image.NewETC2_R_U11_NORM("GL_COMPRESSED_R11_EAC"), nil - case GLenum_GL_COMPRESSED_SIGNED_R11_EAC: - return image.NewETC2_R_S11_NORM("GL_COMPRESSED_SIGNED_R11_EAC"), nil - case GLenum_GL_COMPRESSED_RG11_EAC: - return image.NewETC2_RG_U11_NORM("GL_COMPRESSED_RG11_EAC"), nil - case GLenum_GL_COMPRESSED_SIGNED_RG11_EAC: - return image.NewETC2_RG_S11_NORM("GL_COMPRESSED_SIGNED_RG11_EAC"), nil - case GLenum_GL_COMPRESSED_RGB8_ETC2: - return image.NewETC2_RGB_U8_NORM("GL_COMPRESSED_RGB8_ETC2"), nil - case GLenum_GL_COMPRESSED_SRGB8_ETC2: - return image.NewETC2_SRGB_U8_NORM("GL_COMPRESSED_SRGB8_ETC2"), nil - case GLenum_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: - return image.NewETC2_RGBA_U8U8U8U1_NORM("GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"), nil - case GLenum_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - return image.NewETC2_SRGBA_U8U8U8U1_NORM("GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"), nil - case GLenum_GL_COMPRESSED_RGBA8_ETC2_EAC: - return image.NewETC2_RGBA_U8_NORM("GL_COMPRESSED_RGBA8_ETC2_EAC"), nil - case GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - return image.NewETC2_SRGBA_U8_NORM("GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"), nil - - // S3TC - case GLenum_GL_COMPRESSED_RGB_S3TC_DXT1_EXT: - return image.NewS3_DXT1_RGB("GL_COMPRESSED_RGB_S3TC_DXT1_EXT"), nil - case GLenum_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return image.NewS3_DXT1_RGBA("GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"), nil - case GLenum_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - return image.NewS3_DXT3_RGBA("GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"), nil - case GLenum_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return image.NewS3_DXT5_RGBA("GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"), nil - } - - return nil, fmt.Errorf("Unsupported compressed format: %s", format) -} diff --git a/gapis/api/gles/importance.go b/gapis/api/gles/importance.go deleted file mode 100644 index 6ef3c5300e..0000000000 --- a/gapis/api/gles/importance.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import "github.com/google/gapid/gapis/resolve" - -var _ = []resolve.Importance{ - &GlDrawArrays{}, - &GlDrawArraysIndirect{}, - &GlDrawArraysInstanced{}, - &GlDrawElements{}, - &GlDrawElementsBaseVertex{}, - &GlDrawElementsIndirect{}, - &GlDrawElementsInstanced{}, - &GlDrawElementsInstancedBaseVertex{}, - &GlDrawRangeElements{}, - &GlDrawRangeElementsBaseVertex{}, - &EglSwapBuffers{}, -} - -func (*GlDrawArrays) Importance() int { return 1 } -func (*GlDrawArraysIndirect) Importance() int { return 1 } -func (*GlDrawArraysInstanced) Importance() int { return 1 } -func (*GlDrawElements) Importance() int { return 1 } -func (*GlDrawElementsBaseVertex) Importance() int { return 1 } -func (*GlDrawElementsIndirect) Importance() int { return 1 } -func (*GlDrawElementsInstanced) Importance() int { return 1 } -func (*GlDrawElementsInstancedBaseVertex) Importance() int { return 1 } -func (*GlDrawRangeElements) Importance() int { return 1 } -func (*GlDrawRangeElementsBaseVertex) Importance() int { return 1 } -func (*EglSwapBuffers) Importance() int { return 5 } diff --git a/gapis/api/gles/issue_whitelist.go b/gapis/api/gles/issue_whitelist.go deleted file mode 100644 index a73d226a27..0000000000 --- a/gapis/api/gles/issue_whitelist.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import "github.com/google/gapid/gapis/api" - -func isIssueWhitelisted(cmd api.Cmd, e error) bool { - switch cmd.(type) { - case *GlActiveTexture: - // TODO: b/29446056 - Apps break replay by looping over all texture units. - // Just ignore the replay errors for now. We can do something better later. - return true - case *GlInvalidateFramebuffer, *GlDiscardFramebufferEXT: - if e, ok := e.(ErrUnexpectedDriverTraceError); ok { - if e.DriverError == GLenum_GL_NONE && e.ExpectedError == GLenum_GL_INVALID_ENUM { - // Bug in Nexus 6 driver (Adreno 420). See b/29124256 (QCOM) and b/29124194 (DEQP). - return true - } - } - } - return false -} diff --git a/gapis/api/gles/links.go b/gapis/api/gles/links.go deleted file mode 100644 index 6f3dda3f10..0000000000 --- a/gapis/api/gles/links.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service/path" -) - -// objects returns the path to the Objects field of the currently bound -// context, and the context at p. -func objects(ctx context.Context, p path.Node, r *path.ResolveConfig) (*path.Field, Contextʳ, error) { - if cmdPath := path.FindCommand(p); cmdPath != nil { - cmd, err := resolve.Cmd(ctx, cmdPath, r) - if err != nil { - return nil, NilContextʳ, err - } - thread := cmd.Thread() - - stateObj, err := resolve.State(ctx, cmdPath.StateAfter(), r) - if err != nil { - return nil, NilContextʳ, err - } - state := stateObj.(*State) - context, ok := state.Contexts().Lookup(thread) - if !ok { - return nil, NilContextʳ, nil - } - return state.objectsRoot(cmdPath, thread), context, nil - } - return nil, NilContextʳ, nil -} - -// Link returns the link to the attribute vertex array in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o AttributeLocation) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil { - return nil, err - } - if !c.Bound().VertexArray().VertexAttributeArrays().Contains(o) { - return nil, nil - } - return i. - Field("VertexArrays"). - MapIndex(c.Bound().VertexArray().GetID()). - Field("VertexAttributeArrays"). - MapIndex(o), nil -} - -// Link returns the link to the buffer object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o BufferId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Buffers().Contains(o) { - return nil, err - } - return i.Field("Buffers").MapIndex(o), nil -} - -// Link returns the link to the framebuffer object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o FramebufferId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Framebuffers().Contains(o) { - return nil, err - } - return i.Field("Framebuffers").MapIndex(o), nil -} - -// Link returns the link to the program in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o ProgramId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Programs().Contains(o) { - return nil, err - } - return i.Field("Programs").MapIndex(o), nil -} - -// Link returns the link to the query object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o QueryId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Queries().Contains(o) { - return nil, err - } - return i.Field("Queries").MapIndex(o), nil -} - -// Link returns the link to the renderbuffer object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o RenderbufferId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Renderbuffers().Contains(o) { - return nil, err - } - return i.Field("Renderbuffers").MapIndex(o), nil -} - -// Link returns the link to the sampler object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o SamplerId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Samplers().Contains(o) { - return nil, err - } - return i.Field("Samplers").MapIndex(o), nil -} - -// Link returns the link to the shader object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o ShaderId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Shaders().Contains(o) { - return nil, err - } - return i.Field("Shaders").MapIndex(o), nil -} - -// Link returns the link to the texture object in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o TextureId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().Textures().Contains(o) { - return nil, err - } - return i.Field("Textures").MapIndex(o), nil -} - -// Link returns the link to the uniform in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o UniformIndex) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil { - return nil, err - } - - cmd, err := resolve.Cmd(ctx, path.FindCommand(p), r) - if err != nil { - return nil, err - } - - var program ProgramId - switch cmd := cmd.(type) { - case *GlGetActiveUniform: - program = cmd.Program() - case *GlGetActiveUniformsiv: - program = cmd.Program() - default: - program = c.Bound().Program().GetID() - } - - prog, ok := c.Objects().Programs().Lookup(program) - if !ok || prog.ActiveResources().IsNil() || !prog.ActiveResources().Uniforms().Contains(uint32(o)) { - return nil, nil - } - - return i. - Field("Programs"). - MapIndex(program). - Field("ActiveResources"). - Field("Uniforms"). - MapIndex(o), nil -} - -// Link returns the link to the uniform in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o UniformLocation) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil { - return nil, err - } - - cmd, err := resolve.Cmd(ctx, path.FindCommand(p), r) - if err != nil { - return nil, err - } - - var program ProgramId - switch cmd := cmd.(type) { - case *GlGetActiveUniform: - program = cmd.Program() - case *GlGetUniformLocation: - program = cmd.Program() - default: - program = c.Bound().Program().GetID() - } - - prog, ok := c.Objects().Programs().Lookup(program) - if !ok || !prog.UniformLocations().Contains(o) { - return nil, nil - } - - return i. - Field("Programs"). - MapIndex(program). - Field("UniformLocations"). - MapIndex(o), nil -} - -// Link returns the link to the vertex array in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o VertexArrayId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().VertexArrays().Contains(o) { - return nil, err - } - return i.Field("VertexArrays").MapIndex(o), nil -} - -// Link returns the link to the transform feedback in the state block. -// If nil, nil is returned then the path cannot be followed. -func (o TransformFeedbackId) Link(ctx context.Context, p path.Node, r *path.ResolveConfig) (path.Node, error) { - i, c, err := objects(ctx, p, r) - if i == nil || !c.Objects().TransformFeedbacks().Contains(o) { - return nil, err - } - return i.Field("TransformFeedbacks").MapIndex(o), nil -} diff --git a/gapis/api/gles/markers.go b/gapis/api/gles/markers.go deleted file mode 100644 index ab3b898acb..0000000000 --- a/gapis/api/gles/markers.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "strings" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/memory" -) - -func readString(ctx context.Context, c api.Cmd, s *api.GlobalState, at memory.Pointer, length GLsizei) string { - ptr := NewCharᵖ(at) - if length > 0 { - chars, err := ptr.Slice(0, uint64(length), s.MemoryLayout).Read(ctx, c, s, nil) - if err != nil { - return "" - } - return string(memory.CharToBytes(chars)) - } - chars, err := ptr.StringSlice(ctx, s).Read(ctx, c, s, nil) - if err != nil { - return "" - } - return strings.TrimRight(string(memory.CharToBytes(chars)), "\x00") -} - -// Label returns the user maker name. -func (c *GlPushGroupMarkerEXT) Label(ctx context.Context, s *api.GlobalState) string { - return readString(ctx, c, s, c.Marker(), c.Length()) -} - -// Label returns the user maker name. -func (c *GlInsertEventMarkerEXT) Label(ctx context.Context, s *api.GlobalState) string { - return readString(ctx, c, s, c.Marker(), c.Length()) -} - -// Label returns the user maker name. -func (c *GlPushDebugGroup) Label(ctx context.Context, s *api.GlobalState) string { - // This is incorrect, fudging for a bug in Unity which has been fixed but not - // rolled out. - // See https://github.com/google/gapid/issues/459 for reference. - // - // c.Length() should only be treated as null-terminated if c.Length() is < 0. - // - // TODO: Consider removing once the fixed version is mainstream. - return readString(ctx, c, s, c.Message(), c.Length()) -} - -// Label returns the user maker name. -func (c *GlPushDebugGroupKHR) Label(ctx context.Context, s *api.GlobalState) string { - // This is incorrect, fudging for a bug in Unity which has been fixed but not - // rolled out. - // See https://github.com/google/gapid/issues/459 for reference. - // - // c.Length() should only be treated as null-terminated if c.Length() is < 0. - // - // TODO: Consider removing once the fixed version is mainstream. - return readString(ctx, c, s, c.Message(), c.Length()) -} diff --git a/gapis/api/gles/markers_test.go b/gapis/api/gles/markers_test.go deleted file mode 100644 index 7b0b40d1f7..0000000000 --- a/gapis/api/gles/markers_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles_test - -import ( - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" -) - -var _ = []api.Labeled{ - (*gles.GlPushGroupMarkerEXT)(nil), - (*gles.GlInsertEventMarkerEXT)(nil), -} diff --git a/gapis/api/gles/math.go b/gapis/api/gles/math.go deleted file mode 100644 index 66fca32906..0000000000 --- a/gapis/api/gles/math.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -// EqualTo returns true if the rectangle has the given dimensions. -func (r Rect) EqualTo(x, y GLint, w, h GLsizei) bool { - return r.X() == x && r.Y() == y && r.Width() == w && r.Height() == h -} - -// IsUnit returns true if the bounding box has a min of [-1, -1, -1, -1] -// and max of [+1, +1, +1, +1]. -func (r BoundingBox) IsUnit() bool { - return r.Min().EqualTo(-1, -1, -1, -1) && r.Max().EqualTo(1, 1, 1, 1) -} - -// EqualTo returns true if the color is equal to the given values. -func (c Color) EqualTo(r, g, b, a GLfloat) bool { - return c.Red() == r && c.Green() == g && c.Blue() == b && c.Alpha() == a -} - -// EqualTo returns true if the vector is equal to the given coordinates. -func (v Vec4f) EqualTo(x, y, z, w GLfloat) bool { - return v.Get(0) == x && v.Get(1) == y && v.Get(2) == z && v.Get(3) == w -} - -// EqualTo returns true if the vector is equal to the given coordinates. -func (v Vec4i) EqualTo(x, y, z, w GLint) bool { - return v.Get(0) == x && v.Get(1) == y && v.Get(2) == z && v.Get(3) == w -} diff --git a/gapis/api/gles/read_depth.go b/gapis/api/gles/read_depth.go deleted file mode 100644 index 7f2350b02d..0000000000 --- a/gapis/api/gles/read_depth.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" -) - -// copyDepthToColorGLES emmits commands that will copy the depth data of the -// current read framebuffer into an new framebuffer (which is left bound as the -// read framebuffer upon exit) as the color attachment in R32F format, allowing -// it to be read via glReadPixels. -func copyDepthToColorGLES(ctx context.Context, dID api.CmdID, thread uint64, s *api.GlobalState, out transform.Writer, t *tweaker, fbai fbai, width, height int32) { - const ( - aScreenCoordsLocation AttributeLocation = 0 - aScreenCoords = "aScreenCoords" - uTextureLocation UniformLocation = 0 - uTexture = "uTexture" - - vertexShaderSource string = ` - #version 300 es - - precision highp float; - in vec2 aScreenCoords; - out vec2 uv; - - void main() { - uv = (aScreenCoords + 1.0) / 2.0; - gl_Position = vec4(aScreenCoords.xy, 0., 1.); - }` - fragmentShaderSource string = ` - #version 300 es - - precision highp float; - uniform sampler2D uTexture; - in vec2 uv; - out vec4 fragColor; - - void main() { - fragColor = texture(uTexture, uv); - }` - ) - - // 2D vertices positions for a full screen 2D triangle strip. - positions := []float32{-1., -1., 1., -1., -1., 1., 1., 1.} - ws, hs := GLsizei(width), GLsizei(height) - wi, hi := GLint(width), GLint(height) - - cb := CommandBuilder{Thread: thread, Arena: s.Arena} - - // Create a framebuffer with a depth texture and blit. - fb := t.glGenFramebuffer(ctx) - tex := t.glGenTexture(ctx) - t.glActiveTexture(ctx, GLenum_GL_TEXTURE0) - t.glBindTexture_2D(ctx, tex) - out.MutateAndWrite(ctx, dID, cb.GlTexParameteri(GLenum_GL_TEXTURE_2D, GLenum_GL_TEXTURE_MIN_FILTER, GLint(GLenum_GL_NEAREST))) - out.MutateAndWrite(ctx, dID, cb.GlTexParameteri(GLenum_GL_TEXTURE_2D, GLenum_GL_TEXTURE_MAG_FILTER, GLint(GLenum_GL_NEAREST))) - if fbai.internalFormat != GLenum_GL_NONE && fbai.internalFormat != fbai.sizedFormat { - out.MutateAndWrite(ctx, dID, cb.GlTexImage2D(GLenum_GL_TEXTURE_2D, 0, GLint(fbai.internalFormat), ws, hs, 0, fbai.format, fbai.ty, memory.Nullptr)) - } else { - out.MutateAndWrite(ctx, dID, cb.GlTexStorage2D(GLenum_GL_TEXTURE_2D, 1, fbai.sizedFormat, ws, hs)) - } - t.glBindFramebuffer_Draw(ctx, fb) - out.MutateAndWrite(ctx, dID, cb.GlFramebufferTexture2D(GLenum_GL_DRAW_FRAMEBUFFER, GLenum_GL_DEPTH_ATTACHMENT, GLenum_GL_TEXTURE_2D, tex, 0)) - out.MutateAndWrite(ctx, dID, cb.GlBlitFramebuffer(0, 0, wi, hi, 0, 0, wi, hi, GLbitfield_GL_DEPTH_BUFFER_BIT, GLenum_GL_NEAREST)) - - // Detach the depth texture from the FB and attach a color renderbuffer. - out.MutateAndWrite(ctx, dID, cb.GlFramebufferTexture2D(GLenum_GL_DRAW_FRAMEBUFFER, GLenum_GL_DEPTH_ATTACHMENT, GLenum_GL_TEXTURE_2D, 0, 0)) - rb := t.glGenRenderbuffer(ctx) - t.glBindRenderbuffer(ctx, rb) - out.MutateAndWrite(ctx, dID, cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, GLenum_GL_R32F, ws, hs)) - out.MutateAndWrite(ctx, dID, cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, GLenum_GL_COLOR_ATTACHMENT0, GLenum_GL_RENDERBUFFER, rb)) - - // Temporarily change rasterizing/blending state and enable VAP 0. - t.glDisable(ctx, GLenum_GL_BLEND) - t.glDisable(ctx, GLenum_GL_CULL_FACE) - t.glDisable(ctx, GLenum_GL_DEPTH_TEST) - t.glDisable(ctx, GLenum_GL_SCISSOR_TEST) - t.glDisable(ctx, GLenum_GL_STENCIL_TEST) - t.makeVertexArray(ctx, aScreenCoordsLocation) - t.glViewport(ctx, 0, 0, ws, hs) - - // Create a program, link, and use it. - programID := t.makeProgram(ctx, vertexShaderSource, fragmentShaderSource) - tmp0 := t.AllocData(ctx, aScreenCoords) - out.MutateAndWrite(ctx, dID, cb.GlBindAttribLocation(programID, aScreenCoordsLocation, tmp0.Ptr()). - AddRead(tmp0.Data())) - tmp0.Free() - - attrib := MakeProgramResourceʳ(s.Arena) - attrib.SetType(GLenum_GL_FLOAT_VEC2) - attrib.SetName(aScreenCoords) - attrib.SetArraySize(1) - attrib.SetLocations(NewU32ːGLintᵐ(s.Arena).Add(0, 0)) - - unif := MakeProgramResourceʳ(s.Arena) - unif.SetType(GLenum_GL_SAMPLER_2D) - unif.SetName(uTexture) - unif.SetArraySize(1) - unif.SetLocations(NewU32ːGLintᵐ(s.Arena).Add(0, 0)) - - resources := MakeActiveProgramResourcesʳ(s.Arena) - resources.SetProgramInputs(NewU32ːProgramResourceʳᵐ(s.Arena).Add(0, attrib)) - resources.SetDefaultUniformBlock(NewUniformIndexːProgramResourceʳᵐ(s.Arena).Add(UniformIndex(0), unif)) - - extra := MakeLinkProgramExtra(s.Arena) - extra.SetLinkStatus(GLboolean_GL_TRUE) - extra.SetActiveResources(resources) - out.MutateAndWrite(ctx, dID, api.WithExtras(cb.GlLinkProgram(programID), extra)) - tmp1 := t.AllocData(ctx, uTexture) - out.MutateAndWrite(ctx, dID, cb.GlGetUniformLocation(programID, tmp1.Ptr(), uTextureLocation). - AddRead(tmp1.Data())) - tmp1.Free() - t.glUseProgram(ctx, programID) - - // Create a buffer and fill it. - bufferID := t.glGenBuffer(ctx) - t.GlBindBuffer_ArrayBuffer(ctx, bufferID) - - tmp2 := t.AllocData(ctx, positions) - out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_ARRAY_BUFFER, GLsizeiptr(4*len(positions)), tmp1.Ptr(), GLenum_GL_STATIC_DRAW). - AddRead(tmp2.Data())) - tmp2.Free() - - // Render a textured quad. - out.MutateAndWrite(ctx, dID, cb.GlVertexAttribPointer(aScreenCoordsLocation, 2, GLenum_GL_FLOAT, GLboolean(0), 0, memory.Nullptr)) - out.MutateAndWrite(ctx, dID, cb.GlDrawArrays(GLenum_GL_TRIANGLE_STRIP, 0, 4)) - - // Leave the tweaker with the read fb binding containing the depth in the color attachemnt. - t.glBindFramebuffer_Read(ctx, fb) -} diff --git a/gapis/api/gles/read_framebuffer.go b/gapis/api/gles/read_framebuffer.go deleted file mode 100644 index 4b9824c0a5..0000000000 --- a/gapis/api/gles/read_framebuffer.go +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/context/keys" - "github.com/google/gapid/core/data/binary" - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/stream" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/messages" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/replay/builder" - "github.com/google/gapid/gapis/replay/protocol" - "github.com/google/gapid/gapis/replay/value" - "github.com/google/gapid/gapis/service" -) - -type readFramebuffer struct { - transform.Tasks - targetVersion *Version -} - -func newReadFramebuffer(ctx context.Context, device *device.Instance) *readFramebuffer { - targetVersion, _ := ParseVersion(device.Configuration.Drivers.Opengl.Version) - return &readFramebuffer{targetVersion: targetVersion} -} - -func getBoundFramebufferID(thread uint64, s *api.GlobalState) (FramebufferId, error) { - c := GetContext(s, thread) - if c.IsNil() { - return 0, fmt.Errorf("No OpenGL ES context") - } - if c.Bound().DrawFramebuffer().IsNil() { - return 0, fmt.Errorf("No framebuffer bound") - } - return c.Bound().DrawFramebuffer().GetID(), nil -} - -func (t *readFramebuffer) depth( - id api.CmdID, - thread uint64, - fb FramebufferId, - res replay.Result) { - - t.Add(id, func(ctx context.Context, out transform.Writer) { - postFBData(ctx, id, thread, 0, 0, fb, GLenum_GL_DEPTH_ATTACHMENT, t.targetVersion, out, res) - }) -} - -func (t *readFramebuffer) color( - id api.CmdID, - thread uint64, - width, height uint32, - fb FramebufferId, - bufferIdx uint32, - res replay.Result) { - - t.Add(id, func(ctx context.Context, out transform.Writer) { - attachment := GLenum_GL_COLOR_ATTACHMENT0 + GLenum(bufferIdx) - postFBData(ctx, id, thread, width, height, fb, attachment, t.targetVersion, out, res) - }) -} - -func postFBData(ctx context.Context, - id api.CmdID, - thread uint64, - width, height uint32, - fb FramebufferId, - attachment GLenum, - version *Version, - out transform.Writer, - res replay.Result) { - - s := out.State() - c := GetContext(s, thread) - - if fb == 0 { - var err error - if fb, err = getBoundFramebufferID(thread, s); err != nil { - log.W(ctx, "Could not read framebuffer after cmd %v: %v", id, err) - res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()}) - return - } - } - - fbai, err := GetState(s).getFramebufferAttachmentInfo(thread, fb, attachment) - if err != nil { - log.W(ctx, "Failed to read framebuffer after cmd %v: %v", id, err) - res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()}) - return - } - if fbai.sizedFormat == 0 { - log.W(ctx, "Failed to read framebuffer after cmd %v: no image format", id) - res(nil, &service.ErrDataUnavailable{Reason: messages.ErrFramebufferUnavailable()}) - return - } - - var ( - inW = int32(fbai.width) - inH = int32(fbai.height) - outW = int32(width) - outH = int32(height) - ) - - if outW == 0 { - outW = inW - } - if outH == 0 { - outH = inH - } - - dID := id.Derived() - cb := CommandBuilder{Thread: thread, Arena: s.Arena} - t := newTweaker(out, dID, cb) - defer t.revert(ctx) - t.glBindFramebuffer_Read(ctx, fb) - - unsizedFormat, ty := getUnsizedFormatAndType(fbai.sizedFormat) - - imgFmt, err := getImageFormat(unsizedFormat, ty) - if err != nil { - res(nil, err) - return - } - - channels := imgFmt.Channels() - hasColor := channels.ContainsColor() - hasDepth := channels.ContainsDepth() - hasStencil := channels.ContainsStencil() - - if hasColor && (hasDepth || hasStencil) { - // Sanity check. - // If this fails, the logic of this function has to be rewritten. - panic("Found framebuffer attachment with both color and depth/stencil components!") - } - - // Error out early if trying to read depth data on GLES 2. - if hasDepth && version.IsES && version.Major == 2 { - res(nil, &service.ErrDataUnavailable{Reason: messages.ErrDepthBufferNotSupported()}) - return - } - - bufferBits := GLbitfield(0) - if hasColor { - bufferBits |= GLbitfield_GL_COLOR_BUFFER_BIT - } - if hasDepth { - bufferBits |= GLbitfield_GL_DEPTH_BUFFER_BIT - } - if hasStencil { - bufferBits |= GLbitfield_GL_STENCIL_BUFFER_BIT - } - - if (attachment == GLenum_GL_DEPTH_ATTACHMENT || attachment == GLenum_GL_STENCIL_ATTACHMENT) && - hasDepth && hasStencil { - // The caller of this function has specified that they want either the - // depth or the stencil buffer, but the FBO is actually depth and - // stencil. - // - // To keep the replay logic sane, preserve both depth and stencil data - // and post both back to GAPIS. We then can strip out the unwanted - // component. - var outputFormat *image.Format - if attachment == GLenum_GL_DEPTH_ATTACHMENT { - outputFormat = filterUncompressedImageFormat(imgFmt, stream.Channel.IsDepth) - } else { - outputFormat = filterUncompressedImageFormat(imgFmt, stream.Channel.IsStencil) - } - res = res.Transform(func(in interface{}) (interface{}, error) { - return in.(*image.Data).Convert(outputFormat) - }) - - attachment = GLenum_GL_DEPTH_STENCIL_ATTACHMENT - } - - if hasColor { - if c.Bound().DrawFramebuffer() == c.Objects().Default().Framebuffer() { - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - // TODO: We assume here that the default framebuffer is - // single-buffered. Once we support double-buffering we - // need to decide whether to read from GL_FRONT or GL_BACK. - buf := GLenum_GL_BACK - if !version.IsES { - // OpenGL expects GL_FRONT for single-buffered - // configurations. Note this is not a legal value for GLES. - buf = GLenum_GL_FRONT - } - cb.GlReadBuffer(buf).Call(ctx, s, b) - return nil - })) - } else { - t.glReadBuffer(ctx, attachment) - } - } - - if fbai.multisampled { - // Resolve - t.glScissor(ctx, 0, 0, GLsizei(inW), GLsizei(inH)) - framebufferID := t.glGenFramebuffer(ctx) - t.glBindFramebuffer_Draw(ctx, framebufferID) - renderbufferID := t.glGenRenderbuffer(ctx) - t.glBindRenderbuffer(ctx, renderbufferID) - - if hasColor { - // Blit defaults to color attachment 0. attaching there avoids - // having to setup the read/draw buffer mappings. - attachment = GLenum_GL_COLOR_ATTACHMENT0 - } - - mutateAndWriteEach(ctx, out, dID, - cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, fbai.sizedFormat, GLsizei(inW), GLsizei(inH)), - cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, attachment, GLenum_GL_RENDERBUFFER, renderbufferID), - cb.GlBlitFramebuffer(0, 0, GLint(inW), GLint(inH), 0, 0, GLint(inW), GLint(inH), bufferBits, GLenum_GL_NEAREST), - ) - - t.glBindFramebuffer_Read(ctx, framebufferID) - t.glReadBuffer(ctx, attachment) - } - - // These are formats that are required to be supported by GLES glReadPixels. - // See section 4.3.2 of the GLES 3.0 spec. - needFBQuery := version.IsES && !((unsizedFormat == GLenum_GL_RGBA && ty == GLenum_GL_UNSIGNED_BYTE) || - (unsizedFormat == GLenum_GL_RGBA && ty == GLenum_GL_UNSIGNED_INT_2_10_10_10_REV) || - (unsizedFormat == GLenum_GL_RGBA_INTEGER && ty == GLenum_GL_INT) || - (unsizedFormat == GLenum_GL_RGBA_INTEGER && ty == GLenum_GL_UNSIGNED_INT)) - - needResize := hasColor && (inW != outW || inH != outH) - // If we need to ask the driver what format to use to read the pixels, due - // to driver issues, it needs to be COLOR_ATTACHMENT0. See b/115574126. - needColorAtt0 := needFBQuery && hasColor && attachment != GLenum_GL_COLOR_ATTACHMENT0 - - if needResize || needColorAtt0 { - t.glScissor(ctx, 0, 0, GLsizei(inW), GLsizei(inH)) - framebufferID := t.glGenFramebuffer(ctx) - t.glBindFramebuffer_Draw(ctx, framebufferID) - renderbufferID := t.glGenRenderbuffer(ctx) - t.glBindRenderbuffer(ctx, renderbufferID) - - // Blit defaults to color attachment 0. Attaching there avoids having to - // setup the read/draw buffer mappings. - attachment = GLenum_GL_COLOR_ATTACHMENT0 - sampling := GLenum_GL_NEAREST - if needResize { - sampling = GLenum_GL_LINEAR - } - - mutateAndWriteEach(ctx, out, dID, - cb.GlRenderbufferStorage(GLenum_GL_RENDERBUFFER, fbai.sizedFormat, GLsizei(outW), GLsizei(outH)), - cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, attachment, GLenum_GL_RENDERBUFFER, renderbufferID), - cb.GlBlitFramebuffer(0, 0, GLint(inW), GLint(inH), 0, 0, GLint(outW), GLint(outH), bufferBits, sampling), - ) - t.glBindFramebuffer_Read(ctx, framebufferID) - } - - if hasDepth && version.IsES { - copyDepthToColorGLES(ctx, dID, thread, s, out, t, fbai, inW, inH) - } - - if needFBQuery { - // Can only query the FB if bound to GL_FRAMEBUFFER. See b/115574126. - t.glBindFramebuffer_ReadToBoth(ctx) - } - - t.setPackStorage(ctx, NewPixelStorageState(s.Arena, - 0, // ImageHeight - 0, // SkipImages - 0, // RowLength - 0, // SkipRows - 0, // SkipPixels - 1, // Alignment - ), 0) - - imageSize := imgFmt.Size(int(outW), int(outH), 1) - bufferSize := imageSize - if needFBQuery { - // Since we have no idea what format the data will be in, we need to be - // as pessimistic as possible. Assume 4 channels at 4 bytes each, which - // is the maximum possible by GLES. We also need space to store the - // format and type (2 4byte enums) as well as the GL error (4 byte enum). - bufferSize = 16*int(outW)*int(outH) + 8 + 4 - } - - tmp := s.AllocOrPanic(ctx, uint64(bufferSize)) - defer tmp.Free() - - out.MutateAndWrite(ctx, dID, cb.Custom(func(ctx context.Context, s *api.GlobalState, b *builder.Builder) error { - b.ReserveMemory(tmp.Range()) - - if needFBQuery { - ptr := value.ObservedPointer(tmp.Address()) - // Clear the GL error - b.Call(funcInfoGlGetError) - b.Pop(1) - // Query the driver for the format and type that glReadPixels supports. - b.Push(value.U32(GLenum_GL_IMPLEMENTATION_COLOR_READ_FORMAT)) - b.Push(ptr.Offset(0)) - b.Call(funcInfoGlGetIntegerv) - - b.Push(value.U32(GLenum_GL_IMPLEMENTATION_COLOR_READ_TYPE)) - b.Push(ptr.Offset(4)) - b.Call(funcInfoGlGetIntegerv) - - // Call glReadPixels with the above returned format and type. - b.Push(value.S32(0)) // x - b.Push(value.S32(0)) // y - b.Push(value.S32(outW)) // width - b.Push(value.S32(outH)) // height - b.Load(protocol.Type_Uint32, ptr.Offset(0)) // format - b.Load(protocol.Type_Uint32, ptr.Offset(4)) // type - b.Push(ptr.Offset(12)) // pixels - b.Call(funcInfoGlReadPixels) - // Get the GL error. - b.Call(funcInfoGlGetError) - b.Store(ptr.Offset(8)) - } else { - // We use Call() directly here because on host replay, we are calling - // glReadPixels with depth formats which are not legal for GLES. - cb.GlReadPixels(0, 0, GLsizei(outW), GLsizei(outH), unsizedFormat, ty, tmp.Ptr()). - Call(ctx, s, b) - } - - b.Post(value.ObservedPointer(tmp.Address()), uint64(bufferSize), func(r binary.Reader, err error) { - res.Do(func() (interface{}, error) { - if err != nil { - return nil, err - } - - u, t, e := unsizedFormat, ty, GLenum_GL_NO_ERROR - if needFBQuery { - u, t, e = GLenum(r.Int32()), GLenum(r.Int32()), GLenum(r.Int32()) - bufferSize -= 12 - } - if e != GLenum_GL_NO_ERROR { - return nil, fmt.Errorf("GL error reading pixels from framebuffer: %s", e) - } - - data := make([]byte, bufferSize) - r.Data(data) - if err := r.Error(); err != nil { - return nil, fmt.Errorf("Could not read framebuffer data (expected length %d bytes): %v", bufferSize, err) - } - - if u == unsizedFormat && t == ty { - return &image.Data{ - Bytes: data[:imageSize], - Width: uint32(outW), - Height: uint32(outH), - Depth: 1, - Format: imgFmt, - }, nil - } - - // We had to query the driver for the format and it is different - // than what was requested, So, we need to convert it. Also - // handles the case where we read depth as color. - - f, err := getImageFormat(u, t) - if err != nil { - return nil, err - } - - img := &image.Data{ - Bytes: data[:f.Size(int(outW), int(outH), 1)], - Width: uint32(outW), - Height: uint32(outH), - Depth: 1, - Format: f, - } - - if hasDepth { - // Filter out the red channel and then pretend it's just depth. - redFmt := filterUncompressedImageFormat(f, func(c stream.Channel) bool { - return c == stream.Channel_Red - }) - var err error - if img, err = img.Convert(redFmt); err != nil { - return nil, err - } - depthFmt, err := getImageFormat(GLenum_GL_DEPTH_COMPONENT, t) - if err != nil { - return nil, err - } - img.Format = depthFmt - return img, nil - } - - return img.Convert(imgFmt) - }) - }) - return nil - })) - - out.MutateAndWrite(ctx, dID, cb.GlGetError(0)) // Check for errors. -} - -func mutateAndWriteEach(ctx context.Context, out transform.Writer, id api.CmdID, cmds ...api.Cmd) { - for _, cmd := range cmds { - out.MutateAndWrite(ctx, id, cmd) - } -} - -type nextUnusedIDKeyTy string - -const nextUnusedIDKey = nextUnusedIDKeyTy("nextUnusedID") - -func PutUnusedIDMap(ctx context.Context) context.Context { - return keys.WithValue(ctx, nextUnusedIDKey, map[rune]uint32{}) -} - -// newUnusedID returns temporary object ID. -// The tag makes the IDs for given object type more deterministic. -func newUnusedID(ctx context.Context, tag rune, existenceTest func(uint32) bool) uint32 { - val := ctx.Value(nextUnusedIDKey) - if val == nil { - panic(nextUnusedIDKey + " missing from context") - } - nextUnusedID := val.(map[rune]uint32) - - // Use the tag to allocate from different ranges. - prefix := uint32(tag) - if prefix == 0 || prefix > 128 { - panic(fmt.Errorf("Expected ASCII character")) - } - prefix = prefix * 10000000 - // Get the next ID and make sure it is free. - for { - nextUnusedID[tag]++ - x := prefix + nextUnusedID[tag] - if !existenceTest(x) && x != 0 { - return x - } - } -} diff --git a/gapis/api/gles/read_texture.go b/gapis/api/gles/read_texture.go deleted file mode 100644 index c5d24a1c2c..0000000000 --- a/gapis/api/gles/read_texture.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/service" -) - -type textureRequest struct { - data *ReadGPUTextureDataResolveable -} - -type readTexture struct { - transform.Tasks - targetVersion *Version -} - -func newReadTexture(ctx context.Context, device *device.Instance) *readTexture { - targetVersion, _ := ParseVersion(device.Configuration.Drivers.Opengl.Version) - return &readTexture{targetVersion: targetVersion} -} - -func (t *readTexture) add(ctx context.Context, r *ReadGPUTextureDataResolveable, res replay.Result) { - id := api.CmdID(r.After) - t.Add(id, func(ctx context.Context, out transform.Writer) { - s := out.State() - c := GetContext(s, r.Thread) - - if c.IsNil() { - err := fmt.Errorf("Attempting to read from texture %v when context does not exist.\n"+ - "Resolvable: %+v", r.Texture, r) - log.W(ctx, "%v", err) - res(nil, err) - return - } - - dID := id.Derived() - cb := CommandBuilder{Thread: r.Thread, Arena: s.Arena} - - tex, ok := c.Objects().Textures().Lookup(TextureId(r.Texture)) - if !ok { - err := fmt.Errorf("Attempting to read from texture %v that does not exist.\n"+ - "Resolvable: %+v\nTexture: %+v", r.Texture, r, tex) - log.W(ctx, "%v", err) - res(nil, err) - return - } - lvl := tex.Levels().Get(GLint(r.Level)) - layer := lvl.Layers().Get(GLint(r.Layer)) - if layer.IsNil() { - err := fmt.Errorf("Attempting to read from texture %v (Level: %v/%v, Layer: %v/%v) that does not exist.\n"+ - "Resolvable: %+v\n"+ - "Texture: %+v", - r.Texture, r.Level, tex.Levels().Len(), r.Layer, lvl.Layers().Len(), r, tex) - log.W(ctx, "%v", err) - res(nil, err) - return - } - - tw := newTweaker(out, dID, cb) - defer tw.revert(ctx) - - framebufferID := tw.glGenFramebuffer(ctx) - tw.glBindFramebuffer_Draw(ctx, framebufferID) - - streamFmt, err := getUncompressedStreamFormat(getUnsizedFormatAndType(layer.SizedFormat())) - if err != nil { - res(nil, err) - return - } - - var attachment GLenum - channels := streamFmt.Channels() - switch { - case channels.ContainsColor(): - attachment = GLenum_GL_COLOR_ATTACHMENT0 - case channels.ContainsDepth() && channels.ContainsStencil(): - attachment = GLenum_GL_DEPTH_STENCIL_ATTACHMENT - case channels.ContainsDepth(): - attachment = GLenum_GL_DEPTH_ATTACHMENT - case channels.ContainsStencil(): - attachment = GLenum_GL_STENCIL_ATTACHMENT - default: - res(nil, fmt.Errorf("Unsupported texture format %v", streamFmt)) - return - } - - switch tex.Kind() { - case GLenum_GL_TEXTURE_3D, - GLenum_GL_IMAGE_CUBE_MAP_ARRAY, - GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY, - GLenum_GL_TEXTURE_2D_ARRAY, - GLenum_GL_TEXTURE_1D_ARRAY: - - out.MutateAndWrite(ctx, dID, cb.GlFramebufferTextureLayer(GLenum_GL_DRAW_FRAMEBUFFER, attachment, tex.ID(), GLint(r.Level), GLint(r.Layer))) - - case GLenum_GL_TEXTURE_CUBE_MAP: - face := GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(r.Layer) - out.MutateAndWrite(ctx, dID, cb.GlFramebufferTexture2D(GLenum_GL_DRAW_FRAMEBUFFER, attachment, face, tex.ID(), GLint(r.Level))) - - default: - out.MutateAndWrite(ctx, dID, cb.GlFramebufferTexture(GLenum_GL_DRAW_FRAMEBUFFER, attachment, tex.ID(), GLint(r.Level))) - } - - // Compat may have altered the texture format. - // The caller expects the data in the texture's authored format. - // Convert. - f, err := getImageFormat(GLenum(r.DataFormat), GLenum(r.DataType)) - if err != nil { - res(nil, err) - return - } - res = res.Transform(func(in interface{}) (interface{}, error) { - return in.(*image.Data).Convert(f) - }) - - postFBData(ctx, dID, r.Thread, uint32(layer.Width()), uint32(layer.Height()), framebufferID, attachment, t.targetVersion, out, res) - }) -} - -// Resolve implements the database.Resolver interface. -func (r *ReadGPUTextureDataResolveable) Resolve(ctx context.Context) (interface{}, error) { - c := drawConfig{} - mgr := replay.GetManager(ctx) - intent := replay.Intent{ - Device: r.Device, - Capture: r.Capture, - } - hints := &service.UsageHints{} - res, err := mgr.Replay(ctx, intent, c, textureRequest{r}, API{}, hints, true) - if err != nil { - return nil, err - } - return res.(*image.Data).Bytes, nil -} diff --git a/gapis/api/gles/replay.go b/gapis/api/gles/replay.go deleted file mode 100644 index 592c6c902a..0000000000 --- a/gapis/api/gles/replay.go +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "strings" - - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/config" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/resolve/dependencygraph" - "github.com/google/gapid/gapis/service" -) - -var ( - // Interface compliance tests - _ = replay.QueryIssues(API{}) - _ = replay.QueryFramebufferAttachment(API{}) - _ = replay.Support(API{}) - _ = replay.Profiler(API{}) -) - -// issuesConfig is a replay.Config used by issuesRequests. -type issuesConfig struct{} - -// drawConfig is a replay.Config used by colorBufferRequest and -// depthBufferRequests. -type drawConfig struct { - drawMode service.DrawMode - wireframeOverlayID api.CmdID // used when drawMode == DrawMode_WIREFRAME_OVERLAY - wireframeFramebufferID FramebufferId // used when drawMode == DrawMode_WIREFRAME_ALL - disableReplayOptimization bool -} - -// uniqueConfig returns a replay.Config that is guaranteed to be unique. -// Any requests made with a Config returned from uniqueConfig will not be -// batched with any other request. -func uniqueConfig() replay.Config { - return &struct{}{} -} - -// issuesRequest requests all issues found during replay to be reported to out. -type issuesRequest struct{} - -// framebufferRequest requests a postback of a framebuffer's attachment. -type framebufferRequest struct { - after api.CmdID - width, height uint32 - fb FramebufferId - attachment api.FramebufferAttachment - wireframeOverlay bool -} - -type profileRequest struct { -} - -// GetReplayPriority returns a uint32 representing the preference for -// replaying this trace on the given device. -// A lower number represents a higher priority, and zero represents -// an inability for the trace to be replayed on the given device. -func (a API) GetReplayPriority(ctx context.Context, i *device.Instance, h *capture.Header) uint32 { - v, err := ParseVersion(i.GetConfiguration().GetDrivers().GetOpengl().GetVersion()) - if err != nil { - return 0 // Can't figure out what we're dealing with. - } - - switch { - case v.AtLeastES(3, 0): - traceDev := h.GetDevice() - devHardware, traceHardware := i.GetConfiguration().GetHardware(), traceDev.GetConfiguration().GetHardware() - devOS, traceOS := i.GetConfiguration().GetOS(), traceDev.GetConfiguration().GetOS() - - if s1, s2 := i.GetSerial(), traceDev.GetSerial(); s1 != "" && s1 == s2 { - return 1 // Serial matches that of device the trace was captured on. - } - if h1, h2 := devHardware.GetName(), traceHardware.GetName(); h1 != "" && h1 == h2 { - return 2 // Same hardware device name. - } - - for _, abi := range i.GetConfiguration().GetABIs() { - if abi.SameAs(h.GetABI()) { - if b1, b2 := devOS.GetBuild(), traceOS.GetBuild(); b1 != "" && b1 == b2 { - return 3 // Same OS build. - } - switch devOS.CompareVersions(traceOS) { - case device.CompleteMatch: - return 4 // Same OS version - case device.MajorAndMinorMatch: - return 5 // Same major.minor OS version. - case device.MajorMatch: - return 6 // Same major OS version. - default: - return 7 // Different major version. - } - } - } - return 0 // Device does not support capture ABI. - case v.IsES: - return 0 // Can't replay on this version of an ES device. - default: - return 8 // Desktop GL can be used with heavy use of compat. - } -} - -func (a API) Replay( - ctx context.Context, - intent replay.Intent, - cfg replay.Config, - dependentPayload string, - rrs []replay.RequestAndResult, - device *device.Instance, - capture *capture.GraphicsCapture, - out transform.Writer) error { - if dependentPayload != "" { - return log.Errf(ctx, nil, "GLES does not support dependent payloads") - } - if a.GetReplayPriority(ctx, device, capture.Header) == 0 { - return log.Errf(ctx, nil, "Cannot replay GLES commands on device '%v'", device.Name) - } - - ctx = PutUnusedIDMap(ctx) - - cmds := capture.Commands - - // Gathers and reports any issues found. - var issues *findIssues - - // Prepare data for dead-code-elimination. - dependencyGraph, err := dependencygraph.GetDependencyGraph(ctx, intent.Device) - if err != nil { - return err - } - - // Skip unnecessary commands. - deadCodeElimination := dependencygraph.NewDeadCodeElimination(ctx, dependencyGraph) - deadCodeElimination.KeepAllAlive = config.DisableDeadCodeElimination - - var rf *readFramebuffer // Transform for all framebuffer reads. - var rt *readTexture // Transform for all texture reads. - - var wire transform.Transformer - - transforms := transform.Transforms{deadCodeElimination} - - onCompatError := func(ctx context.Context, id api.CmdID, cmd api.Cmd, err error) { - ctx = log.Enter(ctx, "Compat") - log.E(ctx, "%v: %v - %v", id, cmd, err) - } - - var profile *replay.EndOfReplay - - for _, rr := range rrs { - switch req := rr.Request.(type) { - case issuesRequest: - deadCodeElimination.KeepAllAlive = true - if issues == nil { - issues = newFindIssues(ctx, capture, device) - } - issues.AddResult(rr.Result) - onCompatError = func(ctx context.Context, id api.CmdID, cmd api.Cmd, err error) { - issues.onIssue(cmd, id, service.Severity_ErrorLevel, err) - } - - case textureRequest: - if rt == nil { - rt = newReadTexture(ctx, device) - } - after := api.CmdID(req.data.After) - deadCodeElimination.Request(after) - rt.add(ctx, req.data, rr.Result) - - case framebufferRequest: - if rf == nil { - rf = newReadFramebuffer(ctx, device) - } - deadCodeElimination.Request(req.after) - - thread := cmds[req.after].Thread() - switch req.attachment { - case api.FramebufferAttachment_Depth: - rf.depth(req.after, thread, req.fb, rr.Result) - case api.FramebufferAttachment_Stencil: - return fmt.Errorf("Stencil buffer attachments are not currently supported") - default: - idx := uint32(req.attachment - api.FramebufferAttachment_Color0) - rf.color(req.after, thread, req.width, req.height, req.fb, idx, rr.Result) - } - - cfg := cfg.(drawConfig) - if cfg.disableReplayOptimization { - deadCodeElimination.KeepAllAlive = true - } - switch cfg.drawMode { - case service.DrawMode_WIREFRAME_ALL: - wire = wireframe(ctx, cfg.wireframeFramebufferID) - case service.DrawMode_WIREFRAME_OVERLAY: - wire = wireframeOverlay(ctx, req.after) - case service.DrawMode_OVERDRAW: - return fmt.Errorf("Overdraw is not currently supported for GLES") - } - - case profileRequest: - if profile == nil { - profile = &replay.EndOfReplay{} - } - profile.AddResult(rr.Result) - } - } - - if wire != nil { - transforms.Add(wire) - } - - if issues != nil { - transforms.Add(issues) // Issue reporting required. - } - - // Render pattern for undefined framebuffers. - // Needs to be after 'issues' which uses absence of draw calls to find undefined framebuffers. - transforms.Add(undefinedFramebuffer(ctx, device)) - - if rt != nil { - transforms.Add(rt) - } - if rf != nil { - transforms.Add(rf) - } - - if profile != nil { - // Don't use DCE. - transforms = transform.Transforms{profile} - } - - // Device-dependent transforms. - compatTransform, err := compat(ctx, device, onCompatError) - if err == nil { - transforms.Add(compatTransform) - } else { - log.E(ctx, "Error creating compatability transform: %v", err) - } - - // Cleanup - transforms.Add(&destroyResourcesAtEOS{}) - - if config.DebugReplay { - log.I(ctx, "Replaying %d commands using transform chain:", len(cmds)) - for i, t := range transforms { - log.I(ctx, "(%d) %#v", i, t) - } - } - - if config.LogTransformsToFile { - newTransforms := transform.Transforms{} - for i, t := range transforms { - name := fmt.Sprintf("%T", t) - if n, ok := t.(interface { - Name() string - }); ok { - name = n.Name() - } else if dot := strings.LastIndex(name, "."); dot != -1 { - name = name[dot+1:] - } - newTransforms.Add(t, transform.NewFileLog(ctx, fmt.Sprintf("%v.%v_%v", capture.Name, i, name))) - } - transforms = newTransforms - } - if config.LogTransformsToCapture { - transforms.Add(transform.NewCaptureLog(ctx, capture, "replay_log.gfxtrace")) - } - - if profile == nil { - cmds = []api.Cmd{} // DeadCommandRemoval generates commands. - } - return transforms.TransformAll(ctx, cmds, 0, out) -} - -func (a API) QueryIssues( - ctx context.Context, - intent replay.Intent, - mgr replay.Manager, - loopCount int32, - displayToSurface bool, - hints *service.UsageHints) ([]replay.Issue, error) { - - if loopCount != 1 { - return nil, log.Errf(ctx, nil, "GLES does not support frame looping") - } - - c, r := issuesConfig{}, issuesRequest{} - res, err := mgr.Replay(ctx, intent, c, r, a, hints, true) - if err != nil { - return nil, err - } - return res.([]replay.Issue), nil -} - -func (a API) QueryFramebufferAttachment( - ctx context.Context, - intent replay.Intent, - mgr replay.Manager, - after []uint64, - width, height uint32, - attachment api.FramebufferAttachment, - framebufferIndex uint32, - drawMode service.DrawMode, - disableReplayOptimization bool, - displayToSurface bool, - hints *service.UsageHints) (*image.Data, error) { - - if len(after) > 1 { - return nil, log.Errf(ctx, nil, "GLES does not support subcommands") - } - - c := drawConfig{drawMode: drawMode, disableReplayOptimization: disableReplayOptimization} - switch drawMode { - case service.DrawMode_WIREFRAME_OVERLAY: - c.wireframeOverlayID = api.CmdID(after[0]) - - case service.DrawMode_WIREFRAME_ALL: - c.wireframeFramebufferID = FramebufferId(framebufferIndex) - } - - r := framebufferRequest{ - after: api.CmdID(after[0]), - width: width, - height: height, - fb: FramebufferId(framebufferIndex), - attachment: attachment, - } - res, err := mgr.Replay(ctx, intent, c, r, a, hints, true) - if err != nil { - return nil, err - } - return res.(*image.Data), nil -} - -func (a API) Profile( - ctx context.Context, - intent replay.Intent, - mgr replay.Manager, - hints *service.UsageHints, - traceOptions *service.TraceOptions) (*service.ProfilingData, error) { - - c := uniqueConfig() - r := profileRequest{} - - _, err := mgr.Replay(ctx, intent, c, r, a, hints, true) - return nil, err -} - -// destroyResourcesAtEOS is a transform that destroys all textures, -// framebuffers, buffers, shaders, programs and vertex-arrays that were not -// destroyed by EOS. -type destroyResourcesAtEOS struct { -} - -func (t *destroyResourcesAtEOS) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - return out.MutateAndWrite(ctx, id, cmd) -} - -func (t *destroyResourcesAtEOS) Flush(ctx context.Context, out transform.Writer) error { - s := out.State() - cmds := []api.Cmd{} - - // Start by unbinding all the contexts from all the threads. - for t, c := range GetState(s).Contexts().All() { - if c.IsNil() { - continue - } - cb := CommandBuilder{Thread: t, Arena: s.Arena} - cmds = append(cmds, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, memory.Nullptr, 1)) - } - - // Now using a single thread, bind each context and delete all objects. - cb := CommandBuilder{Thread: 0, Arena: s.Arena} - for i, c := range GetState(s).EGLContexts().All() { - if !c.Other().Initialized() { - // This context was never bound. Skip it. - continue - } - - cmds = append(cmds, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, i, 1)) - - // Delete all Renderbuffers. - renderbuffers := make([]RenderbufferId, 0, c.Objects().Renderbuffers().Len()) - for renderbufferID := range c.Objects().Renderbuffers().All() { - // Skip virtual renderbuffers: backbuffer_color(-1), backbuffer_depth(-2), backbuffer_stencil(-3). - if renderbufferID < 0xf0000000 { - renderbuffers = append(renderbuffers, renderbufferID) - } - } - if len(renderbuffers) > 0 { - tmp := s.AllocDataOrPanic(ctx, renderbuffers) - cmds = append(cmds, cb.GlDeleteRenderbuffers(GLsizei(len(renderbuffers)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Delete all Textures. - textures := make([]TextureId, 0, c.Objects().Textures().Len()) - for textureID := range c.Objects().Textures().All() { - textures = append(textures, textureID) - } - if len(textures) > 0 { - tmp := s.AllocDataOrPanic(ctx, textures) - cmds = append(cmds, cb.GlDeleteTextures(GLsizei(len(textures)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Delete all Framebuffers. - framebuffers := make([]FramebufferId, 0, c.Objects().Framebuffers().Len()) - for framebufferID := range c.Objects().Framebuffers().All() { - framebuffers = append(framebuffers, framebufferID) - } - if len(framebuffers) > 0 { - tmp := s.AllocDataOrPanic(ctx, framebuffers) - cmds = append(cmds, cb.GlDeleteFramebuffers(GLsizei(len(framebuffers)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Delete all Buffers. - buffers := make([]BufferId, 0, c.Objects().Buffers().Len()) - for bufferID := range c.Objects().Buffers().All() { - buffers = append(buffers, bufferID) - } - if len(buffers) > 0 { - tmp := s.AllocDataOrPanic(ctx, buffers) - cmds = append(cmds, cb.GlDeleteBuffers(GLsizei(len(buffers)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Delete all VertexArrays. - vertexArrays := make([]VertexArrayId, 0, c.Objects().VertexArrays().Len()) - for vertexArrayID := range c.Objects().VertexArrays().All() { - vertexArrays = append(vertexArrays, vertexArrayID) - } - if len(vertexArrays) > 0 { - tmp := s.AllocDataOrPanic(ctx, vertexArrays) - cmds = append(cmds, cb.GlDeleteVertexArrays(GLsizei(len(vertexArrays)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Delete all Shaders. - for _, shaderID := range c.Objects().Shaders().Keys() { - cmds = append(cmds, cb.GlDeleteShader(shaderID)) - } - - // Delete all Programs. - for _, programID := range c.Objects().Programs().Keys() { - cmds = append(cmds, cb.GlDeleteProgram(programID)) - } - - // Delete all Queries. - queries := make([]QueryId, 0, c.Objects().Queries().Len()) - for queryID := range c.Objects().Queries().All() { - queries = append(queries, queryID) - } - if len(queries) > 0 { - tmp := s.AllocDataOrPanic(ctx, queries) - cmds = append(cmds, cb.GlDeleteQueries(GLsizei(len(queries)), tmp.Ptr()).AddRead(tmp.Data())) - } - - // Flush all buffered commands before proceeding to the next context. - // Contexts can share objects - e.g. several contexts can contain the same buffer. - // Mutating the delete command ensures the object is removed from all maps, - // and that we will not try to remove it again when iterating over the second context. - cmds = append(cmds, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, memory.Nullptr, 1)) - err := api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - return out.MutateAndWrite(ctx, api.CmdNoID, cmd) - }) - if err != nil { - return err - } - cmds = []api.Cmd{} - } - return nil -} - -func (t *destroyResourcesAtEOS) PreLoop(ctx context.Context, out transform.Writer) {} -func (t *destroyResourcesAtEOS) PostLoop(ctx context.Context, out transform.Writer) {} -func (t *destroyResourcesAtEOS) BuffersCommands() bool { return false } diff --git a/gapis/api/gles/replay.todo b/gapis/api/gles/replay.todo deleted file mode 100644 index 402c0b3fff..0000000000 --- a/gapis/api/gles/replay.todo +++ /dev/null @@ -1,14 +0,0 @@ - -No-alpha framebuffer formats aren't correctly replayed. -------------------------------------------------------- - -RGB565 is a commonly used framebuffer format which is not widely supported on -desktop. Worse still, many desktop drivers have no option for creating a -framebuffer with no alpha channel. For no-alpha framebuffer formats, blending -operations will typically also affect the alpha channel, which is only visible -when replaying with an alpha-channelled framebuffer. We work around this most -common issue by clearing the alpha to 0xff in postColorData. -This does not solve potential blending issues where a trace performs: - glBlendFunc(GL_DST_ALPHA, X) - glBlendFunc(GL_ONE_MINUS_DST_ALPHA, X) -As this will have RGB differences between capture and replay. diff --git a/gapis/api/gles/resolvables.proto b/gapis/api/gles/resolvables.proto deleted file mode 100644 index 52cb10918c..0000000000 --- a/gapis/api/gles/resolvables.proto +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -import "core/image/image.proto"; -import "gapis/service/path/path.proto"; - -package gles; -option go_package = "github.com/google/gapid/gapis/api/gles"; - -// GAPIS internal structure. -message GLSLParseResolvable { - string shader_source = 1; - uint32 language = 2; -} - -// Resolves to []byte. -message ReadGPUTextureDataResolveable { - path.Capture capture = 1; - path.Device device = 2; - uint64 after = 3; - uint64 thread = 4; - uint32 texture = 5; - uint32 level = 6; - uint32 layer = 7; - uint32 data_format = 8; - uint32 data_type = 9; -} \ No newline at end of file diff --git a/gapis/api/gles/resources.go b/gapis/api/gles/resources.go deleted file mode 100644 index ad8af8d55c..0000000000 --- a/gapis/api/gles/resources.go +++ /dev/null @@ -1,639 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "sort" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/messages" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/box" - "github.com/google/gapid/gapis/service/path" -) - -var _ api.Resource = Textureʳ{} - -// IsResource returns true if this instance should be considered as a resource. -func (t Textureʳ) IsResource() bool { - return !t.IsNil() && t.ID() != 0 -} - -// ResourceHandle returns the UI identity for the resource. -func (t Textureʳ) ResourceHandle() string { - return fmt.Sprintf("Texture<%d>", t.ID()) -} - -// ResourceLabel returns an optional debug label for the resource. -func (t Textureʳ) ResourceLabel() string { - return t.Label() -} - -// Order returns an integer used to sort the resources for presentation. -func (t Textureʳ) Order() uint64 { - return uint64(t.ID()) -} - -// ResourceType returns the type of this resource. -func (t Textureʳ) ResourceType(ctx context.Context) api.ResourceType { - return api.ResourceType_TextureResource -} - -// ResourceData returns the resource data given the current state. -func (t Textureʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { - ctx = log.Enter(ctx, "Texture.ResourceData()") - switch t.Kind() { - case GLenum_GL_TEXTURE_1D, GLenum_GL_TEXTURE_2D, GLenum_GL_TEXTURE_2D_MULTISAMPLE: - count := GLint(0) - for i := range t.Levels().All() { - if i >= count { - count = i + 1 - } - } - - levels := make([]*image.Info, count) - for i, level := range t.Levels().All() { - img, err := level.Layers().Get(0).ImageInfo(ctx, s) - if err != nil { - return nil, err - } - levels[i] = img - } - switch t.Kind() { - case GLenum_GL_TEXTURE_1D: - return api.NewResourceData(api.NewTexture(&api.Texture1D{Levels: levels})), nil - case GLenum_GL_TEXTURE_2D: - return api.NewResourceData(api.NewTexture(&api.Texture2D{Levels: levels})), nil - case GLenum_GL_TEXTURE_2D_MULTISAMPLE: - return api.NewResourceData(api.NewTexture(&api.Texture2D{Levels: levels, Multisampled: true})), nil - default: - panic(fmt.Errorf("Unhandled texture kind %v", t.Kind())) - } - - case GLenum_GL_TEXTURE_EXTERNAL_OES: - ei := t.EGLImage() - if ei.IsNil() { - return api.NewResourceData(api.NewTexture(&api.Texture2D{})), nil - } - levels := make([]*image.Info, ei.Images().Len()) - for i, img := range ei.Images().All() { - ii, err := img.ImageInfo(ctx, s) - if err != nil { - return nil, err - } - levels[i] = ii - } - return api.NewResourceData(api.NewTexture(&api.Texture2D{Levels: levels})), nil - - case GLenum_GL_TEXTURE_1D_ARRAY: - numLayers := t.LayerCount() - layers := make([]*api.Texture1D, numLayers) - for layer := range layers { - levels := make([]*image.Info, t.Levels().Len()) - for level := range levels { - img, err := t.Levels().Get(GLint(level)).Layers().Get(GLint(layer)).ImageInfo(ctx, s) - if err != nil { - return nil, err - } - levels[level] = img - } - layers[layer] = &api.Texture1D{Levels: levels} - } - return api.NewResourceData(api.NewTexture(&api.Texture1DArray{Layers: layers})), nil - - case GLenum_GL_TEXTURE_2D_ARRAY, GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - numLayers := t.LayerCount() - layers := make([]*api.Texture2D, numLayers) - for layer := range layers { - levels := make([]*image.Info, t.Levels().Len()) - for level := range levels { - img, err := t.Levels().Get(GLint(level)).Layers().Get(GLint(layer)).ImageInfo(ctx, s) - if err != nil { - return nil, err - } - levels[level] = img - } - layers[layer] = &api.Texture2D{Levels: levels} - } - switch t.Kind() { - case GLenum_GL_TEXTURE_2D_ARRAY: - return api.NewResourceData(api.NewTexture(&api.Texture2DArray{Layers: layers})), nil - case GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - return api.NewResourceData(api.NewTexture(&api.Texture2DArray{Layers: layers, Multisampled: true})), nil - default: - panic(fmt.Errorf("Unhandled texture kind %v", t.Kind())) - } - - case GLenum_GL_TEXTURE_3D: - levels := make([]*image.Info, t.Levels().Len()) - for i, level := range t.Levels().All() { - img := level.Layers().Get(0) - l := &image.Info{ - Width: uint32(img.Width()), - Height: uint32(img.Height()), - Depth: uint32(level.Layers().Len()), - } - levels[i] = l - if img.Data().Size() == 0 { - continue - } - bytes := []byte{} - for i, c := 0, level.Layers().Len(); i < c; i++ { - l := level.Layers().Get(GLint(i)) - if l.IsNil() { - continue - } - pool, err := s.Memory.Get(l.Data().Pool()) - if err != nil { - return nil, err - } - data := pool.Slice(l.Data().Range()) - buf := make([]byte, data.Size()) - if err := data.Get(ctx, 0, buf); err != nil { - return nil, err - } - bytes = append(bytes, buf...) - } - id, err := database.Store(ctx, bytes) - if err != nil { - return nil, err - } - format, err := getImageFormat(img.DataFormat(), img.DataType()) - if err != nil { - return nil, err - } - l.Format = format - l.Bytes = image.NewID(id) - } - return api.NewResourceData(api.NewTexture(&api.Texture3D{Levels: levels})), nil - - case GLenum_GL_TEXTURE_CUBE_MAP: - levels := make([]*api.CubemapLevel, t.Levels().Len()) - for i, level := range t.Levels().All() { - levels[i] = &api.CubemapLevel{} - for j, face := range level.Layers().All() { - img, err := face.ImageInfo(ctx, s) - if err != nil { - return nil, err - } - switch GLenum(j) + GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X { - case GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - levels[i].NegativeX = img - case GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X: - levels[i].PositiveX = img - case GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - levels[i].NegativeY = img - case GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - levels[i].PositiveY = img - case GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - levels[i].NegativeZ = img - case GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - levels[i].PositiveZ = img - } - } - } - return api.NewResourceData(api.NewTexture(&api.Cubemap{Levels: levels})), nil - } - return nil, &service.ErrDataUnavailable{Reason: messages.ErrNoTextureData(t.ResourceHandle())} -} - -func (t Textureʳ) SetResourceData( - ctx context.Context, - at *path.Command, - data *api.ResourceData, - resources api.ResourceMap, - edits api.ReplaceCallback, - mutate api.MutateInitialState, - r *path.ResolveConfig) error { - - return fmt.Errorf("SetResourceData is not supported for Texture") -} - -// ImageInfo returns the Image as a image.Info. -func (i Imageʳ) ImageInfo(ctx context.Context, s *api.GlobalState) (*image.Info, error) { - out := &image.Info{ - Width: uint32(i.Width()), - Height: uint32(i.Height()), - Depth: 1, - } - if i.Data().Size() == 0 { - return out, nil - } - dataFormat, dataType := i.getUnsizedFormatAndType() - format, err := getImageFormat(dataFormat, dataType) - if err != nil { - return nil, err - } - out.Format = format - out.Bytes = image.NewID(i.Data().ResourceID(ctx, s)) - return out, nil -} - -// LayerCount returns the maximum number of layers across all levels. -func (t Textureʳ) LayerCount() int { - max := 0 - for _, l := range t.Levels().All() { - if l.Layers().Len() > max { - max = l.Layers().Len() - } - } - return max -} - -var _ api.Resource = Shaderʳ{} - -// IsResource returns true if this instance should be considered as a resource. -func (s Shaderʳ) IsResource() bool { - return !s.IsNil() && s.ID() != 0 -} - -// ResourceHandle returns the UI identity for the resource. -func (s Shaderʳ) ResourceHandle() string { - return fmt.Sprintf("Shader<%d>", s.ID()) -} - -// ResourceLabel returns an optional debug label for the resource. -func (s Shaderʳ) ResourceLabel() string { - return s.Label() -} - -// Order returns an integer used to sort the resources for presentation. -func (s Shaderʳ) Order() uint64 { - return uint64(s.ID()) -} - -// ResourceType returns the type of this resource. -func (s Shaderʳ) ResourceType(ctx context.Context) api.ResourceType { - return api.ResourceType_ShaderResource -} - -// ResourceData returns the resource data given the current state. -func (s Shaderʳ) ResourceData(ctx context.Context, t *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { - ctx = log.Enter(ctx, "Shader.ResourceData()") - var ty api.ShaderType - switch s.Type() { - case GLenum_GL_VERTEX_SHADER: - ty = api.ShaderType_Vertex - case GLenum_GL_GEOMETRY_SHADER: - ty = api.ShaderType_Geometry - case GLenum_GL_TESS_CONTROL_SHADER: - ty = api.ShaderType_TessControl - case GLenum_GL_TESS_EVALUATION_SHADER: - ty = api.ShaderType_TessEvaluation - case GLenum_GL_FRAGMENT_SHADER: - ty = api.ShaderType_Fragment - case GLenum_GL_COMPUTE_SHADER: - ty = api.ShaderType_Compute - } - - return api.NewResourceData(&api.Shader{Type: ty, Source: s.Source()}), nil -} - -func (s Shaderʳ) SetResourceData( - ctx context.Context, - at *path.Command, - data *api.ResourceData, - resourceIDs api.ResourceMap, - edits api.ReplaceCallback, - mutate api.MutateInitialState, - r *path.ResolveConfig) error { - - cmdIdx := at.Indices[0] - if len(at.Indices) > 1 { - return fmt.Errorf("Subcommands currently not supported for GLES resources") // TODO: Subcommands - } - - // Dirty. TODO: Make separate type for getting info for a single resource. - capturePath := at.Capture - resources, err := resolve.Resources(ctx, capturePath, r) - if err != nil { - return err - } - resourceID := resourceIDs[s.ResourceHandle()] - - resource, err := resources.Find(s.ResourceType(ctx), resourceID) - if err != nil { - return err - } - - c, err := capture.ResolveGraphicsFromPath(ctx, capturePath) - if err != nil { - return err - } - - index := len(resource.Accesses) - 1 - for resource.Accesses[index].Indices[0] > cmdIdx && index >= 0 { // TODO: Subcommands - index-- - } - for j := index; j >= 0; j-- { - i := resource.Accesses[j].Indices[0] // TODO: Subcommands - if a, ok := c.Commands[i].(*GlShaderSource); ok { - edits(uint64(i), a.Replace(ctx, c, data)) - return nil - } - } - - // Reached the beginning of the trace, attempt to modify the shader in the initial state. - if state, ok := mutate(API{}).(*State); ok { - for _, c := range state.EGLContexts().All() { - if id.ID(c.ID()) == resource.Context.GetID().ID() { - if shader, ok := c.Objects().Shaders().Lookup(s.ID()); ok { - src := data.GetShader().Source - shader.SetSource(src) - if e := shader.CompileExtra(); !e.IsNil() { - e.SetSource(src) - } - return nil - } - break - } - } - } - return fmt.Errorf("No command to set data in") -} - -func (a *GlShaderSource) Replace(ctx context.Context, c *capture.GraphicsCapture, data *api.ResourceData) interface{} { - state := c.NewState(ctx) - shader := data.GetShader() - source := shader.Source - src := state.AllocDataOrPanic(ctx, source) - srcLen := state.AllocDataOrPanic(ctx, GLint(len(source))) - srcPtr := state.AllocDataOrPanic(ctx, src.Ptr()) - cb := CommandBuilder{Thread: a.Thread(), Arena: state.Arena} - return cb.GlShaderSource(a.Shader(), 1, srcPtr.Ptr(), srcLen.Ptr()). - AddRead(srcPtr.Data()). - AddRead(srcLen.Data()). - AddRead(src.Data()) -} - -var _ api.Resource = Programʳ{} - -// IsResource returns true if this instance should be considered as a resource. -func (p Programʳ) IsResource() bool { - return !p.IsNil() && p.ID() != 0 -} - -// ResourceHandle returns the UI identity for the resource. -func (p Programʳ) ResourceHandle() string { - return fmt.Sprintf("Program<%d>", p.ID()) -} - -// ResourceLabel returns an optional debug label for the resource. -func (p Programʳ) ResourceLabel() string { - return p.Label() -} - -// Order returns an integer used to sort the resources for presentation. -func (p Programʳ) Order() uint64 { - return uint64(p.ID()) -} - -// ResourceType returns the type of this resource. -func (p Programʳ) ResourceType(ctx context.Context) api.ResourceType { - return api.ResourceType_ProgramResource -} - -// ResourceData returns the resource data given the current state. -func (p Programʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { - ctx = log.Enter(ctx, "Program.ResourceData()") - - shaders := make([]*api.Shader, 0, p.Shaders().Len()) - for shaderType, shader := range p.Shaders().All() { - var ty api.ShaderType - switch shaderType { - case GLenum_GL_VERTEX_SHADER: - ty = api.ShaderType_Vertex - case GLenum_GL_GEOMETRY_SHADER: - ty = api.ShaderType_Geometry - case GLenum_GL_TESS_CONTROL_SHADER: - ty = api.ShaderType_TessControl - case GLenum_GL_TESS_EVALUATION_SHADER: - ty = api.ShaderType_TessEvaluation - case GLenum_GL_FRAGMENT_SHADER: - ty = api.ShaderType_Fragment - case GLenum_GL_COMPUTE_SHADER: - ty = api.ShaderType_Compute - } - shaders = append(shaders, &api.Shader{ - Type: ty, - Source: shader.Source(), - }) - } - - uniforms := []*api.Uniform{} - if res := p.ActiveResources(); !res.IsNil() { - for _, activeUniform := range res.DefaultUniformBlock().All() { - var uniformFormat api.UniformFormat - var uniformType api.UniformType - - switch activeUniform.Type() { - case GLenum_GL_FLOAT: - uniformFormat = api.UniformFormat_Scalar - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_VEC2: - uniformFormat = api.UniformFormat_Vec2 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_VEC3: - uniformFormat = api.UniformFormat_Vec3 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_VEC4: - uniformFormat = api.UniformFormat_Vec4 - uniformType = api.UniformType_Float - case GLenum_GL_INT: - uniformFormat = api.UniformFormat_Scalar - uniformType = api.UniformType_Int32 - case GLenum_GL_INT_VEC2: - uniformFormat = api.UniformFormat_Vec2 - uniformType = api.UniformType_Int32 - case GLenum_GL_INT_VEC3: - uniformFormat = api.UniformFormat_Vec3 - uniformType = api.UniformType_Int32 - case GLenum_GL_INT_VEC4: - uniformFormat = api.UniformFormat_Vec4 - uniformType = api.UniformType_Int32 - case GLenum_GL_UNSIGNED_INT: - uniformFormat = api.UniformFormat_Scalar - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_VEC2: - uniformFormat = api.UniformFormat_Vec2 - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_VEC3: - uniformFormat = api.UniformFormat_Vec3 - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_VEC4: - uniformFormat = api.UniformFormat_Vec4 - uniformType = api.UniformType_Uint32 - case GLenum_GL_BOOL: - uniformFormat = api.UniformFormat_Scalar - uniformType = api.UniformType_Bool - case GLenum_GL_BOOL_VEC2: - uniformFormat = api.UniformFormat_Vec2 - uniformType = api.UniformType_Bool - case GLenum_GL_BOOL_VEC3: - uniformFormat = api.UniformFormat_Vec3 - uniformType = api.UniformType_Bool - case GLenum_GL_BOOL_VEC4: - uniformFormat = api.UniformFormat_Vec4 - uniformType = api.UniformType_Bool - case GLenum_GL_FLOAT_MAT2: - uniformFormat = api.UniformFormat_Mat2 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT3: - uniformFormat = api.UniformFormat_Mat3 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT4: - uniformFormat = api.UniformFormat_Mat4 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT2x3: - uniformFormat = api.UniformFormat_Mat2x3 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT2x4: - uniformFormat = api.UniformFormat_Mat2x4 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT3x2: - uniformFormat = api.UniformFormat_Mat3x2 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT3x4: - uniformFormat = api.UniformFormat_Mat3x4 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT4x2: - uniformFormat = api.UniformFormat_Mat4x2 - uniformType = api.UniformType_Float - case GLenum_GL_FLOAT_MAT4x3: - uniformFormat = api.UniformFormat_Mat4x3 - uniformType = api.UniformType_Float - case GLenum_GL_SAMPLER_2D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_3D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_CUBE: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_2D_SHADOW: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_2D_ARRAY: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_2D_ARRAY_SHADOW: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_SAMPLER_CUBE_SHADOW: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_INT_SAMPLER_2D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_INT_SAMPLER_3D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_INT_SAMPLER_CUBE: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_INT_SAMPLER_2D_ARRAY: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_SAMPLER_2D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_SAMPLER_3D: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_SAMPLER_CUBE: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - case GLenum_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - uniformFormat = api.UniformFormat_Sampler - uniformType = api.UniformType_Uint32 - default: - uniformFormat = api.UniformFormat_Scalar - uniformType = api.UniformType_Float - } - - uniforms = append(uniforms, &api.Uniform{ - UniformLocation: uint32(activeUniform.Locations().Get(0)), - Name: activeUniform.Name(), - Format: uniformFormat, - Type: uniformType, - Value: box.NewValue(uniformValue(ctx, s, uniformType, activeUniform.Value())), - }) - } - } - - sort.Slice(shaders, func(i, j int) bool { return shaders[i].Type < shaders[j].Type }) - sort.Slice(uniforms, func(i, j int) bool { return uniforms[i].UniformLocation < uniforms[j].UniformLocation }) - return api.NewResourceData(&api.Program{Shaders: shaders, Uniforms: uniforms}), nil -} - -func uniformValue(ctx context.Context, s *api.GlobalState, kind api.UniformType, data U8ˢ) interface{} { - r := data.Reader(ctx, s) - - switch kind { - case api.UniformType_Int32: - a := make([]int32, data.Size()/4) - for i := 0; i < len(a); i++ { - a[i] = r.Int32() - } - return a - case api.UniformType_Uint32: - a := make([]uint32, data.Size()/4) - for i := 0; i < len(a); i++ { - a[i] = r.Uint32() - } - return a - case api.UniformType_Bool: - a := make([]bool, data.Size()/4) - for i := 0; i < len(a); i++ { - a[i] = r.Int32() != 0 - } - return a - case api.UniformType_Float: - a := make([]float32, data.Size()/4) - for i := 0; i < len(a); i++ { - a[i] = r.Float32() - } - return a - case api.UniformType_Double: - a := make([]float64, data.Size()/8) - for i := 0; i < len(a); i++ { - a[i] = r.Float64() - } - return a - default: - panic(fmt.Errorf("Can't box uniform data type %v", kind)) - } -} - -func (p Programʳ) SetResourceData( - ctx context.Context, - at *path.Command, - data *api.ResourceData, - resources api.ResourceMap, - edits api.ReplaceCallback, - mutate api.MutateInitialState, - r *path.ResolveConfig) error { - - return fmt.Errorf("SetResourceData is not supported for Program") -} diff --git a/gapis/api/gles/state.go b/gapis/api/gles/state.go deleted file mode 100644 index 89a21ca5de..0000000000 --- a/gapis/api/gles/state.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "fmt" - - "github.com/google/gapid/gapis/api" -) - -// fbai is the result getFramebufferAttachmentInfo. -type fbai struct { - width uint32 - height uint32 - sizedFormat GLenum - internalFormat GLenum // These are GL_NONE, unless the attachement is a texture - format GLenum // that was initialized with a buffer of this internal - ty GLenum // format, format and type. - multisampled bool -} - -func attachmentToEnum(a api.FramebufferAttachment) (GLenum, error) { - switch a { - case api.FramebufferAttachment_Color0: - return GLenum_GL_COLOR_ATTACHMENT0, nil - case api.FramebufferAttachment_Color1: - return GLenum_GL_COLOR_ATTACHMENT1, nil - case api.FramebufferAttachment_Color2: - return GLenum_GL_COLOR_ATTACHMENT2, nil - case api.FramebufferAttachment_Color3: - return GLenum_GL_COLOR_ATTACHMENT3, nil - case api.FramebufferAttachment_Depth: - return GLenum_GL_DEPTH_ATTACHMENT, nil - case api.FramebufferAttachment_Stencil: - return GLenum_GL_STENCIL_ATTACHMENT, nil - default: - return 0, fmt.Errorf("Framebuffer attachment %v unsupported by gles", a) - } -} - -func (f Framebufferʳ) getAttachment(a GLenum) (FramebufferAttachment, error) { - switch a { - case GLenum_GL_DEPTH_ATTACHMENT, GLenum_GL_DEPTH_STENCIL_ATTACHMENT: - return f.DepthAttachment(), nil - case GLenum_GL_STENCIL_ATTACHMENT: - return f.StencilAttachment(), nil - default: - if a >= GLenum_GL_COLOR_ATTACHMENT0 && a < GLenum_GL_COLOR_ATTACHMENT0+64 { - return f.ColorAttachments().Get(GLint(a - GLenum_GL_COLOR_ATTACHMENT0)), nil - } - return FramebufferAttachment{}, fmt.Errorf("Unhandled attachment: %v", a) - } -} - -// TODO: When gfx api macros produce functions instead of inlining, move this logic -// to the gles.api file. -func (s *State) getFramebufferAttachmentInfo(thread uint64, fb FramebufferId, att GLenum) (fbai, error) { - c := s.GetContext(thread) - if c.IsNil() { - return fbai{}, fmt.Errorf("No context bound") - } - if !c.Other().Initialized() { - return fbai{}, fmt.Errorf("Context not initialized") - } - - framebuffer, ok := c.Objects().Framebuffers().Lookup(fb) - if !ok { - return fbai{}, fmt.Errorf("Invalid framebuffer %v", fb) - } - - a, err := framebuffer.getAttachment(att) - if err != nil { - return fbai{}, err - } - - switch a.Type() { - case GLenum_GL_NONE: - return fbai{}, fmt.Errorf("%s is not bound", att) - case GLenum_GL_TEXTURE: - t := a.Texture() - l := t.Levels().Get(a.TextureLevel()).Layers().Get(a.TextureLayer()) - if l.IsNil() { - return fbai{}, fmt.Errorf("Texture %v does not have Level[%v].Layer[%v]", - t.ID(), a.TextureLevel(), a.TextureLayer()) - } - multisampled := l.Samples() > 0 - return fbai{uint32(l.Width()), uint32(l.Height()), l.SizedFormat(), l.InternalFormat(), l.DataFormat(), l.DataType(), multisampled}, nil - case GLenum_GL_RENDERBUFFER: - r := a.Renderbuffer() - l := r.Image() - if l.IsNil() { - return fbai{}, fmt.Errorf("Renderbuffer %v does not have any image date", r.ID()) - } - multisampled := l.Samples() > 0 - return fbai{uint32(l.Width()), uint32(l.Height()), l.SizedFormat(), GLenum_GL_NONE, GLenum_GL_NONE, GLenum_GL_NONE, multisampled}, nil - default: - return fbai{}, fmt.Errorf("Unknown framebuffer attachment type %T", a.Type()) - } -} diff --git a/gapis/api/gles/state_builder.go b/gapis/api/gles/state_builder.go deleted file mode 100644 index c6cb5b3775..0000000000 --- a/gapis/api/gles/state_builder.go +++ /dev/null @@ -1,1380 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "reflect" - "time" - - "github.com/google/gapid/core/app/status" - "github.com/google/gapid/core/data/compare" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/math/interval" - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/config" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay/value" -) - -const ( - maxDiffsLogged = 20 -) - -type stateBuilder struct { - oldState *api.GlobalState // The initial state which we are trying to recreate - newState *api.GlobalState // The recreated state generated by the commands - cmds []api.Cmd // The commands which recreate the initial state - cb CommandBuilder // Default command builder for thread 0 - preCmd []func(api.Cmd) // Actions to be done on the next written command - tmpArena arena.Arena // The arena to use for temporary allocations - seen map[interface{}]bool - memoryIntervals interval.U64RangeList - cloneCtx api.CloneContext -} - -// RebuildState returns a set of commands which, if executed on a new clean -// state, will reproduce the API's state in s. -// The segments of memory that were used to create these commands are returned -// in the rangeList. -func (API) RebuildState(ctx context.Context, oldState *api.GlobalState) ([]api.Cmd, interval.U64RangeList) { - start := time.Now() - s, hasState := oldState.APIs[ID].(*State) - if !hasState { - return nil, nil - } - - newState := api.NewStateWithAllocator(memory.NewBasicAllocator(value.ValidMemoryRanges), oldState.MemoryLayout) - sb := &stateBuilder{ - oldState: oldState, - newState: newState, - cb: CommandBuilder{Thread: 0, Arena: newState.Arena}, - tmpArena: arena.New(), - seen: map[interface{}]bool{}, - memoryIntervals: interval.U64RangeList{}, - cloneCtx: api.CloneContext{}, - } - - defer sb.tmpArena.Dispose() - - // Ensure that all pool IDs are distinct between the old state and new state. - // This helps with verification at the end by ensuring that diffing algorithm - // will not miss diffs just because the pool IDs happen to be same by chance. - sb.newState.Memory.NewAt(sb.oldState.Memory.NextPoolID()) - - // Create EGL contexts (possibly shared) - representative := map[ShareListʳ]EGLContext{} - for i := ContextID(0); i < s.NextContextID(); i++ { - for handle, c := range s.EGLContexts().All() { - // Don't recreate destroyed or uninitialized contexts. - if c.Other().Destroyed() || !c.Other().Initialized() { - continue - } - - // TODO: We need to restore contexts in order without gaps, but this is messy. - if c.Identifier() == i { - sb.contextObject(ctx, handle, c, representative) - } - } - } - - // Create EGL images (may depend on texture from any context) - for _, img := range s.EGLImages().Keys() { - sb.eglImage(ctx, s.EGLImages().Get(img)) - } - - // Second pass over context which sets everything that may depend on EGLimage. - for _, handle := range s.EGLContexts().Keys() { - sb.contextObjectPostEGLImage(ctx, handle, s.EGLContexts().Get(handle)) - } - - // Set the active context for each thread - sb.bindContexts(ctx, s) - - log.I(ctx, "State reconstruction took %v", time.Since(start)) - - if config.CheckRebuiltStateMatches { - // Verify that the recreated state matches the original desired state. - diffs := 0 - compare.Compare(s, GetState(sb.newState), func(d compare.Path) { - if l := len(d); l > 1 { - last := d[l-2] // l-1: is the pool, l-2 is the memory.Slice. - if oldSlice, ok := last.Reference.(memory.Slice); ok { - if newSlice, ok := last.Value.(memory.Slice); ok { - old := AsU8ˢ(sb.tmpArena, oldSlice, sb.oldState.MemoryLayout) - new := AsU8ˢ(sb.tmpArena, newSlice, sb.newState.MemoryLayout) - if old.ResourceID(ctx, sb.oldState) == new.ResourceID(ctx, sb.newState) { - return // The pool IDs are different, but the resource IDs match exactly. - } - oldData := old.MustRead(ctx, nil, sb.oldState, nil) - newData := new.MustRead(ctx, nil, sb.newState, nil) - if reflect.DeepEqual(oldData, newData) { - return // The pool IDs are different, but the actual data matches exactly. - } - } - } - } - if diffs++; diffs <= maxDiffsLogged { - log.W(ctx, "Initial state: %v", d) - } - }) - - if diffs > maxDiffsLogged { - log.W(ctx, "Initial state: found an additional %d differences", diffs-maxDiffsLogged) - } - } - - return sb.cmds, sb.memoryIntervals -} - -func (sb *stateBuilder) E(ctx context.Context, fmt string, args ...interface{}) { - log.E(ctx, "[GL state builder] "+fmt, args...) -} - -func (sb *stateBuilder) readsData(ctx context.Context, v interface{}) memory.Pointer { - tmp := sb.newState.AllocDataOrPanic(ctx, v) - rng := tmp.Range() - interval.Merge(&sb.memoryIntervals, interval.U64Span{rng.Base, rng.Base + rng.Size}, true) - sb.preCmd = append(sb.preCmd, func(cmd api.Cmd) { - cmd.Extras().GetOrAppendObservations().AddRead(tmp.Data()) - tmp.Free() - }) - return tmp.Ptr() -} - -func (sb *stateBuilder) readsSlice(ctx context.Context, v U8ˢ) memory.Pointer { - tmp := sb.newState.AllocOrPanic(ctx, v.Size()) - rng := tmp.Range() - interval.Merge(&sb.memoryIntervals, interval.U64Span{rng.Base, rng.Base + rng.Size}, true) - id := v.ResourceID(ctx, sb.oldState) - sb.preCmd = append(sb.preCmd, func(cmd api.Cmd) { - cmd.Extras().GetOrAppendObservations().AddRead(tmp.Range(), id) - tmp.Free() - }) - return tmp.Ptr() -} - -func (sb *stateBuilder) writesData(ctx context.Context, v interface{}) memory.Pointer { - tmp := sb.newState.AllocDataOrPanic(ctx, v) - rng := tmp.Range() - interval.Merge(&sb.memoryIntervals, interval.U64Span{rng.Base, rng.Base + rng.Size}, true) - sb.preCmd = append(sb.preCmd, func(cmd api.Cmd) { - cmd.Extras().GetOrAppendObservations().AddWrite(tmp.Data()) - tmp.Free() - }) - return tmp.Ptr() -} - -func (sb *stateBuilder) write(ctx context.Context, cmd api.Cmd) { - for _, fn := range sb.preCmd { - fn(cmd) - } - sb.preCmd = sb.preCmd[:0] - if config.CheckRebuiltStateMatches { - if err := cmd.Mutate(ctx, api.CmdNoID, sb.newState, nil, nil); err != nil { - log.W(ctx, "Initial cmd %v: %v - %v", len(sb.cmds), cmd, err) - } - } - sb.cmds = append(sb.cmds, cmd) -} - -func (sb *stateBuilder) enable(ctx context.Context, cap GLenum, val GLboolean) { - write, cb := sb.write, sb.cb - if val == GLboolean_GL_TRUE { - write(ctx, cb.GlEnable(cap)) - } else { - write(ctx, cb.GlDisable(cap)) - } -} - -func (sb *stateBuilder) enablei(ctx context.Context, cap GLenum, idx GLuint, val GLboolean) { - write, cb := sb.write, sb.cb - if val == GLboolean_GL_TRUE { - write(ctx, cb.GlEnablei(cap, idx)) - } else { - write(ctx, cb.GlDisablei(cap, idx)) - } -} - -// once is used to ensure we create shared objects only once -func (sb *stateBuilder) once(key interface{}) (res bool) { - res = !sb.seen[key] - sb.seen[key] = true - return -} - -func (sb *stateBuilder) contextExtras(ctx context.Context, c Contextʳ) []api.CmdExtra { - r := []api.CmdExtra{} - if se := c.Other().StaticStateExtra(); !se.IsNil() { - r = append(r, se.Get().Clone(sb.cb.Arena, sb.cloneCtx)) - } - if de := c.Other().DynamicStateExtra(); !de.IsNil() { - r = append(r, de.Get().Clone(sb.cb.Arena, sb.cloneCtx)) - } - return r -} - -func (sb *stateBuilder) contextObject(ctx context.Context, handle EGLContext, c Contextʳ, representative map[ShareListʳ]EGLContext) { - ctx = status.Start(ctx, "contextObject %v", c.Identifier()) - defer status.Finish(ctx) - - write, cb := sb.write, sb.cb - - // Check if we have already created any other context within this share-list. - sharedCtx := representative[c.Other().ShareList()] // Returns nullptr if we are the first. - representative[c.Other().ShareList()] = handle // Further contexts will reference us. - - // TODO: Record the arguments in state. - write(ctx, cb.EglCreateContext(memory.Nullptr, memory.Nullptr, sharedCtx, memory.Nullptr, handle)) - write(ctx, api.WithExtras(cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, handle, EGLBoolean(1)), - sb.contextExtras(ctx, c)...)) - - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_ALIGNMENT, 1)) - - if names := c.Objects().GeneratedNames().Buffers(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d buffers", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenBuffers(1, sb.writesData(ctx, id))) - if o := c.Objects().Buffers().Get(id); !o.IsNil() { - sb.bufferObject(ctx, o) - } - } - } - }) - } - if names := c.Objects().GeneratedNames().Renderbuffers(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d renderbuffers", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenRenderbuffers(1, sb.writesData(ctx, id))) - if o := c.Objects().Renderbuffers().Get(id); !o.IsNil() { - sb.renderbufferObject(ctx, o) - } - } - } - }) - } - for _, defaultTexture := range []Textureʳ{ - c.Objects().Default().Texture2d(), - c.Objects().Default().Texture2dArray(), - c.Objects().Default().Texture2dMultisample(), - c.Objects().Default().Texture2dMultisampleArray(), - c.Objects().Default().Texture3d(), - c.Objects().Default().TextureBuffer(), - c.Objects().Default().TextureCubeMap(), - c.Objects().Default().TextureCubeMapArray(), - c.Objects().Default().TextureExternalOes(), - } { - sb.textureObject(ctx, defaultTexture) - } - if names := c.Objects().GeneratedNames().Textures(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d textures", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenTextures(1, sb.writesData(ctx, id))) - if o := c.Objects().Textures().Get(id); !o.IsNil() { - sb.textureObject(ctx, o) - } - } - } - }) - } - if objs := c.Objects().ImageUnits(); sb.once(objs) && objs.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d image units", objs.Len()), func(ctx context.Context) { - for _, id := range objs.Keys() { - if o := c.Objects().ImageUnits().Get(id); !o.IsNil() { - sb.imageUnit(ctx, o) - } - } - }) - } - var programs []ProgramId - if objs := c.Objects().Programs(); sb.once(objs) && objs.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d programs", objs.Len()), func(ctx context.Context) { - for _, id := range objs.Keys() { - if o := c.Objects().Programs().Get(id); !o.IsNil() { - sb.programObject(ctx, o) - programs = append(programs, id) - } - } - }) - } - if objs := c.Objects().Shaders(); sb.once(objs) && objs.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d shaders", objs.Len()), func(ctx context.Context) { - for _, id := range objs.Keys() { - if o := c.Objects().Shaders().Get(id); !o.IsNil() { - sb.shaderObject(ctx, o) - } - } - }) - } - if len(programs) > 0 { - status.Do(ctx, fmt.Sprintf("attaching shaders to %d programs", len(programs)), func(ctx context.Context) { - for _, id := range programs { - sb.attachShaders(ctx, c.Objects().Programs().Get(id)) - } - }) - } - if names := c.Objects().GeneratedNames().Pipelines(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d pipelines", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenProgramPipelines(1, sb.writesData(ctx, id))) - if o := c.Objects().Pipelines().Get(id); !o.IsNil() { - sb.pipelineObject(ctx, o) - } - } - } - }) - } - if names := c.Objects().GeneratedNames().Samplers(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d samplers", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenSamplers(1, sb.writesData(ctx, id))) - if o := c.Objects().Samplers().Get(id); !o.IsNil() { - sb.samplerObject(ctx, o) - } - } - } - }) - } - if names := c.Objects().GeneratedNames().Queries(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d queries", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenQueries(1, sb.writesData(ctx, id))) - if o := c.Objects().Queries().Get(id); !o.IsNil() { - sb.queryObject(ctx, o) - } - } - } - }) - } - if objs := c.Objects().SyncObjects(); sb.once(objs) && objs.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d sync objects", objs.Len()), func(ctx context.Context) { - for _, id := range objs.Keys() { - if o := c.Objects().SyncObjects().Get(id); !o.IsNil() { - sb.syncObject(ctx, o) - } - } - }) - } - sb.transformFeedbackObject(ctx, c.Objects().Default().TransformFeedback()) - if names := c.Objects().GeneratedNames().TransformFeedbacks(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d tf feedback objects", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenTransformFeedbacks(1, sb.writesData(ctx, id))) - if o := c.Objects().TransformFeedbacks().Get(id); !o.IsNil() { - sb.transformFeedbackObject(ctx, o) - } - } - } - }) - } - sb.vertexArrayObject(ctx, c.Objects().Default().VertexArray()) - if names := c.Objects().GeneratedNames().VertexArrays(); sb.once(names) && names.Len() > 0 { - status.Do(ctx, fmt.Sprintf("rebuilding %d VAOs", names.Len()), func(ctx context.Context) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenVertexArrays(1, sb.writesData(ctx, id))) - if o := c.Objects().VertexArrays().Get(id); !o.IsNil() { - sb.vertexArrayObject(ctx, o) - } - } - } - }) - } - sb.vertexState(ctx, c.Vertex()) - sb.reasterizationState(ctx, c.Rasterization()) - sb.pixelState(ctx, c.Pixel()) - sb.otherState(ctx, c.Other()) - sb.debugLabels(ctx, c) - sb.bindings(ctx, c) - sb.deleteMarkedObjects(ctx, c) - - write(ctx, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, memory.Nullptr, EGLBoolean(1))) -} - -// eglImage creates an EGLImage object. -// It may reference a texture object in different context, -// so it must be called after all contexts have been created. -func (sb *stateBuilder) eglImage(ctx context.Context, img EGLImageʳ) { - write, cb := sb.write, sb.cb - - // TODO: This might not work if the target texture object has been deleted. - attribs := img.AttribList().MustRead(ctx, nil, sb.oldState, nil) - cmd := cb.EglCreateImageKHR(img.Display(), img.Context(), img.Target(), img.Buffer(), sb.readsData(ctx, attribs), img.ID()) - if extra := img.Extra(); !extra.IsNil() { - cmd.Extras().Add(extra.Get().Clone(cb.Arena, sb.cloneCtx)) - } - write(ctx, cmd) -} - -func (sb *stateBuilder) contextObjectPostEGLImage(ctx context.Context, handle EGLContext, c Contextʳ) { - write, cb := sb.write, sb.cb - - if c.Other().Initialized() { - write(ctx, api.WithExtras(cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, handle, EGLBoolean(1)), - sb.contextExtras(ctx, c)...)) - - for _, id := range c.Objects().Textures().Keys() { - t := c.Objects().Textures().Get(id) - target := t.Kind() - if i := t.EGLImage(); !i.IsNil() { - write(ctx, cb.GlBindTexture(target, t.GetID())) - if target != GLenum_GL_TEXTURE_2D && target != GLenum_GL_TEXTURE_EXTERNAL_OES { - panic(fmt.Errorf("Unknown EGLImage target: %v", target)) - } - img := t.Image() - extra := &EGLImageData{ - ID: img.Data().ResourceID(ctx, sb.oldState), - Size: img.Data().Size(), - Width: img.Width(), - Height: img.Height(), - Format: img.DataFormat(), - Type: img.DataType(), - } - write(ctx, api.WithExtras(cb.GlEGLImageTargetTexture2DOES(target, i.ID()), extra)) - } - } - - // Create framebuffers - sb.framebufferObject(ctx, c, c.Objects().Default().Framebuffer()) - if names := c.Objects().GeneratedNames().Framebuffers(); sb.once(names) { - for _, id := range names.Keys() { - if id != 0 && names.Get(id) { - write(ctx, cb.GlGenFramebuffers(1, sb.writesData(ctx, id))) - if o := c.Objects().Framebuffers().Get(id); !o.IsNil() { - sb.framebufferObject(ctx, c, o) - } - } - } - } - - // Framebuffer bindings - write(ctx, cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, c.Bound().ReadFramebuffer().GetID())) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, c.Bound().DrawFramebuffer().GetID())) - write(ctx, cb.GlBindRenderbuffer(GLenum_GL_RENDERBUFFER, c.Bound().Renderbuffer().GetID())) - - // Texture unit bindings - for _, unit := range c.Objects().TextureUnits().Keys() { - tu := c.Objects().TextureUnits().Get(unit) - bind := func(target GLenum, tex Textureʳ) { - if t := tex.GetID(); t != 0 || unit == 0 { - write(ctx, cb.GlActiveTexture(GLenum_GL_TEXTURE0+GLenum(unit))) - write(ctx, cb.GlBindTexture(target, t)) - } - } - bind(GLenum_GL_TEXTURE_2D, tu.Binding2d()) - bind(GLenum_GL_TEXTURE_2D_ARRAY, tu.Binding2dArray()) - bind(GLenum_GL_TEXTURE_2D_MULTISAMPLE, tu.Binding2dMultisample()) - bind(GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY, tu.Binding2dMultisampleArray()) - bind(GLenum_GL_TEXTURE_3D, tu.Binding3d()) - bind(GLenum_GL_TEXTURE_BUFFER, tu.BindingBuffer()) - bind(GLenum_GL_TEXTURE_CUBE_MAP, tu.BindingCubeMap()) - bind(GLenum_GL_TEXTURE_CUBE_MAP_ARRAY, tu.BindingCubeMapArray()) - bind(GLenum_GL_TEXTURE_EXTERNAL_OES, tu.BindingExternalOes()) - } - write(ctx, cb.GlActiveTexture(GLenum_GL_TEXTURE0+GLenum(c.Bound().TextureUnit().ID()))) - - write(ctx, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, memory.Nullptr, EGLBoolean(1))) - } -} - -// We have generally setup the whole state on single-thread. -// As a last step, call eglMakeCurrent for on all user-threads. -func (sb *stateBuilder) bindContexts(ctx context.Context, s *State) { - write, cb := sb.write, sb.cb - - for _, handle := range s.EGLContexts().Keys() { - c := s.EGLContexts().Get(handle) - if thread := c.Other().BoundOnThread(); thread != 0 { - cb := CommandBuilder{Thread: thread, Arena: sb.cb.Arena} - write(ctx, api.WithExtras(cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, handle, EGLBoolean(1)), - sb.contextExtras(ctx, c)...)) - } - } - write(ctx, cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, memory.Nullptr, EGLBoolean(1))) -} - -func (sb *stateBuilder) bufferObject(ctx context.Context, b Bufferʳ) { - write, cb, id := sb.write, sb.cb, b.GetID() - target := GLenum_GL_ARRAY_BUFFER // Any binding point will do. - - write(ctx, cb.GlBindBuffer(target, id)) - write(ctx, cb.GlBufferData(target, GLsizeiptr(b.Data().Size()), sb.readsSlice(ctx, b.Data()), b.Usage())) - if b.Mapped() == GLboolean_GL_TRUE { - write(ctx, cb.GlMapBufferRange(target, b.MapOffset(), b.MapLength(), b.AccessFlags(), b.MapPointer())) // GLES30 - } -} - -// Just to be on the safe side, this should be done before textures and framebuffers, -// since we generate some of them as temporary objects (to avoid ID collisions). -func (sb *stateBuilder) renderbufferObject(ctx context.Context, rb Renderbufferʳ) { - write, cb, id := sb.write, sb.cb, rb.GetID() - - write(ctx, cb.GlBindRenderbuffer(GLenum_GL_RENDERBUFFER, id)) - - if img := rb.Image(); !img.IsNil() { - fmt, w, h := img.getCorrectInternalFormat(), img.Width(), img.Height() - write(ctx, cb.GlRenderbufferStorageMultisample(GLenum_GL_RENDERBUFFER, img.Samples(), fmt, w, h)) // GLES30 - - // Fill the renderbuffer with data using a framebuffer blit - if img.Data().Size() != 0 { - // Create temporary objects - tex := TextureId(0x10000001) - write(ctx, cb.GlGenTextures(1, sb.writesData(ctx, tex))) - write(ctx, cb.GlBindTexture(GLenum_GL_TEXTURE_2D, tex)) - src := FramebufferId(0x10000002) - write(ctx, cb.GlGenFramebuffers(1, sb.writesData(ctx, src))) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, src)) - dst := FramebufferId(0x10000003) - write(ctx, cb.GlGenFramebuffers(1, sb.writesData(ctx, dst))) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, dst)) - - // Upload data and blit it to our renderbuffer - att := GLenum_GL_COLOR_ATTACHMENT0 // TODO: Consider depth - dataFormat, dataType := img.getUnsizedFormatAndType() - write(ctx, cb.GlTexImage2D(GLenum_GL_TEXTURE_2D, 0, GLint(fmt), w, h, 0, dataFormat, dataType, sb.readsSlice(ctx, img.Data()))) - write(ctx, cb.GlFramebufferTexture2D(GLenum_GL_READ_FRAMEBUFFER, att, GLenum_GL_TEXTURE_2D, tex, 0)) - write(ctx, cb.GlFramebufferRenderbuffer(GLenum_GL_DRAW_FRAMEBUFFER, att, GLenum_GL_RENDERBUFFER, id)) - write(ctx, cb.GlScissor(0, 0, w, h)) - mask := GLbitfield_GL_COLOR_BUFFER_BIT | GLbitfield_GL_DEPTH_BUFFER_BIT | GLbitfield_GL_STENCIL_BUFFER_BIT - write(ctx, cb.GlBlitFramebuffer(0, 0, GLint(w), GLint(h), 0, 0, GLint(w), GLint(h), mask, GLenum_GL_NEAREST)) - - // Delete temporary objects - write(ctx, cb.GlBindTexture(GLenum_GL_TEXTURE_2D, 0)) - write(ctx, cb.GlDeleteTextures(1, sb.readsData(ctx, tex))) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, 0)) - write(ctx, cb.GlDeleteFramebuffers(1, sb.readsData(ctx, src))) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, 0)) - write(ctx, cb.GlDeleteFramebuffers(1, sb.readsData(ctx, dst))) - } - } -} - -func getTextureTargetInfo(target GLenum) (isMultisample, isArray, is3D bool) { - switch target { - case GLenum_GL_TEXTURE_2D: - break - case GLenum_GL_TEXTURE_2D_ARRAY: - isArray = true - case GLenum_GL_TEXTURE_2D_MULTISAMPLE: - isMultisample = true - case GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - isMultisample, isArray = true, true - case GLenum_GL_TEXTURE_3D: - is3D = true - case GLenum_GL_TEXTURE_BUFFER: - break - case GLenum_GL_TEXTURE_CUBE_MAP: - break - case GLenum_GL_TEXTURE_CUBE_MAP_ARRAY: - isArray = true - case GLenum_GL_TEXTURE_EXTERNAL_OES: - break - default: - panic(fmt.Errorf("Unsupported texture type: %v", target)) - } - return -} - -// must be after renderbuffers and textures -func (sb *stateBuilder) framebufferObject(ctx context.Context, c Contextʳ, fb Framebufferʳ) { - write, cb, id := sb.write, sb.cb, fb.GetID() - - target := GLenum_GL_FRAMEBUFFER - write(ctx, cb.GlBindFramebuffer(target, id)) - - if id == 0 { - if drawBuffer := fb.DrawBuffer().Get(0); drawBuffer != GLenum_GL_BACK { - write(ctx, cb.GlDrawBuffers(1, sb.readsData(ctx, drawBuffer))) - } - if fb.ReadBuffer() != GLenum_GL_BACK { - write(ctx, cb.GlReadBuffer(fb.ReadBuffer())) - } - } else { - // Attachments - attach := func(name GLenum, a FramebufferAttachment) { - switch a.Type() { - case GLenum_GL_RENDERBUFFER: - write(ctx, cb.GlFramebufferRenderbuffer(target, name, a.Type(), a.Renderbuffer().GetID())) - case GLenum_GL_TEXTURE: - ty, id, level, layer := a.Texture().Kind(), a.Texture().GetID(), a.TextureLevel(), a.TextureLayer() - _, isArray, is3D := getTextureTargetInfo(ty) - if a.NumViews() > 1 { - write(ctx, cb.GlFramebufferTextureMultiviewOVR(target, name, id, level, layer, a.NumViews())) - } else if ty == GLenum_GL_TEXTURE_CUBE_MAP { - if a.Layered() == GLboolean_GL_TRUE { - write(ctx, cb.GlFramebufferTexture(target, name, id, level)) // GLES32 - } else { - ty = GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(a.TextureLayer()%6) - write(ctx, cb.GlFramebufferTexture2D(target, name, ty, id, level)) - } - } else if isArray || is3D { - if a.Layered() == GLboolean_GL_TRUE { - write(ctx, cb.GlFramebufferTexture(target, name, id, level)) // GLES32 - } else if a.NumViews() == 1 { - write(ctx, cb.GlFramebufferTextureLayer(target, name, id, level, layer)) // GLES30 - } - } else { - write(ctx, cb.GlFramebufferTexture2D(target, name, ty, id, level)) - } - } - } - for _, i := range fb.ColorAttachments().Keys() { - attach(GLenum_GL_COLOR_ATTACHMENT0+GLenum(i), fb.ColorAttachments().Get(i)) - } - attach(GLenum_GL_DEPTH_ATTACHMENT, fb.DepthAttachment()) - attach(GLenum_GL_STENCIL_ATTACHMENT, fb.StencilAttachment()) - - // Active attachments - drawBuffers := []GLenum{} - for i := 0; i < fb.DrawBuffer().Len(); i++ { - drawBuffers = append(drawBuffers, fb.DrawBuffer().Get(GLint(i))) - } - write(ctx, cb.GlDrawBuffers(GLsizei(len(drawBuffers)), sb.readsData(ctx, drawBuffers))) - write(ctx, cb.GlReadBuffer(fb.ReadBuffer())) - - // Parameters - param := func(name GLenum, value GLint) { - write(ctx, cb.GlFramebufferParameteri(target, name, value)) - } - param(GLenum_GL_FRAMEBUFFER_DEFAULT_WIDTH, fb.DefaultWidth()) // GLES31 - param(GLenum_GL_FRAMEBUFFER_DEFAULT_HEIGHT, fb.DefaultHeight()) // GLES31 - param(GLenum_GL_FRAMEBUFFER_DEFAULT_LAYERS, fb.DefaultLayers()) // GLES32 - param(GLenum_GL_FRAMEBUFFER_DEFAULT_SAMPLES, fb.DefaultSamples()) // GLES31 - if fb.DefaultFixedSampleLocations() == GLboolean_GL_TRUE { - param(GLenum_GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS, 1) // GLES31 - } - } -} - -func (sb *stateBuilder) imageUnit(ctx context.Context, i ImageUnitʳ) { - write, cb, id := sb.write, sb.cb, i.GetID() - - if !i.Texture().IsNil() { - write(ctx, cb.GlBindImageTexture(id, i.Texture().GetID(), i.Level(), i.Layered(), i.Layer(), i.Access(), i.Fmt())) // GLES31 - } -} - -func (sb *stateBuilder) shaderObject(ctx context.Context, s Shaderʳ) { - write, cb, id := sb.write, sb.cb, s.GetID() - - write(ctx, cb.GlCreateShader(s.Type(), id)) - if e := s.CompileExtra(); !e.IsNil() { - if !e.Binary().IsNil() { - sb.E(ctx, "Precompiled shaders not suppored yet") // TODO - } - write(ctx, cb.GlShaderSource(id, 1, sb.readsData(ctx, sb.readsData(ctx, e.Source())), memory.Nullptr)) - write(ctx, api.WithExtras(cb.GlCompileShader(id), e.Get().Clone(cb.Arena, sb.cloneCtx))) - } - write(ctx, cb.GlShaderSource(id, 1, sb.readsData(ctx, sb.readsData(ctx, s.Source())), memory.Nullptr)) -} - -func (sb *stateBuilder) programObject(ctx context.Context, p Programʳ) { - write, cb, id := sb.write, sb.cb, p.GetID() - - write(ctx, cb.GlCreateProgram(id)) - for _, name := range p.AttributeBindings().Keys() { - write(ctx, cb.GlBindAttribLocation(id, p.AttributeBindings().Get(name), sb.readsData(ctx, name))) - } - if count := p.TransformFeedbackVaryings().Len(); count > 0 { - varyings := make([]memory.Pointer, count) - for _, i := range p.TransformFeedbackVaryings().Keys() { - varyings[i] = sb.readsData(ctx, p.TransformFeedbackVaryings().Get(i)) - } - mode := p.TransformFeedbackBufferMode() - write(ctx, cb.GlTransformFeedbackVaryings(id, GLsizei(len(varyings)), sb.readsData(ctx, varyings), mode)) - } - if p.Separable() { - write(ctx, cb.GlProgramParameteri(id, GLenum_GL_PROGRAM_SEPARABLE, 1)) - } - if p.BinaryRetrievableHint() { - write(ctx, cb.GlProgramParameteri(id, GLenum_GL_PROGRAM_BINARY_RETRIEVABLE_HINT, 1)) - } - if !p.LinkExtra().IsNil() { - if p.SuccessfulLinkExtra() != p.LinkExtra() { - sb.E(ctx, "Stale program executable not suppored yet") // TODO - } - if !p.LinkExtra().Binary().IsNil() { - sb.E(ctx, "Precompiled programs not suppored yet") // TODO - } - - // Create the shaders from the extra. - attachedShaders := []ShaderId{} - for _, t := range p.LinkExtra().Shaders().Keys() { - s := p.LinkExtra().Shaders().Get(t) - if !s.Binary().IsNil() { - sb.E(ctx, "Precompiled programs not suppored yet") // TODO - continue - } - write(ctx, cb.GlCreateShader(t, s.ID())) - write(ctx, cb.GlShaderSource(s.ID(), 1, sb.readsData(ctx, sb.readsData(ctx, s.Source())), memory.Nullptr)) - write(ctx, api.WithExtras(cb.GlCompileShader(s.ID()), s.Get().Clone(cb.Arena, sb.cloneCtx))) - write(ctx, cb.GlAttachShader(id, s.ID())) - attachedShaders = append(attachedShaders, s.ID()) - } - - write(ctx, api.WithExtras(cb.GlLinkProgram(id), p.LinkExtra().Get().Clone(cb.Arena, sb.cloneCtx))) - write(ctx, cb.GlUseProgram(id)) - for _, k := range p.ActiveResources().DefaultUniformBlock().Keys() { - u := p.ActiveResources().DefaultUniformBlock().Get(k) - if loc, ok := u.Locations().Lookup(0); ok { - sb.uniform(ctx, u.Type(), UniformLocation(loc), GLsizei(u.ArraySize()), sb.readsSlice(ctx, u.Value())) - } - } - for _, loc := range p.ActiveResources().UniformBlocks().Keys() { - b := p.ActiveResources().UniformBlocks().Get(loc) - if index := b.Binding(); index > 0 { - write(ctx, cb.GlUniformBlockBinding(id, UniformBlockIndex(loc), GLuint(index))) - } - } - write(ctx, cb.GlUseProgram(0)) - - // Detach and delete the linked shaders (we'll attach the shaders from the state later). - for _, shaderID := range attachedShaders { - write(ctx, cb.GlDetachShader(id, shaderID)) - write(ctx, cb.GlDeleteShader(shaderID)) - } - } - if !p.ValidateExtra().IsNil() { - write(ctx, api.WithExtras(cb.GlValidateProgram(id), p.ValidateExtra().Get().Clone(cb.Arena, sb.cloneCtx))) - } -} - -func (sb *stateBuilder) attachShaders(ctx context.Context, p Programʳ) { - write, cb, id := sb.write, sb.cb, p.GetID() - - for _, k := range p.Shaders().Keys() { - if s := p.Shaders().Get(k).GetID(); s != 0 { - write(ctx, cb.GlAttachShader(id, s)) - } - } -} - -func (sb *stateBuilder) uniform(ctx context.Context, ty GLenum, loc UniformLocation, n GLsizei, v memory.Pointer) { - write, cb := sb.write, sb.cb - - switch ty { - case GLenum_GL_FLOAT: - write(ctx, cb.GlUniform1fv(loc, n, v)) - case GLenum_GL_FLOAT_VEC2: - write(ctx, cb.GlUniform2fv(loc, n, v)) - case GLenum_GL_FLOAT_VEC3: - write(ctx, cb.GlUniform3fv(loc, n, v)) - case GLenum_GL_FLOAT_VEC4: - write(ctx, cb.GlUniform4fv(loc, n, v)) - case GLenum_GL_BOOL: - case GLenum_GL_INT: - write(ctx, cb.GlUniform1iv(loc, n, v)) - case GLenum_GL_BOOL_VEC2: - case GLenum_GL_INT_VEC2: - write(ctx, cb.GlUniform2iv(loc, n, v)) - case GLenum_GL_BOOL_VEC3: - case GLenum_GL_INT_VEC3: - write(ctx, cb.GlUniform3iv(loc, n, v)) - case GLenum_GL_BOOL_VEC4: - case GLenum_GL_INT_VEC4: - write(ctx, cb.GlUniform4iv(loc, n, v)) - case GLenum_GL_UNSIGNED_INT: - write(ctx, cb.GlUniform1uiv(loc, n, v)) - case GLenum_GL_UNSIGNED_INT_VEC2: - write(ctx, cb.GlUniform2uiv(loc, n, v)) - case GLenum_GL_UNSIGNED_INT_VEC3: - write(ctx, cb.GlUniform3uiv(loc, n, v)) - case GLenum_GL_UNSIGNED_INT_VEC4: - write(ctx, cb.GlUniform4uiv(loc, n, v)) - case GLenum_GL_FLOAT_MAT2: - write(ctx, cb.GlUniformMatrix2fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT3: - write(ctx, cb.GlUniformMatrix3fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT4: - write(ctx, cb.GlUniformMatrix4fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT2x3: - write(ctx, cb.GlUniformMatrix2x3fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT2x4: - write(ctx, cb.GlUniformMatrix2x4fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT3x2: - write(ctx, cb.GlUniformMatrix3x2fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT3x4: - write(ctx, cb.GlUniformMatrix3x4fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT4x2: - write(ctx, cb.GlUniformMatrix4x2fv(loc, n, GLboolean_GL_FALSE, v)) - case GLenum_GL_FLOAT_MAT4x3: - write(ctx, cb.GlUniformMatrix4x3fv(loc, n, GLboolean_GL_FALSE, v)) - default: - write(ctx, cb.GlUniform1iv(loc, n, v)) - } -} - -func (sb *stateBuilder) pipelineObject(ctx context.Context, pipe Pipelineʳ) { - write, cb, id := sb.write, sb.cb, pipe.GetID() - - write(ctx, cb.GlBindProgramPipeline(id)) - write(ctx, cb.GlActiveShaderProgram(id, pipe.ActiveProgram().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_COMPUTE_SHADER_BIT, pipe.ComputeShader().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_FRAGMENT_SHADER_BIT, pipe.FragmentShader().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_VERTEX_SHADER_BIT, pipe.VertexShader().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_TESS_CONTROL_SHADER_BIT, pipe.TessControlShader().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_TESS_EVALUATION_SHADER_BIT, pipe.TessEvaluationShader().GetID())) - write(ctx, cb.GlUseProgramStages(id, GLbitfield_GL_GEOMETRY_SHADER_BIT, pipe.GeometryShader().GetID())) - if !pipe.ValidateExtra().IsNil() { - write(ctx, api.WithExtras(cb.GlValidateProgramPipeline(id), pipe.ValidateExtra().Get().Clone(cb.Arena, sb.cloneCtx))) - } - write(ctx, cb.GlBindProgramPipeline(0)) -} - -func (sb *stateBuilder) textureObject(ctx context.Context, t Textureʳ) { - write, cb, id := sb.write, sb.cb, t.GetID() - - target := t.Kind() - isMultisample, isArray, is3D := getTextureTargetInfo(target) - isCompressed := func(img Imageʳ) bool { - return GetSizedFormatInfoOrPanic(img.SizedFormat()).Compression() != CompressionAlgorithm_Uncompressed - } - - write(ctx, cb.GlBindTexture(target, id)) - - // Allocate space for texture data - if target == GLenum_GL_TEXTURE_BUFFER { - b := t.Buffer() - write(ctx, cb.GlTexBufferRange(target, b.InternalFormat(), b.Binding().GetID(), b.Offset(), b.Size())) - } else if target == GLenum_GL_TEXTURE_EXTERNAL_OES { - // The dimensions are fully specified by the EGLimage - } else if t.ImmutableFormat() == GLboolean_GL_TRUE { - img := t.Levels().Get(0).Layers().Get(0) // Must exist - lvl, fmt := GLsizei(t.Levels().Len()), img.getCorrectInternalFormat() - w, h, d := img.Width(), img.Height(), GLsizei(t.Levels().Get(0).Layers().Len()) - samples, fixed := img.Samples(), img.FixedSampleLocations() - if isMultisample { - if isArray || is3D { - write(ctx, cb.GlTexStorage3DMultisample(target, samples, fmt, w, h, d, fixed)) - } else { - write(ctx, cb.GlTexStorage2DMultisample(target, samples, fmt, w, h, fixed)) - } - } else { - if isArray || is3D { - write(ctx, cb.GlTexStorage3D(target, lvl, fmt, w, h, d)) - } else { - write(ctx, cb.GlTexStorage2D(target, lvl, fmt, w, h)) - } - } - } else if isArray || is3D { - for _, lvl := range t.Levels().Keys() { - levelObject := t.Levels().Get(lvl) - img := levelObject.Layers().Get(0) // Must exist, all layers must be consistent. - fmt, w, h, d := img.getCorrectInternalFormat(), img.Width(), img.Height(), GLsizei(levelObject.Layers().Len()) - dataFormat, dataType := img.getUnsizedFormatAndType() - if isCompressed(img) { - dataSize := GLsizei(img.Data().Size()) * d - write(ctx, cb.GlCompressedTexImage3D(target, lvl, fmt, w, h, d, 0, dataSize, memory.Nullptr)) - } else { - write(ctx, cb.GlTexImage3D(target, lvl, GLint(fmt), w, h, d, 0, dataFormat, dataType, memory.Nullptr)) - } - } - } else { - for _, lvl := range t.Levels().Keys() { - levelObject := t.Levels().Get(lvl) - for _, layer := range levelObject.Layers().Keys() { - img := levelObject.Layers().Get(layer) - // NB: Each face of cubemap faces can technically have different format and size. - fmt, w, h := img.getCorrectInternalFormat(), img.Width(), img.Height() - dataFormat, dataType := img.getUnsizedFormatAndType() - target := target - if target == GLenum_GL_TEXTURE_CUBE_MAP { - target = GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(layer%6) - } - - if isCompressed(img) { - write(ctx, cb.GlCompressedTexImage2D(target, lvl, fmt, w, h, 0, GLsizei(img.Data().Size()), memory.Nullptr)) - } else { - write(ctx, cb.GlTexImage2D(target, lvl, GLint(fmt), w, h, 0, dataFormat, dataType, memory.Nullptr)) - } - } - } - } - - // Upload the layers one by one - for _, lvl := range t.Levels().Keys() { - levelObject := t.Levels().Get(lvl) - for _, layer := range levelObject.Layers().Keys() { - img := levelObject.Layers().Get(layer) - fmt, w, h, d := img.getCorrectInternalFormat(), img.Width(), img.Height(), GLsizei(1) - dataFormat, dataType := img.getUnsizedFormatAndType() - dataSize, data := GLsizei(img.Data().Size()), sb.readsSlice(ctx, img.Data()) - - if dataSize == 0 { - continue // The texture layer was not initialized. - } else if target == GLenum_GL_TEXTURE_BUFFER { - continue // There should be no images or layers. - } else if target == GLenum_GL_TEXTURE_EXTERNAL_OES { - continue // The content is fully specified by the EGLimage - } else if isArray || is3D { - if isCompressed(img) { - write(ctx, cb.GlCompressedTexSubImage3D(target, lvl, 0, 0, layer, w, h, d, fmt, dataSize, data)) - } else { - write(ctx, cb.GlTexSubImage3D(target, lvl, 0, 0, layer, w, h, d, dataFormat, dataType, data)) - } - } else { - target := target - if target == GLenum_GL_TEXTURE_CUBE_MAP { - target = GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X + GLenum(layer%6) - } - if isCompressed(img) { - write(ctx, cb.GlCompressedTexSubImage2D(target, lvl, 0, 0, w, h, fmt, dataSize, data)) - } else { - write(ctx, cb.GlTexSubImage2D(target, lvl, 0, 0, w, h, dataFormat, dataType, data)) - } - } - } - } - - defaults := MakeTexture(sb.tmpArena) - parami := func(name GLenum, value GLint, defaultValue GLint) { - if value != defaultValue || target == GLenum_GL_TEXTURE_EXTERNAL_OES { - write(ctx, cb.GlTexParameteri(target, name, value)) - } - } - parami(GLenum_GL_TEXTURE_MAG_FILTER, GLint(t.MagFilter()), GLint(defaults.MagFilter())) - parami(GLenum_GL_TEXTURE_MIN_FILTER, GLint(t.MinFilter()), GLint(defaults.MinFilter())) - parami(GLenum_GL_TEXTURE_WRAP_S, GLint(t.WrapS()), GLint(defaults.WrapS())) - parami(GLenum_GL_TEXTURE_WRAP_T, GLint(t.WrapT()), GLint(defaults.WrapT())) - parami(GLenum_GL_TEXTURE_WRAP_R, GLint(t.WrapR()), GLint(defaults.WrapR())) - parami(GLenum_GL_TEXTURE_COMPARE_FUNC, GLint(t.CompareFunc()), GLint(defaults.CompareFunc())) - parami(GLenum_GL_TEXTURE_COMPARE_MODE, GLint(t.CompareMode()), GLint(defaults.CompareMode())) - parami(GLenum_GL_TEXTURE_BASE_LEVEL, t.BaseLevel(), defaults.BaseLevel()) - parami(GLenum_GL_TEXTURE_MAX_LEVEL, t.MaxLevel(), defaults.MaxLevel()) - parami(GLenum_GL_TEXTURE_SWIZZLE_A, GLint(t.SwizzleA()), GLint(defaults.SwizzleA())) - parami(GLenum_GL_TEXTURE_SWIZZLE_B, GLint(t.SwizzleB()), GLint(defaults.SwizzleB())) - parami(GLenum_GL_TEXTURE_SWIZZLE_G, GLint(t.SwizzleG()), GLint(defaults.SwizzleG())) - parami(GLenum_GL_TEXTURE_SWIZZLE_R, GLint(t.SwizzleR()), GLint(defaults.SwizzleR())) - parami(GLenum_GL_DEPTH_STENCIL_TEXTURE_MODE, GLint(t.DepthStencilTextureMode()), GLint(defaults.DepthStencilTextureMode())) - parami(GLenum_GL_TEXTURE_SRGB_DECODE_EXT, GLint(t.DecodeSRGB()), GLint(defaults.DecodeSRGB())) - if t.MaxLod() != defaults.MaxLod() { - write(ctx, cb.GlTexParameterf(target, GLenum_GL_TEXTURE_MAX_LOD, t.MaxLod())) - } - if t.MinLod() != defaults.MinLod() { - write(ctx, cb.GlTexParameterf(target, GLenum_GL_TEXTURE_MIN_LOD, t.MinLod())) - } - if !t.BorderColor().EqualTo(0, 0, 0, 0) { - write(ctx, cb.GlTexParameterfv(target, GLenum_GL_TEXTURE_BORDER_COLOR, sb.readsData(ctx, t.BorderColor()))) - } else if !t.BorderColorI().EqualTo(0, 0, 0, 0) { - write(ctx, cb.GlTexParameteriv(target, GLenum_GL_TEXTURE_BORDER_COLOR, sb.readsData(ctx, t.BorderColorI()))) - } - if t.MaxAnisotropy() != 1.0 { - write(ctx, cb.GlTexParameterf(target, GLenum_GL_TEXTURE_MAX_ANISOTROPY_EXT, GLfloat(t.MaxAnisotropy()))) - } -} - -func (sb *stateBuilder) samplerObject(ctx context.Context, s Samplerʳ) { - write, cb, id := sb.write, sb.cb, s.GetID() - - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_COMPARE_FUNC, GLint(s.CompareFunc()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_COMPARE_MODE, GLint(s.CompareMode()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_MIN_FILTER, GLint(s.MinFilter()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_MAG_FILTER, GLint(s.MagFilter()))) - write(ctx, cb.GlSamplerParameterf(id, GLenum_GL_TEXTURE_MIN_LOD, GLfloat(s.MinLod()))) - write(ctx, cb.GlSamplerParameterf(id, GLenum_GL_TEXTURE_MAX_LOD, GLfloat(s.MaxLod()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_WRAP_R, GLint(s.WrapR()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_WRAP_S, GLint(s.WrapS()))) - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_WRAP_T, GLint(s.WrapT()))) - write(ctx, cb.GlSamplerParameterf(id, GLenum_GL_TEXTURE_MAX_ANISOTROPY_EXT, GLfloat(s.MaxAnisotropy()))) - if !s.BorderColor().EqualTo(0, 0, 0, 0) { - write(ctx, cb.GlSamplerParameterfv(id, GLenum_GL_TEXTURE_BORDER_COLOR, sb.readsData(ctx, s.BorderColor()))) // GLES32 - } else if !s.BorderColorI().EqualTo(0, 0, 0, 0) { - write(ctx, cb.GlSamplerParameterIiv(id, GLenum_GL_TEXTURE_BORDER_COLOR, sb.readsData(ctx, s.BorderColorI()))) // GLES32 - } - if s.DecodeSRGB() != GLenum_GL_DECODE_EXT { - write(ctx, cb.GlSamplerParameteri(id, GLenum_GL_TEXTURE_SRGB_DECODE_EXT, GLint(s.DecodeSRGB()))) - } -} - -func (sb *stateBuilder) queryObject(ctx context.Context, q Queryʳ) { - write, cb, id := sb.write, sb.cb, q.GetID() - - target := q.Type() - write(ctx, cb.GlBeginQuery(target, id)) - if !q.Active() { - write(ctx, cb.GlEndQuery(target)) - } -} - -func (sb *stateBuilder) syncObject(ctx context.Context, s SyncObjectʳ) { - write, cb := sb.write, sb.cb - - write(ctx, cb.GlFenceSync(GLenum_GL_SYNC_GPU_COMMANDS_COMPLETE, 0, s.ID())) -} - -func (sb *stateBuilder) transformFeedbackObject(ctx context.Context, tf TransformFeedbackʳ) { - write, cb, id := sb.write, sb.cb, tf.GetID() - - write(ctx, cb.GlBindTransformFeedback(GLenum_GL_TRANSFORM_FEEDBACK, id)) - if tf.Active() == GLboolean_GL_TRUE { - sb.E(ctx, "Transform feedback data was not restored") // TODO - write(ctx, cb.GlBeginTransformFeedback(tf.PrimitiveMode())) - write(ctx, cb.GlPauseTransformFeedback()) - } - write(ctx, cb.GlBindTransformFeedback(GLenum_GL_TRANSFORM_FEEDBACK, 0)) -} - -func (sb *stateBuilder) vertexArrayObject(ctx context.Context, vao VertexArrayʳ) { - write, cb, id := sb.write, sb.cb, vao.GetID() - - write(ctx, cb.GlBindVertexArray(id)) - if id > 0 { - for _, loc := range vao.VertexAttributeArrays().Keys() { - vaa := vao.VertexAttributeArrays().Get(loc) - defaultArray := MakeVertexAttributeArray(sb.tmpArena) - defaultArray.SetBinding(vao.VertexBufferBindings().Get(VertexBufferBindingIndex(loc))) - if vaa.Get().Equals(defaultArray) { - continue // Default - } - if vaa.Enabled() == GLboolean_GL_TRUE { - write(ctx, cb.GlEnableVertexAttribArray(loc)) - } - if vaa.Stride() != 0 || vaa.Pointer() != memory.Nullptr { - // Same as glVertexAttribFormat for our purposes here, with the difference that - // it sets the obsolete and unused properties 'stride' and 'pointer'. - write(ctx, cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, vaa.Binding().Buffer().GetID())) - if vaa.Integer() == GLboolean_GL_TRUE { - write(ctx, cb.GlVertexAttribIPointer(loc, vaa.Size(), vaa.Type(), vaa.Stride(), vaa.Pointer())) - } else { - write(ctx, cb.GlVertexAttribPointer(loc, vaa.Size(), vaa.Type(), vaa.Normalized(), vaa.Stride(), vaa.Pointer())) - } - } else { - if vaa.Integer() == GLboolean_GL_TRUE { - write(ctx, cb.GlVertexAttribIFormat(loc, vaa.Size(), vaa.Type(), vaa.RelativeOffset())) - } else { - write(ctx, cb.GlVertexAttribFormat(loc, vaa.Size(), vaa.Type(), vaa.Normalized(), vaa.RelativeOffset())) - } - } - if VertexBufferBindingIndex(loc) != vaa.Binding().Id() { - write(ctx, cb.GlVertexAttribBinding(loc, vaa.Binding().Id())) - } - } - for _, i := range vao.VertexBufferBindings().Keys() { - b := vao.VertexBufferBindings().Get(i) - defaultBinding := MakeVertexBufferBinding(sb.tmpArena) - defaultBinding.SetId(VertexBufferBindingIndex(i)) - if b.Get().Equals(defaultBinding) { - continue - } - write(ctx, cb.GlBindVertexBuffer(i, b.Buffer().GetID(), b.Offset(), b.Stride())) - if divisor := b.Divisor(); divisor != 0 { - write(ctx, cb.GlVertexBindingDivisor(i, divisor)) - } - } - if !vao.ElementArrayBuffer().IsNil() { - write(ctx, cb.GlBindBuffer(GLenum_GL_ELEMENT_ARRAY_BUFFER, vao.ElementArrayBuffer().GetID())) - } - } else { - for _, loc := range vao.VertexAttributeArrays().Keys() { - vaa := vao.VertexAttributeArrays().Get(loc) - defaultArray := MakeVertexAttributeArray(sb.tmpArena) - defaultArray.SetBinding(vao.VertexBufferBindings().Get(VertexBufferBindingIndex(loc))) - if vaa.Get().Equals(defaultArray) { - continue // Default - } - if vaa.Enabled() == GLboolean_GL_TRUE { - write(ctx, cb.GlEnableVertexAttribArray(loc)) - } - write(ctx, cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, vaa.Binding().Buffer().GetID())) - if vaa.Integer() == GLboolean_GL_TRUE { - write(ctx, cb.GlVertexAttribIPointer(loc, vaa.Size(), vaa.Type(), vaa.Stride(), vaa.Pointer())) - } else { - write(ctx, cb.GlVertexAttribPointer(loc, vaa.Size(), vaa.Type(), vaa.Normalized(), vaa.Stride(), vaa.Pointer())) - } - if divisor := vaa.Binding().Divisor(); divisor != 0 { - write(ctx, cb.GlVertexAttribDivisor(loc, divisor)) - } - } - } - write(ctx, cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, 0)) - write(ctx, cb.GlBindVertexArray(0)) -} - -func (sb *stateBuilder) vertexState(ctx context.Context, vs VertexState) { - write, cb := sb.write, sb.cb - - for _, loc := range vs.Attributes().Keys() { - att := vs.Attributes().Get(loc) - switch att.Type() { - case GLenum_GL_FLOAT_VEC4: - write(ctx, cb.GlVertexAttrib4fv(loc, sb.readsSlice(ctx, att.Value()))) - case GLenum_GL_INT_VEC4: - write(ctx, cb.GlVertexAttribI4iv(loc, sb.readsSlice(ctx, att.Value()))) - case GLenum_GL_UNSIGNED_INT_VEC4: - write(ctx, cb.GlVertexAttribI4uiv(loc, sb.readsSlice(ctx, att.Value()))) - } - } - - write(ctx, cb.GlPatchParameteri(GLenum_GL_PATCH_VERTICES, vs.PatchVertices())) - - sb.enable(ctx, GLenum_GL_PRIMITIVE_RESTART_FIXED_INDEX, vs.PrimitiveRestartFixedIndex()) -} - -func (sb *stateBuilder) reasterizationState(ctx context.Context, rs RasterizationState) { - write, cb := sb.write, sb.cb - - write(ctx, cb.GlViewport(rs.Viewport().X(), rs.Viewport().Y(), rs.Viewport().Width(), rs.Viewport().Height())) - write(ctx, cb.GlDepthRangef(rs.DepthRange().Get(0), rs.DepthRange().Get(1))) - if !rs.PrimitiveBoundingBox().IsUnit() { - min, max := rs.PrimitiveBoundingBox().Min(), rs.PrimitiveBoundingBox().Max() - write(ctx, cb.GlPrimitiveBoundingBox( - min.Get(0), min.Get(1), min.Get(2), min.Get(3), - max.Get(0), max.Get(1), max.Get(2), max.Get(3)), - ) - } - - // Rasterization - sb.enable(ctx, GLenum_GL_RASTERIZER_DISCARD, rs.RasterizerDiscard()) - write(ctx, cb.GlLineWidth(rs.LineWidth())) - sb.enable(ctx, GLenum_GL_CULL_FACE, rs.CullFace()) - write(ctx, cb.GlCullFace(rs.CullFaceMode())) - write(ctx, cb.GlFrontFace(rs.FrontFace())) - write(ctx, cb.GlPolygonOffset(rs.PolygonOffsetFactor(), rs.PolygonOffsetUnits())) - sb.enable(ctx, GLenum_GL_POLYGON_OFFSET_FILL, rs.PolygonOffsetFill()) - - // Multisampling - sb.enable(ctx, GLenum_GL_SAMPLE_ALPHA_TO_COVERAGE, rs.SampleAlphaToCoverage()) - sb.enable(ctx, GLenum_GL_SAMPLE_COVERAGE, rs.SampleCoverage()) - write(ctx, cb.GlSampleCoverage(rs.SampleCoverageValue(), rs.SampleCoverageInvert())) - sb.enable(ctx, GLenum_GL_SAMPLE_SHADING, rs.SampleShading()) - write(ctx, cb.GlMinSampleShading(rs.MinSampleShadingValue())) - sb.enable(ctx, GLenum_GL_SAMPLE_MASK, rs.SampleMask()) - for _, i := range rs.SampleMaskValue().Keys() { - write(ctx, cb.GlSampleMaski(i, rs.SampleMaskValue().Get(i))) // GLES31 - } -} - -func (sb *stateBuilder) pixelState(ctx context.Context, ps PixelState) { - write, cb := sb.write, sb.cb - - // Scissor - sb.enable(ctx, GLenum_GL_SCISSOR_TEST, ps.Scissor().Test()) - write(ctx, cb.GlScissor(ps.Scissor().Box().X(), ps.Scissor().Box().Y(), ps.Scissor().Box().Width(), ps.Scissor().Box().Height())) - - // Stencil - st := ps.Stencil() - sb.enable(ctx, GLenum_GL_STENCIL_TEST, st.Test()) - write(ctx, cb.GlStencilFuncSeparate(GLenum_GL_FRONT, st.Func(), st.Ref(), st.ValueMask())) - write(ctx, cb.GlStencilOpSeparate(GLenum_GL_FRONT, st.Fail(), st.PassDepthFail(), st.PassDepthPass())) - write(ctx, cb.GlStencilFuncSeparate(GLenum_GL_BACK, st.BackFunc(), st.BackRef(), st.BackValueMask())) - write(ctx, cb.GlStencilOpSeparate(GLenum_GL_BACK, st.BackFail(), st.BackPassDepthFail(), st.BackPassDepthPass())) - - // Blend - write(ctx, cb.GlBlendColor(ps.BlendColor().Red(), ps.BlendColor().Green(), ps.BlendColor().Blue(), ps.BlendColor().Alpha())) - for _, i := range ps.Blend().Keys() { - bs := ps.Blend().Get(i) - write(ctx, cb.GlBlendEquationSeparatei(i, bs.EquationRgb(), bs.EquationAlpha())) // GLES32 - write(ctx, cb.GlBlendFuncSeparatei(i, bs.SrcRgb(), bs.DstRgb(), bs.SrcAlpha(), bs.DstAlpha())) // GLES32 - sb.enablei(ctx, GLenum_GL_BLEND, GLuint(i), bs.Enabled()) // GLES32? - } - - // Depth - sb.enable(ctx, GLenum_GL_DEPTH_TEST, ps.Depth().Test()) - write(ctx, cb.GlDepthFunc(ps.Depth().Func())) - - sb.enable(ctx, GLenum_GL_DITHER, ps.Dither()) - sb.enable(ctx, GLenum_GL_FRAMEBUFFER_SRGB_EXT, ps.FramebufferSrgb()) - - // Framebuffer control - for _, i := range ps.ColorWritemask().Keys() { - mask := ps.ColorWritemask().Get(i) - write(ctx, cb.GlColorMaski(i, mask.R(), mask.G(), mask.B(), mask.A())) // GLES32 - } - write(ctx, cb.GlDepthMask(ps.DepthWritemask())) - write(ctx, cb.GlStencilMaskSeparate(GLenum_GL_FRONT, ps.StencilWritemask())) - write(ctx, cb.GlStencilMaskSeparate(GLenum_GL_BACK, ps.StencilBackWritemask())) - clearColor := ps.ColorClearValue() - write(ctx, cb.GlClearColor(clearColor.Get(0), clearColor.Get(1), clearColor.Get(2), clearColor.Get(3))) - write(ctx, cb.GlClearDepthf(ps.DepthClearValue())) - write(ctx, cb.GlClearStencil(ps.StencilClearValue())) -} - -// must be done after all data uploads (because it sets unpack state) -func (sb *stateBuilder) otherState(ctx context.Context, os OtherState) { - write, cb := sb.write, sb.cb - - // glPixelStorei - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_ALIGNMENT, os.Pack().Alignment())) - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_IMAGE_HEIGHT, os.Pack().ImageHeight())) - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_ROW_LENGTH, os.Pack().RowLength())) - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_SKIP_IMAGES, os.Pack().SkipImages())) - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_SKIP_PIXELS, os.Pack().SkipPixels())) - write(ctx, cb.GlPixelStorei(GLenum_GL_PACK_SKIP_ROWS, os.Pack().SkipRows())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_ALIGNMENT, os.Unpack().Alignment())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_IMAGE_HEIGHT, os.Unpack().ImageHeight())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_ROW_LENGTH, os.Unpack().RowLength())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_SKIP_IMAGES, os.Unpack().SkipImages())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_SKIP_PIXELS, os.Unpack().SkipPixels())) - write(ctx, cb.GlPixelStorei(GLenum_GL_UNPACK_SKIP_ROWS, os.Unpack().SkipRows())) - - // Debug state - write(ctx, cb.GlDebugMessageCallback(os.Debug().CallbackFunction(), os.Debug().CallbackUserParam())) - sb.enable(ctx, GLenum_GL_DEBUG_OUTPUT, os.Debug().Output()) - sb.enable(ctx, GLenum_GL_DEBUG_OUTPUT_SYNCHRONOUS, os.Debug().OutputSynchronous()) -} - -func (sb *stateBuilder) debugLabels(ctx context.Context, c Contextʳ) { - write, cb := sb.write, sb.cb - - label := func(target GLenum, id GLuint, text string) { - if text != "" { - write(ctx, cb.GlObjectLabel(target, id, GLsizei(len(text)), sb.readsData(ctx, text))) - } - } - for _, id := range c.Objects().Textures().Keys() { - label(GLenum_GL_TEXTURE, GLuint(id), c.Objects().Textures().Get(id).Label()) - } - for _, id := range c.Objects().Framebuffers().Keys() { - label(GLenum_GL_FRAMEBUFFER, GLuint(id), c.Objects().Framebuffers().Get(id).Label()) - } - for _, id := range c.Objects().Renderbuffers().Keys() { - label(GLenum_GL_RENDERBUFFER, GLuint(id), c.Objects().Renderbuffers().Get(id).Label()) - } - for _, id := range c.Objects().Buffers().Keys() { - label(GLenum_GL_BUFFER, GLuint(id), c.Objects().Buffers().Get(id).Label()) - } - for _, id := range c.Objects().Shaders().Keys() { - label(GLenum_GL_SHADER, GLuint(id), c.Objects().Shaders().Get(id).Label()) - } - for _, id := range c.Objects().Programs().Keys() { - label(GLenum_GL_PROGRAM, GLuint(id), c.Objects().Programs().Get(id).Label()) - } - for _, id := range c.Objects().VertexArrays().Keys() { - label(GLenum_GL_VERTEX_ARRAY, GLuint(id), c.Objects().VertexArrays().Get(id).Label()) - } - for _, id := range c.Objects().Queries().Keys() { - label(GLenum_GL_QUERY, GLuint(id), c.Objects().Queries().Get(id).Label()) - } - for _, id := range c.Objects().Samplers().Keys() { - label(GLenum_GL_SAMPLER, GLuint(id), c.Objects().Samplers().Get(id).Label()) - } - for _, id := range c.Objects().TransformFeedbacks().Keys() { - label(GLenum_GL_TRANSFORM_FEEDBACK, GLuint(id), c.Objects().TransformFeedbacks().Get(id).Label()) - } - for _, id := range c.Objects().Pipelines().Keys() { - label(GLenum_GL_PROGRAM_PIPELINE, GLuint(id), c.Objects().Pipelines().Get(id).Label()) - } -} - -// bindings must be done at the end, since other stages overwrite them. -func (sb *stateBuilder) bindings(ctx context.Context, c Contextʳ) { - write, cb := sb.write, sb.cb - - // Most of this method assumes binding points are initialized to 0. - // So first reset all binding points which used in other code to 0. - write(ctx, cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, 0)) - write(ctx, cb.GlBindRenderbuffer(GLenum_GL_RENDERBUFFER, 0)) - write(ctx, cb.GlBindFramebuffer(GLenum_GL_FRAMEBUFFER, 0)) - - // TODO: This does not handle deleted objects which are still bound. - - // Indexed-buffers - { - bind := func(target GLenum, bindings GLuintːBufferBindingᵐ) { - for _, index := range bindings.Keys() { - b := bindings.Get(index) - if id := b.Binding().GetID(); id != 0 { - write(ctx, cb.GlBindBufferRange(target, index, id, b.Start(), b.Size())) - } - } - } - bind(GLenum_GL_UNIFORM_BUFFER, c.Bound().UniformBuffers()) //GLES30 - bind(GLenum_GL_ATOMIC_COUNTER_BUFFER, c.Bound().AtomicCounterBuffers()) //GLES31 - bind(GLenum_GL_SHADER_STORAGE_BUFFER, c.Bound().ShaderStorageBuffers()) //GLES31 - for _, k := range c.Objects().TransformFeedbacks().Keys() { - tf := c.Objects().TransformFeedbacks().Get(k) - write(ctx, cb.GlBindTransformFeedback(GLenum_GL_TRANSFORM_FEEDBACK, tf.GetID())) - bind(GLenum_GL_TRANSFORM_FEEDBACK_BUFFER, tf.Buffers()) //GLES30 - } - } - - // Non-indexed buffers (must be after indexed due to generic binding points) - { - bind := func(target GLenum, b Bufferʳ) { - if id := b.GetID(); id != 0 { - write(ctx, cb.GlBindBuffer(target, id)) - } - } - bind(GLenum_GL_ARRAY_BUFFER, c.Bound().ArrayBuffer()) //GLES20 - bind(GLenum_GL_ELEMENT_ARRAY_BUFFER, c.Bound().VertexArray().ElementArrayBuffer()) //GLES20 - bind(GLenum_GL_COPY_READ_BUFFER, c.Bound().CopyReadBuffer()) //GLES30 - bind(GLenum_GL_COPY_WRITE_BUFFER, c.Bound().CopyWriteBuffer()) //GLES30 - bind(GLenum_GL_PIXEL_PACK_BUFFER, c.Bound().PixelPackBuffer()) //GLES30 - bind(GLenum_GL_PIXEL_UNPACK_BUFFER, c.Bound().PixelUnpackBuffer()) //GLES30 - bind(GLenum_GL_UNIFORM_BUFFER, c.Bound().UniformBuffer()) //GLES30 - bind(GLenum_GL_ATOMIC_COUNTER_BUFFER, c.Bound().AtomicCounterBuffer()) //GLES31 - bind(GLenum_GL_DISPATCH_INDIRECT_BUFFER, c.Bound().DispatchIndirectBuffer()) //GLES31 - bind(GLenum_GL_DRAW_INDIRECT_BUFFER, c.Bound().DrawIndirectBuffer()) //GLES31 - bind(GLenum_GL_SHADER_STORAGE_BUFFER, c.Bound().ShaderStorageBuffer()) //GLES31 - bind(GLenum_GL_TEXTURE_BUFFER, c.Bound().TextureBuffer()) //GLES32 - for _, k := range c.Objects().TransformFeedbacks().Keys() { - tf := c.Objects().TransformFeedbacks().Get(k) - write(ctx, cb.GlBindTransformFeedback(GLenum_GL_TRANSFORM_FEEDBACK, tf.GetID())) - bind(GLenum_GL_TRANSFORM_FEEDBACK_BUFFER, tf.Buffer()) //GLES30 - } - } - - // Samplers - for _, unit := range c.Objects().TextureUnits().Keys() { - tu := c.Objects().TextureUnits().Get(unit) - if sampler := tu.SamplerBinding().GetID(); sampler != 0 { - write(ctx, cb.GlBindSampler(GLuint(unit), sampler)) - } - } - - // Programs - write(ctx, cb.GlUseProgram(c.Bound().Program().GetID())) - if id := c.Bound().Pipeline().GetID(); id != 0 { - write(ctx, cb.GlBindProgramPipeline(id)) - } - - // Transform feedback - write(ctx, cb.GlBindTransformFeedback(GLenum_GL_TRANSFORM_FEEDBACK, c.Bound().TransformFeedback().GetID())) - if c.Bound().TransformFeedback().Active() == GLboolean_GL_TRUE && - c.Bound().TransformFeedback().Paused() == GLboolean_GL_FALSE { - // Active and unpaused transform feedback is very limiting on possible state modifications. - // So create it in paused state and resume it fairly late (only one can be active&resumed). - write(ctx, cb.GlResumeTransformFeedback()) - } - - // Vertex Array - write(ctx, cb.GlBindVertexArray(c.Bound().VertexArray().GetID())) -} - -// deleteMarkedObjects will delete objects if they are marked for deletion. -// This must be done after bindings since bindings are still keeping them alive. -func (sb *stateBuilder) deleteMarkedObjects(ctx context.Context, c Contextʳ) { - write, cb := sb.write, sb.cb - - for _, id := range c.Objects().Shaders().Keys() { - if c.Objects().Shaders().Get(id).DeleteStatus() { - write(ctx, cb.GlDeleteShader(id)) - } - } - for _, id := range c.Objects().Programs().Keys() { - if c.Objects().Programs().Get(id).DeleteStatus() { - write(ctx, cb.GlDeleteProgram(id)) - } - } -} diff --git a/gapis/api/gles/string.go b/gapis/api/gles/string.go deleted file mode 100644 index e3e2322bf2..0000000000 --- a/gapis/api/gles/string.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import "fmt" - -func (c Color) String() string { - return fmt.Sprintf("R:% 6f, G:% 6f, B:% 6f, A:% 6f", c.Red(), c.Green(), c.Blue(), c.Alpha()) -} - -func (v Vec2f) String() string { - return fmt.Sprintf("(% 6f, % 6f)", v.Get(0), v.Get(1)) -} - -func (v Vec3f) String() string { - return fmt.Sprintf("(% 6f, % 6f, % 6f)", v.Get(0), v.Get(1), v.Get(2)) -} - -func (v Vec4f) String() string { - return fmt.Sprintf("(% 6f, % 6f, % 6f, % 6f)", v.Get(0), v.Get(1), v.Get(2), v.Get(3)) -} - -func (v Vec2i) String() string { - return fmt.Sprintf("(% 6d, % 6d)", v.Get(0), v.Get(1)) -} - -func (v Vec3i) String() string { - return fmt.Sprintf("(% 6d, % 6d, % 6d)", v.Get(0), v.Get(1), v.Get(2)) -} - -func (v Vec4i) String() string { - return fmt.Sprintf("(% 6d, % 6d, % 6d, % 6d)", v.Get(0), v.Get(1), v.Get(2), v.Get(3)) -} - -func (m Mat2f) String() string { - return fmt.Sprintf(".Get(%), %v]", m.Get(0), m.Get(1)) -} - -func (m Mat3f) String() string { - return fmt.Sprintf(".Get(%), %v, %v]", m.Get(0), m.Get(1), m.Get(2)) -} - -func (m Mat4f) String() string { - return fmt.Sprintf(".Get(%), %v, %v, %v]", m.Get(0), m.Get(1), m.Get(2), m.Get(3)) -} - -func (a VertexAttributeArray) String() string { - if a.Enabled() == GLboolean_GL_TRUE { - return fmt.Sprintf("%d x %v", int(a.Size()), a.Type()) - } - return "disabled" -} diff --git a/gapis/api/gles/stub_program.go b/gapis/api/gles/stub_program.go deleted file mode 100644 index 72063194a6..0000000000 --- a/gapis/api/gles/stub_program.go +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - "sort" - "strings" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" -) - -var ( - // We don't include tests directly in the gles package as it adds - // signaficantly to the test build time. - VisibleForTestingStubShaderSource = stubShaderSource -) - -func buildStubProgram(ctx context.Context, thread uint64, e *api.CmdExtras, s *api.GlobalState, programID ProgramId) []api.Cmd { - programInfo := FindLinkProgramExtra(s.Arena, e).Clone(s.Arena, api.CloneContext{}) - vss, fss, err := stubShaderSource(programInfo) - if err != nil { - log.E(ctx, "Unable to build stub shader: %v", err) - } - c := GetContext(s, thread) - vertexShaderID := ShaderId(newUnusedID(ctx, 'S', func(x uint32) bool { - ok := c.Objects().Buffers().Contains(BufferId(x)) - return ok - })) - fragmentShaderID := ShaderId(newUnusedID(ctx, 'S', func(x uint32) bool { - ok := c.Objects().Buffers().Contains(BufferId(x)) - return ok || x == uint32(vertexShaderID) - })) - cb := CommandBuilder{Thread: thread, Arena: s.Arena} - glLinkProgram := cb.GlLinkProgram(programID) - glLinkProgram.Extras().Add(programInfo) - return append( - CompileProgram(ctx, s, cb, vertexShaderID, fragmentShaderID, programID, vss, fss), - glLinkProgram, - ) -} - -func stubShaderSource(pi LinkProgramExtraʳ) (vertexShaderSource, fragmentShaderSource string, err error) { - vsDecls, fsDecls := []string{}, []string{} - vsTickles, fsTickles := []string{}, []string{} - if !pi.IsNil() && !pi.ActiveResources().IsNil() { - for _, u := range pi.ActiveResources().DefaultUniformBlock().All() { - var decls, tickles *[]string - if isSampler(u.Type()) { - decls, tickles = &fsDecls, &fsTickles - } else { - decls, tickles = &vsDecls, &vsTickles - } - - ty, err := glslTypeFor(u.Type()) - if err != nil { - return "", "", err - } - if u.ArraySize() > 1 { - name := strings.TrimRight(u.Name(), "[0]") - *decls = append(*decls, fmt.Sprintf("uniform %s %s[%d];\n", ty, name, u.ArraySize())) - for i := GLint(0); i < u.ArraySize(); i++ { - tkl, err := glslTickle(u.Type(), fmt.Sprintf("%s[%d]", name, i)) - if err != nil { - return "", "", err - } - *tickles = append(*tickles, fmt.Sprintf("no_strip += %s;\n ", tkl)) - } - } else { - *decls = append(*decls, fmt.Sprintf("uniform %s %s;\n", ty, u.Name())) - tkl, err := glslTickle(u.Type(), u.Name()) - if err != nil { - return "", "", err - } - *tickles = append(*tickles, fmt.Sprintf("no_strip += %s;\n ", tkl)) - } - } - // Deterministic output FTW! - sort.Strings(vsDecls) - sort.Strings(fsDecls) - sort.Strings(vsTickles) - sort.Strings(fsTickles) - } - return fmt.Sprintf(`#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -%svoid main() { - float no_strip = 0.0; - %sgl_Position = vec4(no_strip * 0.000001, 0., 0., 1.); -}`, strings.Join(vsDecls, ""), strings.Join(vsTickles, "")), - fmt.Sprintf(`#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -%svoid main() { - float no_strip = 0.0; - %sgl_FragColor = vec4(1., no_strip * 0.000001, 1., 1.); -}`, strings.Join(fsDecls, ""), strings.Join(fsTickles, "")), nil -} - -func glslTypeFor(ty GLenum) (string, error) { - switch ty { - case GLenum_GL_FLOAT: - return "float", nil - case GLenum_GL_FLOAT_VEC2: - return "vec2", nil - case GLenum_GL_FLOAT_VEC3: - return "vec3", nil - case GLenum_GL_FLOAT_VEC4: - return "vec4", nil - case GLenum_GL_INT: - return "int", nil - case GLenum_GL_INT_VEC2: - return "ivec2", nil - case GLenum_GL_INT_VEC3: - return "ivec3", nil - case GLenum_GL_INT_VEC4: - return "ivec4", nil - case GLenum_GL_UNSIGNED_INT: - return "unsigned int", nil - case GLenum_GL_UNSIGNED_INT_VEC2: - return "uvec2", nil - case GLenum_GL_UNSIGNED_INT_VEC3: - return "uvec3", nil - case GLenum_GL_UNSIGNED_INT_VEC4: - return "uvec4", nil - case GLenum_GL_BOOL: - return "bool", nil - case GLenum_GL_BOOL_VEC2: - return "bvec2", nil - case GLenum_GL_BOOL_VEC3: - return "bvec3", nil - case GLenum_GL_BOOL_VEC4: - return "bvec4", nil - case GLenum_GL_FLOAT_MAT2: - return "mat2", nil - case GLenum_GL_FLOAT_MAT3: - return "mat3", nil - case GLenum_GL_FLOAT_MAT4: - return "mat4", nil - case GLenum_GL_FLOAT_MAT2x3: - return "mat2x3", nil - case GLenum_GL_FLOAT_MAT2x4: - return "mat2x4", nil - case GLenum_GL_FLOAT_MAT3x2: - return "mat3x2", nil - case GLenum_GL_FLOAT_MAT3x4: - return "mat3x4", nil - case GLenum_GL_FLOAT_MAT4x2: - return "mat4x2", nil - case GLenum_GL_FLOAT_MAT4x3: - return "mat4x3", nil - case GLenum_GL_SAMPLER_2D: - return "sampler2D", nil - case GLenum_GL_SAMPLER_3D: - return "sampler3D", nil - case GLenum_GL_SAMPLER_CUBE: - return "samplerCube", nil - case GLenum_GL_SAMPLER_2D_SHADOW: - return "sampler2DShadow", nil - case GLenum_GL_SAMPLER_2D_ARRAY: - return "sampler2DArray", nil - case GLenum_GL_SAMPLER_2D_ARRAY_SHADOW: - return "sampler2DArrayShadow", nil - case GLenum_GL_SAMPLER_CUBE_SHADOW: - return "samplerCubeShadow", nil - case GLenum_GL_INT_SAMPLER_2D: - return "isampler2D", nil - case GLenum_GL_INT_SAMPLER_3D: - return "isampler3D", nil - case GLenum_GL_INT_SAMPLER_CUBE: - return "isamplerCube", nil - case GLenum_GL_INT_SAMPLER_2D_ARRAY: - return "isampler2DArray", nil - case GLenum_GL_UNSIGNED_INT_SAMPLER_2D: - return "usampler2D", nil - case GLenum_GL_UNSIGNED_INT_SAMPLER_3D: - return "usampler3D", nil - case GLenum_GL_UNSIGNED_INT_SAMPLER_CUBE: - return "usamplerCube", nil - case GLenum_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - return "usampler2DArray", nil - default: - return "", fmt.Errorf("Unknown uniform type %s", ty) - } -} - -func isSampler(ty GLenum) bool { - switch ty { - case GLenum_GL_SAMPLER_2D, - GLenum_GL_SAMPLER_3D, - GLenum_GL_SAMPLER_CUBE, - GLenum_GL_SAMPLER_2D_SHADOW, - GLenum_GL_SAMPLER_2D_ARRAY, - GLenum_GL_SAMPLER_2D_ARRAY_SHADOW, - GLenum_GL_SAMPLER_CUBE_SHADOW, - GLenum_GL_INT_SAMPLER_2D, - GLenum_GL_INT_SAMPLER_3D, - GLenum_GL_INT_SAMPLER_CUBE, - GLenum_GL_INT_SAMPLER_2D_ARRAY, - GLenum_GL_UNSIGNED_INT_SAMPLER_2D, - GLenum_GL_UNSIGNED_INT_SAMPLER_3D, - GLenum_GL_UNSIGNED_INT_SAMPLER_CUBE, - GLenum_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - return true - default: - return false - } -} - -func glslTickle(ty GLenum, name string) (string, error) { - switch ty { - case GLenum_GL_FLOAT: - return name, nil - case GLenum_GL_FLOAT_VEC2, GLenum_GL_FLOAT_VEC3, GLenum_GL_FLOAT_VEC4: - return fmt.Sprintf("%s.x", name), nil - case GLenum_GL_INT, GLenum_GL_UNSIGNED_INT: - return fmt.Sprintf("float(%s)", name), nil - case GLenum_GL_INT_VEC2, GLenum_GL_INT_VEC3, GLenum_GL_INT_VEC4, - GLenum_GL_UNSIGNED_INT_VEC2, GLenum_GL_UNSIGNED_INT_VEC3, GLenum_GL_UNSIGNED_INT_VEC4: - return fmt.Sprintf("float(%s.x)", name), nil - case GLenum_GL_BOOL: - return fmt.Sprintf("(%s?1.:0.)", name), nil - case GLenum_GL_BOOL_VEC2, GLenum_GL_BOOL_VEC3, GLenum_GL_BOOL_VEC4: - return fmt.Sprintf("(%s?1.:0.)", name), nil - case GLenum_GL_FLOAT_MAT2, GLenum_GL_FLOAT_MAT3, GLenum_GL_FLOAT_MAT4, - GLenum_GL_FLOAT_MAT2x3, GLenum_GL_FLOAT_MAT2x4, - GLenum_GL_FLOAT_MAT3x2, GLenum_GL_FLOAT_MAT3x4, - GLenum_GL_FLOAT_MAT4x2, GLenum_GL_FLOAT_MAT4x3: - return fmt.Sprintf("%s[0].x", name), nil - case GLenum_GL_SAMPLER_2D: - return fmt.Sprintf("texture2D(%s, vec2(0.)).x", name), nil - case GLenum_GL_SAMPLER_3D: - return fmt.Sprintf("texture3D(%s, vec3(0.)).x", name), nil - case GLenum_GL_SAMPLER_CUBE: - return fmt.Sprintf("textureCube(%s, vec3(0.)).x", name), nil - - // The below types do not exist in GLSL 110. - case GLenum_GL_SAMPLER_2D_SHADOW, - GLenum_GL_SAMPLER_2D_ARRAY_SHADOW, - GLenum_GL_SAMPLER_CUBE_SHADOW: - return fmt.Sprintf("texture(%s, vec3(0.))", name), nil - - case GLenum_GL_SAMPLER_2D_ARRAY, - GLenum_GL_INT_SAMPLER_2D, - GLenum_GL_INT_SAMPLER_3D, - GLenum_GL_INT_SAMPLER_CUBE, - GLenum_GL_INT_SAMPLER_2D_ARRAY, - GLenum_GL_UNSIGNED_INT_SAMPLER_2D, - GLenum_GL_UNSIGNED_INT_SAMPLER_3D, - GLenum_GL_UNSIGNED_INT_SAMPLER_CUBE, - GLenum_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - return fmt.Sprintf("texture(%s, vec3(0.)).x", name), nil - default: - return "", fmt.Errorf("Unknown uniform type %s", ty) - } -} diff --git a/gapis/api/gles/stub_program_test.go b/gapis/api/gles/stub_program_test.go deleted file mode 100644 index cb885d0032..0000000000 --- a/gapis/api/gles/stub_program_test.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles_test - -import ( - "testing" - - "github.com/google/gapid/core/memory/arena" - "github.com/google/gapid/gapis/api/gles" -) - -func TestStubShaderSource(t *testing.T) { - a := arena.New() - defer a.Dispose() - - type uniform struct { - ty gles.GLenum - name string - size gles.GLint - } - - newLPE := func(uniforms ...uniform) gles.LinkProgramExtraʳ { - m := gles.NewUniformIndexːProgramResourceʳᵐ(a) - for i, u := range uniforms { - res := gles.MakeProgramResourceʳ(a) - res.SetType(u.ty) - res.SetName(u.name) - res.SetArraySize(u.size) - m.Add(gles.UniformIndex(i), res) - } - resources := gles.MakeActiveProgramResourcesʳ(a) - resources.SetDefaultUniformBlock(m) - - out := gles.MakeLinkProgramExtraʳ(a) - out.SetLinkStatus(gles.GLboolean_GL_TRUE) - out.SetActiveResources(resources) - return out - } - - for _, test := range []struct { - name string - pi gles.LinkProgramExtraʳ - vs, fs string - }{ - { - name: "Simple", - pi: newLPE( - uniform{ty: gles.GLenum_GL_FLOAT_VEC4, name: "foo"}, - uniform{ty: gles.GLenum_GL_SAMPLER_2D, name: "bar"}, - ), - vs: `#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -uniform vec4 foo; -void main() { - float no_strip = 0.0; - no_strip += foo.x; - gl_Position = vec4(no_strip * 0.000001, 0., 0., 1.); -}`, - fs: `#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -uniform sampler2D bar; -void main() { - float no_strip = 0.0; - no_strip += texture2D(bar, vec2(0.)).x; - gl_FragColor = vec4(1., no_strip * 0.000001, 1., 1.); -}`, - }, { - name: "Array", - pi: newLPE( - uniform{ty: gles.GLenum_GL_FLOAT_VEC4, name: "foo", size: 3}, - uniform{ty: gles.GLenum_GL_FLOAT_VEC4, name: "bar[0]", size: 3}, - ), - vs: `#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -uniform vec4 bar[3]; -uniform vec4 foo[3]; -void main() { - float no_strip = 0.0; - no_strip += bar[0].x; - no_strip += bar[1].x; - no_strip += bar[2].x; - no_strip += foo[0].x; - no_strip += foo[1].x; - no_strip += foo[2].x; - gl_Position = vec4(no_strip * 0.000001, 0., 0., 1.); -}`, - fs: `#version 150 - -///////////////////////////////////////////// -// GAPID stub shader (no source available) // -///////////////////////////////////////////// - -precision highp float; -void main() { - float no_strip = 0.0; - gl_FragColor = vec4(1., no_strip * 0.000001, 1., 1.); -}`, - }, - } { - vs, fs, err := gles.VisibleForTestingStubShaderSource(test.pi) - if err != nil { - t.Errorf("Testing '%s': stubShaderSource returned error: %v", test.name, err) - } - if vs != test.vs { - t.Errorf("Testing '%s': Vertex shader was not as expected. Expected:\n%v\nGot:\n%s", test.name, test.vs, vs) - } - if fs != test.fs { - t.Errorf("Testing '%s': Fragment shader was not as expected. Expected:\n%v\nGot:\n%s", test.name, test.fs, fs) - } - } -} diff --git a/gapis/api/gles/synthetic.api b/gapis/api/gles/synthetic.api deleted file mode 100644 index 567382e659..0000000000 --- a/gapis/api/gles/synthetic.api +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// replayCreateRenderer constructs a GLES renderer for replay without making it active. -@synthetic -cmd void replayCreateRenderer(u32 rendererID) { } - -// replayBindRenderer makes the renderer constructed with replayCreateRenderer active. -@synthetic -cmd void replayBindRenderer(u32 rendererID, bool reset_viewport_scissor) { } - -// replayUnbindRenderer makes the renderer constructed with replayCreateRenderer inactive. -@synthetic -cmd void replayUnbindRenderer(u32 rendererID) { } - -// replayChangeBackbuffer alters the backbuffer dimensions and format. -@synthetic -cmd void replayChangeBackbuffer(u32 rendererID, - GLsizei backbuffer_width, - GLsizei backbuffer_height, - GLenum backbuffer_color_fmt, - GLenum backbuffer_depth_fmt, - GLenum backbuffer_stencil_fmt) { } - -// replayCreateExternalImage creates a texture base EGL external image. This command -// is only valid if the replay target is GLES. -@synthetic -cmd EGLImageKHR replayCreateExternalImage(u32 rendererID, TextureId texture) { return ? } - -// replayFrameDelimiter replay a call that acts as a frame delimiter, e.g. eglSwapBuffers() -@synthetic -cmd void replayFrameDelimiter(u32 rendererID) { } - -@synthetic -cmd void startTimer(u8 index) { } - -@synthetic -cmd u64 stopTimer(u8 index) { return ? } // Time returned in nanoseconds - -@synthetic -cmd void flushPostBuffer() { } diff --git a/gapis/api/gles/templates/BUILD.bazel b/gapis/api/gles/templates/BUILD.bazel deleted file mode 100644 index c248ab3e3a..0000000000 --- a/gapis/api/gles/templates/BUILD.bazel +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("//tools/build:rules.bzl", "api_template") - -package(default_visibility = ["//visibility:public"]) - -api_template( - name = "api_exports.cpp", - includes = ["//gapis/api/templates"], - outputs = ["{api}_exports.cpp"], - template = "api_exports.cpp.tmpl", -) - -api_template( - name = "api_imports.cpp", - includes = ["//gapis/api/templates"], - outputs = ["{api}_imports.cpp"], - template = "api_imports.cpp.tmpl", -) diff --git a/gapis/api/gles/templates/api_exports.cpp.tmpl b/gapis/api/gles/templates/api_exports.cpp.tmpl deleted file mode 100644 index 5fb1c3da32..0000000000 --- a/gapis/api/gles/templates/api_exports.cpp.tmpl +++ /dev/null @@ -1,115 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl"}} - -{{$filename := print (Global "API") "_exports.cpp" }} -{{$ | Macro "Exports" | Reflow 4 | Write $filename}} - -{{define "Exports"}} - {{AssertType $ "API"}} - {{Template "C++.Copyright"}} -¶ -#include "gapii/cc/gles_exports.h" -#include "gapii/cc/{{Global "API"}}_imports.h" -#include "gapii/cc/{{Global "API"}}_types.h" -#include "gapii/cc/spy.h" -¶ -#include "core/cc/get_{{Global "API"}}_proc_address.h" -#include "core/cc/log.h" -#include "core/cc/target.h" // STDCALL -¶ -#include -¶ -#include -¶ -using namespace gapii; -¶ -const uint8_t GlesAPI = {{$.Index}}; -¶ -extern "C" {« - {{range $c := AllCommands $}} - {{if not (GetAnnotation $c "synthetic")}} - {{$name := Macro "CmdName" $c}} - EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}); - {{end}} - {{end}} -¶ - EXPORT void* STDCALL eglGetProcAddress(const char* name); - EXPORT void* STDCALL wglGetProcAddress(const char* name); - EXPORT void* STDCALL glXGetProcAddress(const char* name); - EXPORT void* STDCALL glXGetProcAddressARB(const char* name); -»} // extern "C" -¶ - -namespace gapii { - -Symbol kGLESExports[] = { -{{range $i, $c := AllCommandsSorted $}} - {{$name := Macro "CmdName" $c}} - {{if not (GetAnnotation $c "synthetic")}} - {"{{$name}}", reinterpret_cast({{$name}})}, - {{end}} -{{end}} - {"eglGetProcAddress", reinterpret_cast(eglGetProcAddress)}, - {"wglGetProcAddress", reinterpret_cast(wglGetProcAddress)}, - {"glXGetProcAddress", reinterpret_cast(glXGetProcAddress)}, - {"glXGetProcAddressARB", reinterpret_cast(glXGetProcAddressARB)}, - {NULL, NULL} -}; - -} // namespace gapii - - namespace {« -¶ - void* STDCALL GetSpyProcAddress(const char* name) { - if (void* proc = Spy::get()->LookupSymbol(name)) { - return proc; - } else { - GAPID_ERROR("%s will NOT be captured.", name); - return core::GetGlesProcAddress(name); - } - } -¶ - »} // anonymous namespace -¶ - extern "C" {« -¶ - {{range $c := AllCommands $}} - {{if not (GetAnnotation $c "synthetic")}} - {{$name := Macro "CmdName" $c}} - {{$imports := print (Title (Global "API")) "Spy::imports()"}} - EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}) { - GAPID_DEBUG({{Template "C++.PrintfCommandCall" $c}}); - Spy* s = Spy::get(); - auto spy_ctx = s->enter("{{$name}}", GlesAPI); - {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} - s->{{$name}}({{Macro "C++.CallArguments" $c | Strings "spy_ctx" | JoinWith ", "}}); - s->exit(); - GAPID_DEBUG("{{$name}}() -- done"); - {{if not (IsVoid $c.Return.Type)}}return _result_;{{end}} - } - {{end}} - {{end}} -¶ - EXPORT void* STDCALL eglGetProcAddress(const char* name) { return GetSpyProcAddress(name); } - EXPORT void* STDCALL wglGetProcAddress(const char* name) { return GetSpyProcAddress(name); } - EXPORT void* STDCALL glXGetProcAddress(const char* name) { return GetSpyProcAddress(name); } - EXPORT void* STDCALL glXGetProcAddressARB(const char* name) { return GetSpyProcAddress(name); } -¶ - »} // extern "C" -{{end}} diff --git a/gapis/api/gles/templates/api_imports.cpp.tmpl b/gapis/api/gles/templates/api_imports.cpp.tmpl deleted file mode 100644 index 40652ec62b..0000000000 --- a/gapis/api/gles/templates/api_imports.cpp.tmpl +++ /dev/null @@ -1,61 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl" }} -{{Include "../../templates/api_classnames.tmpl"}} - -{{$filename := print (Global "API") "_imports.cpp" }} -{{$ | Macro "imports.cpp" | Reflow 4 | Write $filename}} - -{{/* -------------------------------------------------------------------------------- - Entry point. -------------------------------------------------------------------------------- -*/}} -{{define "imports.cpp"}} -{{template "C++.Copyright"}} -¶ -#include "{{Global "API"}}_imports.h" -¶ -#include "core/cc/get_{{Global "API"}}_proc_address.h" -¶ -#include -¶ -namespace gapii { -¶ - {{$name := Macro "ApiClassnames.Imports"}} - {{$name}}::{{$name}}() { - memset(this, 0, sizeof(*this)); - resolve(); - } -¶ - void {{$name}}::resolve() { - if (!core::hasGLorGLES()) { - return; - } - using namespace core; - {{range $c := AllCommands $}} - {{if not (GetAnnotation $c "synthetic")}} - {{$name := Macro "CmdName" $c}} - {{$name}} = reinterpret_cast<{{Template "C++.FunctionPtrType" $c}}>(GetGlesProcAddress("{{$name}}")); - {{end}} - {{end}} - } -¶ -} // namespace gapii -¶ -{{end}} diff --git a/gapis/api/gles/texture_compat.go b/gapis/api/gles/texture_compat.go deleted file mode 100644 index fd91be25da..0000000000 --- a/gapis/api/gles/texture_compat.go +++ /dev/null @@ -1,473 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" -) - -var luminanceSwizzle = map[GLenum]GLenum{ - GLenum_GL_RED: GLenum_GL_RED, - GLenum_GL_GREEN: GLenum_GL_RED, - GLenum_GL_BLUE: GLenum_GL_RED, - GLenum_GL_ALPHA: GLenum_GL_ONE, -} -var alphaSwizzle = map[GLenum]GLenum{ - GLenum_GL_RED: GLenum_GL_ZERO, - GLenum_GL_GREEN: GLenum_GL_ZERO, - GLenum_GL_BLUE: GLenum_GL_ZERO, - GLenum_GL_ALPHA: GLenum_GL_RED, -} -var luminanceAlphaSwizzle = map[GLenum]GLenum{ - GLenum_GL_RED: GLenum_GL_RED, - GLenum_GL_GREEN: GLenum_GL_RED, - GLenum_GL_BLUE: GLenum_GL_RED, - GLenum_GL_ALPHA: GLenum_GL_GREEN, -} -var luminanceAlphaCompat = map[GLenum]struct { - rgFormat GLenum - compatSwizzle map[GLenum]GLenum -}{ - GLenum_GL_LUMINANCE: {GLenum_GL_RED, luminanceSwizzle}, - GLenum_GL_LUMINANCE8_EXT: {GLenum_GL_R8, luminanceSwizzle}, - GLenum_GL_LUMINANCE16F_EXT: {GLenum_GL_R16F, luminanceSwizzle}, - GLenum_GL_LUMINANCE32F_EXT: {GLenum_GL_R32F, luminanceSwizzle}, - GLenum_GL_ALPHA: {GLenum_GL_RED, alphaSwizzle}, - GLenum_GL_ALPHA8_EXT: {GLenum_GL_R8, alphaSwizzle}, - GLenum_GL_ALPHA16F_EXT: {GLenum_GL_R16F, alphaSwizzle}, - GLenum_GL_ALPHA32F_EXT: {GLenum_GL_R32F, alphaSwizzle}, - GLenum_GL_LUMINANCE_ALPHA: {GLenum_GL_RG, luminanceAlphaSwizzle}, - GLenum_GL_LUMINANCE8_ALPHA8_EXT: {GLenum_GL_RG8, luminanceAlphaSwizzle}, - GLenum_GL_LUMINANCE_ALPHA16F_EXT: {GLenum_GL_RG16F, luminanceAlphaSwizzle}, - GLenum_GL_LUMINANCE_ALPHA32F_EXT: {GLenum_GL_RG32F, luminanceAlphaSwizzle}, -} - -type textureCompat struct { - f features - v *Version - - // Original user-defined swizzle which would be used without compatibility layer. - // (GL_TEXTURE_SWIZZLE_{R,G,B,A}, Texture) -> GL_{RED,GREEN,BLUE,ALPHA,ONE,ZERO} - origSwizzle map[GLenum]map[Textureʳ]GLenum - - // Compatibility component remapping needed to support luminance/alpha formats. - // Texture -> (GL_{RED,GREEN,BLUE,ALPHA} -> GL_{RED,GREEN,ONE,ZERO}) - compatSwizzle map[Textureʳ]map[GLenum]GLenum -} - -// getSwizzle returns the original user-defined swizzle and the current swizzle from state. -func (tc *textureCompat) getSwizzle(t Textureʳ, parameter GLenum) (orig, curr GLenum) { - var init GLenum - switch parameter { - case GLenum_GL_TEXTURE_SWIZZLE_R: - init, curr = GLenum_GL_RED, t.SwizzleR() - case GLenum_GL_TEXTURE_SWIZZLE_G: - init, curr = GLenum_GL_GREEN, t.SwizzleG() - case GLenum_GL_TEXTURE_SWIZZLE_B: - init, curr = GLenum_GL_BLUE, t.SwizzleB() - case GLenum_GL_TEXTURE_SWIZZLE_A: - init, curr = GLenum_GL_ALPHA, t.SwizzleA() - } - if orig, ok := tc.origSwizzle[parameter][t]; ok { - return orig, curr - } - return init, curr -} - -func (tc *textureCompat) writeCompatSwizzle(ctx context.Context, cb CommandBuilder, t Textureʳ, parameter GLenum, out transform.Writer, id api.CmdID) { - target := t.Kind() - orig, curr := tc.getSwizzle(t, parameter) - compat := orig - if compatSwizzle, ok := tc.compatSwizzle[t]; ok { - if v, ok := compatSwizzle[compat]; ok { - compat = v - } - } - if compat != curr { - out.MutateAndWrite(ctx, id.Derived(), cb.GlTexParameteri(target, parameter, GLint(compat))) - } -} - -type glenumProperty struct { - get func() GLenum - set func(GLenum) -} - -// Common handler for all glTex* methods. -// Arguments may be null if the given method does not use them. -func (tc *textureCompat) convertFormat( - ctx context.Context, - target GLenum, - internalformat, format, componentType *glenumProperty, - out transform.Writer, - id api.CmdID, - cmd api.Cmd) { - - // Compressed formats are replaced by RGBA8 - // TODO: What about SRGB? - if internalformat != nil && isCompressedFormat(internalformat.get()) { - if _, supported := tc.f.compressedTextureFormats[internalformat.get()]; !supported { - internalformat.set(GLenum_GL_RGBA8) - } - } - - if tc.v.IsES { - return - } - - // ES and desktop disagree how unsized internal formats are represented - // (floats in particular), so always explicitly use one of the sized formats. - if internalformat != nil && format != nil && componentType != nil && internalformat.get() == format.get() { - internalformat.set(getSizedFormatFromTuple(internalformat.get(), componentType.get())) - } - - if internalformat != nil { - s := out.State() - - switch target { - case GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_X, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - GLenum_GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GLenum_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - target = GLenum_GL_TEXTURE_CUBE_MAP - } - - // Luminance/Alpha is not supported on desktop so convert it to R/G. - if t, err := subGetBoundTextureOrErrorInvalidEnum(ctx, nil, api.CmdNoID, nil, s, GetState(s), cmd.Thread(), nil, nil, target); err == nil { - if laCompat, ok := luminanceAlphaCompat[internalformat.get()]; ok { - internalformat.set(laCompat.rgFormat) - tc.compatSwizzle[t] = laCompat.compatSwizzle - } else { - // Remove the compat mapping and reset swizzles to the original values below. - delete(tc.compatSwizzle, t) - } - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - tc.writeCompatSwizzle(ctx, cb, t, GLenum_GL_TEXTURE_SWIZZLE_R, out, id) - tc.writeCompatSwizzle(ctx, cb, t, GLenum_GL_TEXTURE_SWIZZLE_G, out, id) - tc.writeCompatSwizzle(ctx, cb, t, GLenum_GL_TEXTURE_SWIZZLE_B, out, id) - tc.writeCompatSwizzle(ctx, cb, t, GLenum_GL_TEXTURE_SWIZZLE_A, out, id) - } - - switch internalformat.get() { - case GLenum_GL_BGRA8_EXT: // Not supported in GL 3.2 - // The GPU order of channels is transparent to us, so we can just use RGBA instead. - internalformat.set(GLenum_GL_RGBA8) - case GLenum_GL_RGB565: // Not supported in GL 3.2 - internalformat.set(GLenum_GL_RGB8) - case GLenum_GL_RGB10_A2UI: // Not supported in GL 3.2 - internalformat.set(GLenum_GL_RGBA16UI) - case GLenum_GL_STENCIL_INDEX8: // TODO: not supported on desktop. - } - } - - if format != nil { - // Luminance/Alpha is not supported on desktop so convert it to R/G. - switch format.get() { - case GLenum_GL_LUMINANCE, GLenum_GL_ALPHA: - format.set(GLenum_GL_RED) - case GLenum_GL_LUMINANCE_ALPHA: - format.set(GLenum_GL_RG) - } - } - - if componentType != nil { - // Half-float is a core feature on desktop (with different enum value) - if componentType.get() == GLenum_GL_HALF_FLOAT_OES { - componentType.set(GLenum_GL_HALF_FLOAT) - } - } -} - -func (tc *textureCompat) postTexParameter(ctx context.Context, target, parameter GLenum, out transform.Writer, id api.CmdID, cmd api.Cmd) { - if tc.v.IsES { - return - } - - s := out.State() - switch parameter { - case GLenum_GL_TEXTURE_SWIZZLE_R, GLenum_GL_TEXTURE_SWIZZLE_G, GLenum_GL_TEXTURE_SWIZZLE_B, GLenum_GL_TEXTURE_SWIZZLE_A: - if t, err := subGetBoundTextureOrErrorInvalidEnum(ctx, nil, api.CmdNoID, nil, s, GetState(s), cmd.Thread(), nil, nil, target); err == nil { - _, curr := tc.getSwizzle(t, parameter) - // The tex parameter was recently mutated, so set the original swizzle from current state. - tc.origSwizzle[parameter][t] = curr - // Combine the original and compat swizzles and write out the commands to set it. - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - tc.writeCompatSwizzle(ctx, cb, t, parameter, out, id) - } - case GLenum_GL_TEXTURE_SWIZZLE_RGBA: - log.E(ctx, "Unexpected GL_TEXTURE_SWIZZLE_RGBA") - } -} - -// decompressTexImage2D writes a glTexImage2D using the decompressed data for -// the given glCompressedTexImage2D. -func decompressTexImage2D(ctx context.Context, i api.CmdID, a *GlCompressedTexImage2D, s *api.GlobalState, out transform.Writer) error { - ctx = log.Enter(ctx, "decompressTexImage2D") - dID := i.Derived() - c := GetContext(s, a.Thread()) - cb := CommandBuilder{Thread: a.Thread(), Arena: s.Arena} - data := AsU8ˢ(s.Arena, a.Data().Slice(0, uint64(a.ImageSize()), s.MemoryLayout), s.MemoryLayout) - if pb := c.Bound().PixelUnpackBuffer(); !pb.IsNil() { - offset := a.Data().Address() - data = pb.Data().Slice(offset, offset+uint64(a.ImageSize())) - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, 0)) - defer out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, pb.ID())) - } else { - a.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - } - - format, err := getCompressedImageFormat(a.Internalformat()) - if err != nil { - return err - } - - src := image.Info{ - Bytes: image.NewID(data.ResourceID(ctx, s)), - Width: uint32(a.Width()), - Height: uint32(a.Height()), - Depth: 1, - Format: format, - } - dst, err := src.Convert(ctx, image.RGBA_U8_NORM) - if err != nil { - return err - } - - dstSize := a.Width() * a.Height() * 4 - - tmp := s.AllocOrPanic(ctx, uint64(dstSize)) - out.MutateAndWrite(ctx, i, cb.GlTexImage2D( - a.Target(), - a.Level(), - GLint(GLenum_GL_RGBA8), - a.Width(), - a.Height(), - a.Border(), - GLenum_GL_RGBA, - GLenum_GL_UNSIGNED_BYTE, - tmp.Ptr(), - ).AddRead(tmp.Range(), dst.Bytes.ID())) - tmp.Free() - - return nil -} - -// decompressTexSubImage2D writes a glTexSubImage2D using the decompressed data for -// the given glCompressedTexSubImage2D. -func decompressTexSubImage2D(ctx context.Context, i api.CmdID, a *GlCompressedTexSubImage2D, s *api.GlobalState, out transform.Writer) error { - ctx = log.Enter(ctx, "decompressTexSubImage2D") - dID := i.Derived() - c := GetContext(s, a.Thread()) - cb := CommandBuilder{Thread: a.Thread(), Arena: s.Arena} - data := AsU8ˢ(s.Arena, a.Data().Slice(0, uint64(a.ImageSize()), s.MemoryLayout), s.MemoryLayout) - if pb := c.Bound().PixelUnpackBuffer(); !pb.IsNil() { - offset := a.Data().Address() - data = pb.Data().Slice(offset, offset+uint64(a.ImageSize())) - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, 0)) - defer out.MutateAndWrite(ctx, dID, cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, pb.ID())) - } else { - a.Extras().Observations().ApplyReads(s.Memory.ApplicationPool()) - } - - format, err := getCompressedImageFormat(a.Internalformat()) - if err != nil { - return err - } - - src := image.Info{ - Bytes: image.NewID(data.ResourceID(ctx, s)), - Width: uint32(a.Width()), - Height: uint32(a.Height()), - Depth: 1, - Format: format, - } - dst, err := src.Convert(ctx, image.RGBA_U8_NORM) - if err != nil { - return err - } - - dstSize := a.Width() * a.Height() * 4 - - tmp := s.AllocOrPanic(ctx, uint64(dstSize)) - out.MutateAndWrite(ctx, i, cb.GlTexSubImage2D( - a.Target(), - a.Level(), - a.Xoffset(), - a.Yoffset(), - a.Width(), - a.Height(), - GLenum_GL_RGBA, - GLenum_GL_UNSIGNED_BYTE, - tmp.Ptr(), - ).AddRead(tmp.Range(), dst.Bytes.ID())) - tmp.Free() - - return nil -} - -// getSupportedCompressedTextureFormats returns the set of supported compressed -// texture formats for a given extension list. -func getSupportedCompressedTextureFormats(v *Version, extensions extensions) map[GLenum]struct{} { - supported := map[GLenum]struct{}{} - for extension := range extensions { - for _, format := range getExtensionTextureFormats(extension) { - supported[format] = struct{}{} - } - } - if v.AtLeastES(3, 0) || v.AtLeastGL(4, 3) { - supported[GLenum_GL_COMPRESSED_R11_EAC] = struct{}{} - supported[GLenum_GL_COMPRESSED_SIGNED_R11_EAC] = struct{}{} - supported[GLenum_GL_COMPRESSED_RG11_EAC] = struct{}{} - supported[GLenum_GL_COMPRESSED_SIGNED_RG11_EAC] = struct{}{} - supported[GLenum_GL_COMPRESSED_RGB8_ETC2] = struct{}{} - supported[GLenum_GL_COMPRESSED_SRGB8_ETC2] = struct{}{} - supported[GLenum_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2] = struct{}{} - supported[GLenum_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2] = struct{}{} - supported[GLenum_GL_COMPRESSED_RGBA8_ETC2_EAC] = struct{}{} - supported[GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC] = struct{}{} - } - return supported - -} - -// getExtensionTextureFormats returns the list of compressed texture formats -// enabled by a given extension -func getExtensionTextureFormats(extension string) []GLenum { - switch extension { - case "GL_AMD_compressed_ATC_texture": - return []GLenum{ - GLenum_GL_ATC_RGB_AMD, - GLenum_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, - GLenum_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, - } - case "GL_OES_compressed_ETC1_RGB8_texture": - return []GLenum{ - GLenum_GL_ETC1_RGB8_OES, - } - case "GL_EXT_texture_compression_dxt1": - return []GLenum{ - GLenum_GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - } - case "GL_EXT_texture_compression_s3tc", "GL_NV_texture_compression_s3tc": - return []GLenum{ - GLenum_GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - } - case "GL_KHR_texture_compression_astc_ldr": - return []GLenum{ - GLenum_GL_COMPRESSED_RGBA_ASTC_4x4_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_5x4_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_5x5_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_6x5_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_6x6_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x5_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x6_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x8_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x5_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x6_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x8_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x10_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_12x10_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_12x12_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, - } - case "GL_EXT_texture_compression_latc", "GL_NV_texture_compression_latc": - return []GLenum{ - GLenum_GL_COMPRESSED_LUMINANCE_LATC1_EXT, - GLenum_GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT, - GLenum_GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, - GLenum_GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT, - } - default: - return []GLenum{} - } -} - -func isCompressedFormat(internalformat GLenum) bool { - switch internalformat { - case - GLenum_GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, - GLenum_GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, - GLenum_GL_ATC_RGB_AMD, - GLenum_GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT, - GLenum_GL_COMPRESSED_LUMINANCE_LATC1_EXT, - GLenum_GL_COMPRESSED_RG11_EAC, - GLenum_GL_COMPRESSED_RGB8_ETC2, - GLenum_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, - GLenum_GL_COMPRESSED_RGBA8_ETC2_EAC, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x10_KHR, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x5, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x6, - GLenum_GL_COMPRESSED_RGBA_ASTC_10x8, - GLenum_GL_COMPRESSED_RGBA_ASTC_12x10, - GLenum_GL_COMPRESSED_RGBA_ASTC_12x12, - GLenum_GL_COMPRESSED_RGBA_ASTC_4x4, - GLenum_GL_COMPRESSED_RGBA_ASTC_5x4, - GLenum_GL_COMPRESSED_RGBA_ASTC_5x5, - GLenum_GL_COMPRESSED_RGBA_ASTC_6x5, - GLenum_GL_COMPRESSED_RGBA_ASTC_6x6, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x5, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x6, - GLenum_GL_COMPRESSED_RGBA_ASTC_8x8, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - GLenum_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - GLenum_GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - GLenum_GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT, - GLenum_GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT, - GLenum_GL_COMPRESSED_SIGNED_R11_EAC, - GLenum_GL_COMPRESSED_SIGNED_RG11_EAC, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8, - GLenum_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, - GLenum_GL_COMPRESSED_SRGB8_ETC2, - GLenum_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, - GLenum_GL_ETC1_RGB8_OES: - return true - } - return false -} diff --git a/gapis/api/gles/tweaker.go b/gapis/api/gles/tweaker.go deleted file mode 100644 index 7c5a729b06..0000000000 --- a/gapis/api/gles/tweaker.go +++ /dev/null @@ -1,514 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - "fmt" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" -) - -// tweaker provides a set of methods for temporarily changing the GLES state. -type tweaker struct { - out transform.Writer - cb CommandBuilder - dID api.CmdID // Derived ID to use for generated commands. Can be NoID. - s *api.GlobalState - c Contextʳ - undo []func(context.Context) -} - -func newTweaker(out transform.Writer, id api.CmdID, cb CommandBuilder) *tweaker { - s := out.State() - c := GetContext(s, cb.Thread) - dID := id.Derived() - return &tweaker{out: out, cb: cb, dID: dID, s: s, c: c} -} - -// revert undoes all the changes made by the tweaker. -func (t *tweaker) revert(ctx context.Context) { - for i := len(t.undo) - 1; i >= 0; i-- { - t.undo[i](ctx) - } - t.undo = nil -} - -func (t *tweaker) doAndUndo(ctx context.Context, do, undo api.Cmd) { - t.out.MutateAndWrite(ctx, t.dID, do) - t.undo = append(t.undo, func(ctx context.Context) { - t.out.MutateAndWrite(ctx, t.dID, undo) - }) -} - -func (t *tweaker) AllocData(ctx context.Context, v ...interface{}) api.AllocResult { - tmp := t.s.AllocDataOrPanic(ctx, v...) - t.undo = append(t.undo, func(ctx context.Context) { tmp.Free() }) - return tmp -} - -func (t *tweaker) getCapability(ctx context.Context, name GLenum) bool { - a := t.cb.GlIsEnabled(name, 0) - o := a.Extras().Observations() - s := t.out.State() - i := GLuint(0) // capability index. - res, err := subGetCapability(ctx, a, t.dID, o, s, GetState(s), a.Thread(), nil, nil, name, i) - if err != nil { - return false - } - return res != 0 -} - -func (t *tweaker) eglMakeCurrent(ctx context.Context, nID EGLContext) { - var oID EGLContext - for k, v := range GetState(t.s).EGLContexts().All() { - if v == t.c { - oID = k - break - } - } - if oCtx, nCtx := t.c, GetState(t.s).EGLContexts().Get(nID); oCtx != nCtx { - t.out.MutateAndWrite(ctx, t.dID, t.cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, nID, 1)) - t.c = nCtx - t.undo = append(t.undo, func(ctx context.Context) { - t.out.MutateAndWrite(ctx, t.dID, t.cb.EglMakeCurrent(memory.Nullptr, memory.Nullptr, memory.Nullptr, oID, 1)) - t.c = oCtx - }) - } -} - -func (t *tweaker) glEnable(ctx context.Context, name GLenum) { - // TODO: This does not correctly handle indexed state. - if o := t.getCapability(ctx, name); o != true { - t.doAndUndo(ctx, - t.cb.GlEnable(name), - t.cb.GlDisable(name)) - } -} - -func (t *tweaker) glDisable(ctx context.Context, name GLenum) { - // TODO: This does not correctly handle indexed state. - if o := t.getCapability(ctx, name); o != false { - t.doAndUndo(ctx, - t.cb.GlDisable(name), - t.cb.GlEnable(name)) - } -} - -func (t *tweaker) glViewport(ctx context.Context, x, y GLint, w, h GLsizei) { - if o := t.c.Rasterization().Viewport(); !o.EqualTo(x, y, w, h) { - t.doAndUndo(ctx, - t.cb.GlViewport(x, y, w, h), - t.cb.GlViewport(o.X(), o.Y(), o.Width(), o.Height())) - } -} - -func (t *tweaker) glDisableVertexAttribArray(ctx context.Context, l AttributeLocation) { - arr := t.c.Bound().VertexArray().VertexAttributeArrays().Get(l) - if !arr.IsNil() && arr.Enabled() == GLboolean_GL_TRUE { - t.doAndUndo(ctx, - t.cb.GlDisableVertexAttribArray(l), - t.cb.GlEnableVertexAttribArray(l)) - } -} - -func (t *tweaker) glDepthMask(ctx context.Context, v GLboolean) { - if o := t.c.Pixel().DepthWritemask(); o != v { - t.doAndUndo(ctx, - t.cb.GlDepthMask(v), - t.cb.GlDepthMask(o)) - } -} - -func (t *tweaker) glDepthFunc(ctx context.Context, v GLenum) { - if o := t.c.Pixel().Depth().Func(); o != v { - t.doAndUndo(ctx, - t.cb.GlDepthFunc(v), - t.cb.GlDepthFunc(o)) - } -} - -func (t *tweaker) glBlendColor(ctx context.Context, r, g, b, a GLfloat) { - if o := t.c.Pixel().BlendColor(); !o.EqualTo(r, g, b, a) { - t.doAndUndo(ctx, - t.cb.GlBlendColor(r, g, b, a), - t.cb.GlBlendColor(o.Red(), o.Green(), o.Blue(), o.Alpha())) - } -} - -func (t *tweaker) glBlendFunc(ctx context.Context, src, dst GLenum) { - t.glBlendFuncSeparate(ctx, src, dst, src, dst) -} - -func (t *tweaker) glBlendFuncSeparate(ctx context.Context, srcRGB, dstRGB, srcA, dstA GLenum) { - // TODO: This does not correctly handle indexed state. - o := t.c.Pixel().Blend().Get(0) - n := o - n.SetSrcRgb(srcRGB) - n.SetDstRgb(dstRGB) - n.SetSrcAlpha(srcA) - n.SetDstAlpha(dstA) - if o != n { - t.doAndUndo(ctx, - t.cb.GlBlendFuncSeparate(srcRGB, dstRGB, srcA, dstA), - t.cb.GlBlendFuncSeparate(o.SrcRgb(), o.DstRgb(), o.SrcAlpha(), o.DstAlpha())) - } -} - -// glPolygonOffset adjusts the offset depth factor and units. Unlike the original glPolygonOffset, -// this function adds the given values to the current values rather than setting them. -func (t *tweaker) glPolygonOffset(ctx context.Context, factor, units GLfloat) { - origFactor, origUnits := t.c.Rasterization().PolygonOffsetFactor(), t.c.Rasterization().PolygonOffsetUnits() - t.doAndUndo(ctx, - t.cb.GlPolygonOffset(origFactor+factor, origUnits+units), - t.cb.GlPolygonOffset(origFactor, origUnits)) -} - -func (t *tweaker) glLineWidth(ctx context.Context, width GLfloat) { - if o := t.c.Rasterization().LineWidth(); o != width { - t.doAndUndo(ctx, - t.cb.GlLineWidth(width), - t.cb.GlLineWidth(o)) - } -} - -// This will either bind new VAO (GLES 3.x) or save state of the default one (GLES 2.0). -func (t *tweaker) makeVertexArray(ctx context.Context, enabledLocations ...AttributeLocation) { - if t.c.Constants().MajorVersion() >= 3 { - // GLES 3.0 and 3.1 introduce a lot of new state which would be hard to restore. - // It is much easier to just create a fresh Vertex Array Object to work with. - vertexArrayID := t.glGenVertexArray(ctx) - t.glBindVertexArray(ctx, vertexArrayID) - for _, location := range enabledLocations { - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlEnableVertexAttribArray(location)) - } - } else { - // GLES 2.0 does not have Vertex Array Objects, but the state is fairly simple. - vao := t.c.Bound().VertexArray() - // Disable all vertex attribute arrays - for _, location := range vao.VertexAttributeArrays().Keys() { - if vao.VertexAttributeArrays().Get(location).Enabled() == GLboolean_GL_TRUE { - t.doAndUndo(ctx, - t.cb.GlDisableVertexAttribArray(location), - t.cb.GlEnableVertexAttribArray(location)) - } - } - // Enable and save state for the attribute arrays that we will use - origArrayBufferID := t.c.Bound().ArrayBuffer().GetID() - for _, location := range enabledLocations { - location := location - t.doAndUndo(ctx, - t.cb.GlEnableVertexAttribArray(location), - t.cb.GlDisableVertexAttribArray(location)) - - vaa := vao.VertexAttributeArrays().Get(location) - size, ty, norm, stride, ptr := vaa.Size(), vaa.Type(), vaa.Normalized(), vaa.Stride(), vaa.Pointer() - bufID := vao.VertexBufferBindings().Get(VertexBufferBindingIndex(location)).Buffer().GetID() - t.undo = append(t.undo, func(ctx context.Context) { - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, bufID)) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlVertexAttribPointer(location, size, ty, norm, stride, memory.Pointer(ptr))) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, origArrayBufferID)) - }) - } - } -} - -func (t *tweaker) glGenBuffer(ctx context.Context) BufferId { - id := BufferId(newUnusedID(ctx, 'B', func(x uint32) bool { return !t.c.Objects().Buffers().Get(BufferId(x)).IsNil() })) - tmp := t.AllocData(ctx, id) - t.doAndUndo(ctx, - t.cb.GlGenBuffers(1, tmp.Ptr()).AddWrite(tmp.Data()), - t.cb.GlDeleteBuffers(1, tmp.Ptr()).AddRead(tmp.Data())) - return id -} - -func (t *tweaker) glGenRenderbuffer(ctx context.Context) RenderbufferId { - id := RenderbufferId(newUnusedID(ctx, 'R', func(x uint32) bool { return !t.c.Objects().Renderbuffers().Get(RenderbufferId(x)).IsNil() })) - tmp := t.AllocData(ctx, id) - t.doAndUndo(ctx, - t.cb.GlGenRenderbuffers(1, tmp.Ptr()).AddWrite(tmp.Data()), - t.cb.GlDeleteRenderbuffers(1, tmp.Ptr()).AddRead(tmp.Data())) - return id -} - -func (t *tweaker) glGenFramebuffer(ctx context.Context) FramebufferId { - id := FramebufferId(newUnusedID(ctx, 'F', func(x uint32) bool { return !t.c.Objects().Framebuffers().Get(FramebufferId(x)).IsNil() })) - tmp := t.AllocData(ctx, id) - t.doAndUndo(ctx, - t.cb.GlGenFramebuffers(1, tmp.Ptr()).AddWrite(tmp.Data()), - t.cb.GlDeleteFramebuffers(1, tmp.Ptr()).AddRead(tmp.Data())) - return id -} - -func (t *tweaker) glGenTexture(ctx context.Context) TextureId { - id := TextureId(newUnusedID(ctx, 'T', func(x uint32) bool { return !t.c.Objects().Textures().Get(TextureId(x)).IsNil() })) - tmp := t.AllocData(ctx, id) - t.doAndUndo(ctx, - t.cb.GlGenTextures(1, tmp.Ptr()).AddWrite(tmp.Data()), - t.cb.GlDeleteTextures(1, tmp.Ptr()).AddRead(tmp.Data())) - return id -} - -func (t *tweaker) glGenVertexArray(ctx context.Context) VertexArrayId { - id := VertexArrayId(newUnusedID(ctx, 'V', func(x uint32) bool { return !t.c.Objects().VertexArrays().Get(VertexArrayId(x)).IsNil() })) - tmp := t.AllocData(ctx, id) - t.doAndUndo(ctx, - t.cb.GlGenVertexArrays(1, tmp.Ptr()).AddWrite(tmp.Data()), - t.cb.GlDeleteVertexArrays(1, tmp.Ptr()).AddRead(tmp.Data())) - return id -} - -func (t *tweaker) glCreateProgram(ctx context.Context) ProgramId { - id := ProgramId(newUnusedID(ctx, 'P', func(x uint32) bool { - return !t.c.Objects().Programs().Get(ProgramId(x)).IsNil() || !t.c.Objects().Shaders().Get(ShaderId(x)).IsNil() - })) - t.doAndUndo(ctx, - t.cb.GlCreateProgram(id), - t.cb.GlDeleteProgram(id)) - return id -} - -func (t *tweaker) makeProgram(ctx context.Context, vertexShaderSource, fragmentShaderSource string) ProgramId { - programID := t.glCreateProgram(ctx) - vertexShaderID := t.glCreateShader(ctx, GLenum_GL_VERTEX_SHADER) - t.glShaderSource(ctx, vertexShaderID, vertexShaderSource) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlCompileShader(vertexShaderID)) - fragmentShaderID := t.glCreateShader(ctx, GLenum_GL_FRAGMENT_SHADER) - t.glShaderSource(ctx, fragmentShaderID, fragmentShaderSource) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlCompileShader(fragmentShaderID)) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlAttachShader(programID, vertexShaderID)) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlAttachShader(programID, fragmentShaderID)) - return programID -} - -func (t *tweaker) glCreateShader(ctx context.Context, shaderType GLenum) ShaderId { - id := ShaderId(newUnusedID(ctx, 'S', func(x uint32) bool { - return !t.c.Objects().Programs().Get(ProgramId(x)).IsNil() || !t.c.Objects().Shaders().Get(ShaderId(x)).IsNil() - })) - // We need to mutate the state, as otherwise two consecutive calls can return the same ShaderId. - t.doAndUndo(ctx, - t.cb.GlCreateShader(shaderType, id), - t.cb.GlDeleteShader(id)) - return id -} - -func (t *tweaker) glShaderSource(ctx context.Context, shaderID ShaderId, shaderSource string) { - tmpSrc := t.AllocData(ctx, shaderSource) - tmpSrcLen := t.AllocData(ctx, GLint(len(shaderSource))) - tmpPtrToSrc := t.AllocData(ctx, tmpSrc.Ptr()) - t.out.MutateAndWrite(ctx, t.dID, t.cb.GlShaderSource(shaderID, 1, tmpPtrToSrc.Ptr(), tmpSrcLen.Ptr()). - AddRead(tmpPtrToSrc.Data()). - AddRead(tmpSrcLen.Data()). - AddRead(tmpSrc.Data())) - return -} - -func (t *tweaker) glScissor(ctx context.Context, x, y GLint, w, h GLsizei) { - if o := t.c.Pixel().Scissor().Box(); !o.EqualTo(x, y, w, h) { - t.doAndUndo(ctx, - t.cb.GlScissor(x, y, w, h), - t.cb.GlScissor(o.X(), o.Y(), o.Width(), o.Height())) - } -} - -func (t *tweaker) GlBindBuffer_ArrayBuffer(ctx context.Context, id BufferId) { - if o := t.c.Bound().ArrayBuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, id), - t.cb.GlBindBuffer(GLenum_GL_ARRAY_BUFFER, o)) - } -} - -func (t *tweaker) GlBindBuffer_ElementArrayBuffer(ctx context.Context, id BufferId) { - vao := t.c.Bound().VertexArray() - if o := vao.ElementArrayBuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindBuffer(GLenum_GL_ELEMENT_ARRAY_BUFFER, id), - t.cb.GlBindBuffer(GLenum_GL_ELEMENT_ARRAY_BUFFER, o)) - } -} - -func (t *tweaker) GlBindBuffer_PixelUnpackBuffer(ctx context.Context, id BufferId) { - if o := t.c.Bound().PixelUnpackBuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, id), - t.cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, o)) - } -} - -func (t *tweaker) glBindFramebuffer_Draw(ctx context.Context, id FramebufferId) { - if o := t.c.Bound().DrawFramebuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, id), - t.cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, o)) - } -} - -func (t *tweaker) glBindFramebuffer_Read(ctx context.Context, id FramebufferId) { - if o := t.c.Bound().ReadFramebuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, id), - t.cb.GlBindFramebuffer(GLenum_GL_READ_FRAMEBUFFER, o)) - } -} - -// glBindFramebuffer_ReadToBoth binds the currently bound READ_FRAMEBUFFER to GL_FRAMEBUFFER. -func (t *tweaker) glBindFramebuffer_ReadToBoth(ctx context.Context) { - d, r := t.c.Bound().DrawFramebuffer().GetID(), t.c.Bound().ReadFramebuffer().GetID() - t.doAndUndo(ctx, - t.cb.GlBindFramebuffer(GLenum_GL_FRAMEBUFFER, r), - t.cb.GlBindFramebuffer(GLenum_GL_DRAW_FRAMEBUFFER, d)) -} - -func (t *tweaker) glReadBuffer(ctx context.Context, id GLenum) { - fb := t.c.Bound().ReadFramebuffer() - if o := fb.ReadBuffer(); o != id { - t.doAndUndo(ctx, - t.cb.GlReadBuffer(id), - t.cb.GlReadBuffer(o)) - } -} - -func (t *tweaker) glBindRenderbuffer(ctx context.Context, id RenderbufferId) { - if o := t.c.Bound().Renderbuffer().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindRenderbuffer(GLenum_GL_RENDERBUFFER, id), - t.cb.GlBindRenderbuffer(GLenum_GL_RENDERBUFFER, o)) - } -} - -func (t *tweaker) glBindTexture(ctx context.Context, tex *Texture) { - var old TextureId - switch tex.Kind() { - case GLenum_GL_TEXTURE_2D: - old = t.c.Bound().TextureUnit().Binding2d().GetID() - case GLenum_GL_TEXTURE_3D: - old = t.c.Bound().TextureUnit().Binding3d().GetID() - case GLenum_GL_TEXTURE_2D_ARRAY: - old = t.c.Bound().TextureUnit().Binding2dArray().GetID() - case GLenum_GL_TEXTURE_CUBE_MAP: - old = t.c.Bound().TextureUnit().BindingCubeMap().GetID() - case GLenum_GL_TEXTURE_CUBE_MAP_ARRAY: - old = t.c.Bound().TextureUnit().BindingCubeMapArray().GetID() - case GLenum_GL_TEXTURE_2D_MULTISAMPLE: - old = t.c.Bound().TextureUnit().Binding2dMultisample().GetID() - case GLenum_GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - old = t.c.Bound().TextureUnit().Binding2dMultisampleArray().GetID() - case GLenum_GL_TEXTURE_EXTERNAL_OES: - old = t.c.Bound().TextureUnit().BindingExternalOes().GetID() - default: - panic(fmt.Errorf("%v is not a texture kind", tex.Kind())) - } - - if old != tex.ID() { - t.doAndUndo(ctx, - t.cb.GlBindTexture(tex.Kind(), tex.ID()), - t.cb.GlBindTexture(tex.Kind(), old)) - } -} - -func (t *tweaker) glBindTexture_2D(ctx context.Context, id TextureId) { - if o := t.c.Bound().TextureUnit().Binding2d().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindTexture(GLenum_GL_TEXTURE_2D, id), - t.cb.GlBindTexture(GLenum_GL_TEXTURE_2D, o)) - } -} - -func (t *tweaker) glBindTexture_2DArray(ctx context.Context, id TextureId) { - if o := t.c.Bound().TextureUnit().Binding2dArray().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindTexture(GLenum_GL_TEXTURE_2D_ARRAY, id), - t.cb.GlBindTexture(GLenum_GL_TEXTURE_2D_ARRAY, o)) - } -} - -func (t *tweaker) glBindVertexArray(ctx context.Context, id VertexArrayId) { - if o := t.c.Bound().VertexArray().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlBindVertexArray(id), - t.cb.GlBindVertexArray(o)) - } -} - -func (t *tweaker) glUseProgram(ctx context.Context, id ProgramId) { - if o := t.c.Bound().Program().GetID(); o != id { - t.doAndUndo(ctx, - t.cb.GlUseProgram(id), - t.cb.GlUseProgram(o)) - } -} - -func (t *tweaker) glActiveTexture(ctx context.Context, unit GLenum) { - if o := GLenum(t.c.Bound().TextureUnit().ID()) + GLenum_GL_TEXTURE0; o != unit { - t.doAndUndo(ctx, - t.cb.GlActiveTexture(unit), - t.cb.GlActiveTexture(o)) - } -} - -func (t *tweaker) setPackStorage(ctx context.Context, state PixelStorageState, bufferId BufferId) { - origState := map[GLenum]GLint{} - forEachPackStorageState(t.c.Other().Pack(), func(n GLenum, v GLint) { origState[n] = v }) - forEachPackStorageState(state, func(name GLenum, value GLint) { - if o := origState[name]; o != value { - t.doAndUndo(ctx, - t.cb.GlPixelStorei(name, value), - t.cb.GlPixelStorei(name, o)) - } - }) - if o := t.c.Bound().PixelPackBuffer().GetID(); o != bufferId { - t.doAndUndo(ctx, - t.cb.GlBindBuffer(GLenum_GL_PIXEL_PACK_BUFFER, bufferId), - t.cb.GlBindBuffer(GLenum_GL_PIXEL_PACK_BUFFER, o)) - } -} - -func forEachPackStorageState(state PixelStorageState, action func(n GLenum, v GLint)) { - action(GLenum_GL_PACK_ALIGNMENT, state.Alignment()) - action(GLenum_GL_PACK_IMAGE_HEIGHT, state.ImageHeight()) - action(GLenum_GL_PACK_ROW_LENGTH, state.RowLength()) - action(GLenum_GL_PACK_SKIP_IMAGES, state.SkipImages()) - action(GLenum_GL_PACK_SKIP_PIXELS, state.SkipPixels()) - action(GLenum_GL_PACK_SKIP_ROWS, state.SkipRows()) -} - -func (t *tweaker) setUnpackStorage(ctx context.Context, state PixelStorageState, bufferId BufferId) { - origState := map[GLenum]GLint{} - forEachUnpackStorageState(t.c.Other().Unpack(), func(n GLenum, v GLint) { origState[n] = v }) - forEachUnpackStorageState(state, func(name GLenum, value GLint) { - if o := origState[name]; o != value { - t.doAndUndo(ctx, - t.cb.GlPixelStorei(name, value), - t.cb.GlPixelStorei(name, o)) - } - }) - if o := t.c.Bound().PixelUnpackBuffer().GetID(); o != bufferId { - t.doAndUndo(ctx, - t.cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, bufferId), - t.cb.GlBindBuffer(GLenum_GL_PIXEL_UNPACK_BUFFER, o)) - } -} - -func forEachUnpackStorageState(state PixelStorageState, action func(n GLenum, v GLint)) { - action(GLenum_GL_UNPACK_ALIGNMENT, state.Alignment()) - action(GLenum_GL_UNPACK_IMAGE_HEIGHT, state.ImageHeight()) - action(GLenum_GL_UNPACK_ROW_LENGTH, state.RowLength()) - action(GLenum_GL_UNPACK_SKIP_IMAGES, state.SkipImages()) - action(GLenum_GL_UNPACK_SKIP_PIXELS, state.SkipPixels()) - action(GLenum_GL_UNPACK_SKIP_ROWS, state.SkipRows()) -} diff --git a/gapis/api/gles/types.api b/gapis/api/gles/types.api deleted file mode 100644 index 09ca6a4fab..0000000000 --- a/gapis/api/gles/types.api +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// OpenGL ES 3.1 data-types. See: -// https://www.khronos.org/registry/gles/specs/3.1/es_spec_3.1.pdf - -enum GLboolean : u8 { // Boolean value. - GL_FALSE = 0x00 - GL_TRUE = 0x01 -} - -sub GLboolean toGLboolean(bool v) { - return switch v { - case true: GL_TRUE - case false: GL_FALSE - } -} - -// type s8 GLbyte // 8 bit, signed, two's complement binary integer. (Currently unused) -type u8 GLubyte // 8 bit, unsigned binary integer. -type char GLchar // 8 bit character used for strings. -type s16 GLshort // 16 bit, signed, two's complement binary integer. -// type u16 GLushort // 16 bit, unsigned binary integer. (Currently unused) -type s32 GLint // 32 bit, signed, two's complement binary integer. -type u32 GLuint // 32 bit, unsigned binary integer. -type s64 GLint64 // 64 bit, signed, two's complement binary integer. -type s64 GLint64EXT // 64 bit, signed, two's complement binary integer. -type u64 GLuint64 // 64 bit, unsigned binary integer. -type u64 GLuint64EXT // 64 bit, unsigned binary integer. -type s32 GLfixed // 16.16 bits, signed, two's complement fixed-point integer. -type s32 GLsizei // 32 bit, signed binary integer used to represent sizes. -type s32 GLintptr // TODO: No API datatype to represent this type. -type s32 GLsizeiptr // TODO: No API datatype to represent this type. -type void* GLDEBUGPROC // void (*)(GLenum,GLenum,GLuint,GLenum,GLsizei,const GLchar*,const void*) -// type u16 GLhalf // 16 bit floating-point number encoded as a unsigned 16 bit integer. (Currently unused) -type f32 GLfloat // 32 bit floating-point number. -type f32 GLclampf // 32 bit floating-point value clamped to [0, 1] -type void GLvoid // Void type. -type s32 GLclampx // GLES 1.0 fixed point - -@replay_custom_value -@replay_remap -type void* GLsync // Sync object handle. diff --git a/gapis/api/gles/undefined_framebuffer.go b/gapis/api/gles/undefined_framebuffer.go deleted file mode 100644 index 031ea2d54c..0000000000 --- a/gapis/api/gles/undefined_framebuffer.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/memory" -) - -// undefinedFramebuffer adds a transform that will render a pattern into the -// color buffer at the end of each frame. -func undefinedFramebuffer(ctx context.Context, device *device.Instance) transform.Transformer { - seenSurfaces := make(map[EGLSurface]bool) - return transform.Transform("DirtyFramebuffer", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - out.MutateAndWrite(ctx, id, cmd) - s := out.State() - c := GetContext(s, cmd.Thread()) - if c.IsNil() || !c.Other().Initialized() || c.Constants().MajorVersion() < 2 { - return nil // We can't do anything without a context or GLES 1. - } - if eglMakeCurrent, ok := cmd.(*EglMakeCurrent); ok && !seenSurfaces[eglMakeCurrent.Draw()] { - // Render the undefined pattern for new contexts. - drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out) - seenSurfaces[eglMakeCurrent.Draw()] = true - } - if cmd.CmdFlags(ctx, id, s).IsStartOfFrame() { - if _, ok := cmd.(*EglSwapBuffersWithDamageKHR); ok { - // TODO: This is a hack. eglSwapBuffersWithDamageKHR is nearly - // exculsively used by the Android framework, which also loves - // to do partial framebuffer updates. Unfortunately we do not - // currently know whether the framebuffer is invalidated between - // calls to eglSwapBuffersWithDamageKHR as the OS now uses the - // EGL_EXT_buffer_age extension, which we do not track. For now, - // assume that eglSwapBuffersWithDamageKHR calls are coming from - // the framework, and that the framebuffer is reused between - // calls. - // BUG: https://github.com/google/gapid/issues/846. - return nil - } - if !c.Other().PreserveBuffersOnSwap() { - drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out) - } - } - return nil - }) -} - -func drawUndefinedFramebuffer(ctx context.Context, id api.CmdID, cmd api.Cmd, device *device.Instance, s *api.GlobalState, c Contextʳ, out transform.Writer) error { - const ( - aScreenCoordsLocation AttributeLocation = 0 - aScreenCoords = "aScreenCoords" - - vertexShaderSource string = ` - #version 100 - - precision highp float; - attribute vec2 aScreenCoords; - varying vec2 uv; - - void main() { - uv = aScreenCoords; - gl_Position = vec4(aScreenCoords.xy, 0., 1.); - }` - fragmentShaderSource string = ` - #version 100 - - precision highp float; - varying vec2 uv; - - float F(float a) { return smoothstep(0.0, 0.1, a) * smoothstep(0.4, 0.3, a); } - - void main() { - vec2 v = uv * 5.0; - gl_FragColor = vec4(0.8, 0.9, 0.6, 1.0) * F(fract(v.x + v.y)); - }` - ) - - // 2D vertices positions for a full screen 2D triangle strip. - positions := []float32{-1., -1., 1., -1., -1., 1., 1., 1.} - - dID := id.Derived() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - t := newTweaker(out, id, cb) - - // Temporarily change rasterizing/blending state and enable VAP 0. - t.glDisable(ctx, GLenum_GL_BLEND) - t.glDisable(ctx, GLenum_GL_CULL_FACE) - t.glDisable(ctx, GLenum_GL_DEPTH_TEST) - t.glDisable(ctx, GLenum_GL_SCISSOR_TEST) - t.glDisable(ctx, GLenum_GL_STENCIL_TEST) - t.makeVertexArray(ctx, aScreenCoordsLocation) - - programID := t.makeProgram(ctx, vertexShaderSource, fragmentShaderSource) - - tmp0 := t.AllocData(ctx, aScreenCoords) - out.MutateAndWrite(ctx, dID, cb.GlBindAttribLocation(programID, aScreenCoordsLocation, tmp0.Ptr()). - AddRead(tmp0.Data())) - tmp0.Free() - - attrib := MakeProgramResourceʳ(s.Arena) - attrib.SetType(GLenum_GL_FLOAT_VEC2) - attrib.SetName(aScreenCoords) - attrib.SetArraySize(1) - attrib.SetLocations(NewU32ːGLintᵐ(s.Arena).Add(0, 0)) - - resources := MakeActiveProgramResourcesʳ(s.Arena) - resources.SetProgramInputs(NewU32ːProgramResourceʳᵐ(s.Arena).Add(0, attrib)) - - extra := MakeLinkProgramExtra(s.Arena) - extra.SetLinkStatus(GLboolean_GL_TRUE) - extra.SetActiveResources(resources) - out.MutateAndWrite(ctx, dID, api.WithExtras(cb.GlLinkProgram(programID), extra)) - t.glUseProgram(ctx, programID) - - bufferID := t.glGenBuffer(ctx) - t.GlBindBuffer_ArrayBuffer(ctx, bufferID) - - tmp1 := t.AllocData(ctx, positions) - out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_ARRAY_BUFFER, GLsizeiptr(4*len(positions)), tmp1.Ptr(), GLenum_GL_STATIC_DRAW). - AddRead(tmp1.Data())) - tmp1.Free() - - out.MutateAndWrite(ctx, dID, cb.GlVertexAttribPointer(aScreenCoordsLocation, 2, GLenum_GL_FLOAT, GLboolean(0), 0, memory.Nullptr)) - out.MutateAndWrite(ctx, dID, cb.GlDrawArrays(GLenum_GL_TRIANGLE_STRIP, 0, 4)) - - t.revert(ctx) - - return nil -} diff --git a/gapis/api/gles/version.go b/gapis/api/gles/version.go deleted file mode 100644 index f1628c34c6..0000000000 --- a/gapis/api/gles/version.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "fmt" - "regexp" - "strconv" -) - -// Version represents the GL version major and minor numbers, -// and whether its flavour is ES, as opposed to Desktop GL. -type Version struct { - IsES bool - Major int - Minor int -} - -// AtLeast returns true if the version is greater or equal to major.minor. -func (v Version) AtLeast(major, minor int) bool { - if v.Major > major { - return true - } - if v.Major < major { - return false - } - return v.Minor >= minor -} - -// AtLeastES returns true if the version is OpenGL ES and is greater or equal to -// major.minor. -func (v Version) AtLeastES(major, minor int) bool { - return v.IsES && v.AtLeast(major, minor) -} - -// AtLeastGL returns true if the version is not OpenGL ES and is greater or -// equal to major.minor. -func (v Version) AtLeastGL(major, minor int) bool { - return !v.IsES && v.AtLeast(major, minor) -} - -// MaxGLSL returns the highest supported GLSL version for the given GL version. -func (v Version) MaxGLSL() Version { - major, minor, isES := v.Major, v.Minor, v.IsES - switch { - case major == 2 && isES: - return Version{Major: 1, Minor: 0} - case major == 3 && isES: - return Version{Major: 3, Minor: 0} - - case major == 2 && minor == 0 && !isES: - return Version{Major: 1, Minor: 1} - case major == 2 && minor == 1 && !isES: - return Version{Major: 1, Minor: 2} - case major == 3 && minor == 0 && !isES: - return Version{Major: 1, Minor: 3} - case major == 3 && minor == 1 && !isES: - return Version{Major: 1, Minor: 4} - case major == 3 && minor == 2 && !isES: - return Version{Major: 1, Minor: 5} - - default: - return Version{Major: major, Minor: minor} - } -} - -// AsInt returns the version in the form Mmm, where M is the major version and -// m is the minor version. -func (v Version) AsInt() int { - return v.Major*100 + v.Minor*10 -} - -var versionRe = regexp.MustCompile(`^(OpenGL ES.*? )?(\d+)\.(\d+).*`) - -// ParseVersion parses the GL version major, minor and flavour from the output of glGetString(GL_VERSION). -func ParseVersion(str string) (*Version, error) { - if match := versionRe.FindStringSubmatch(str); match != nil { - isES := len(match[1]) > 0 // Desktop GL doesn't have a flavour prefix. - major, _ := strconv.Atoi(match[2]) - minor, _ := strconv.Atoi(match[3]) - return &Version{IsES: isES, Major: major, Minor: minor}, nil - } - return nil, fmt.Errorf("Unknown GL_VERSION format: %s", str) -} diff --git a/gapis/api/gles/wireframe.go b/gapis/api/gles/wireframe.go deleted file mode 100644 index 219d309418..0000000000 --- a/gapis/api/gles/wireframe.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gles - -import ( - "bytes" - "context" - "fmt" - - "github.com/google/gapid/core/data/endian" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/database" -) - -// wireframe returns a command transform that replaces all draw calls of -// triangle primitives with draw calls of a wireframe equivalent. -func wireframe(ctx context.Context, framebuffer FramebufferId) transform.Transformer { - ctx = log.Enter(ctx, "Wireframe") - return transform.Transform("Wireframe", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - if dc, ok := cmd.(drawCall); ok { - s := out.State() - c := GetContext(s, cmd.Thread()) - - fb := c.Bound().DrawFramebuffer() - if fb.IsNil() { - return out.MutateAndWrite(ctx, id, cmd) - } - - if fb.ID() != framebuffer { - return out.MutateAndWrite(ctx, id, cmd) - } - - dID := id.Derived() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - - t := newTweaker(out, dID, cb) - defer t.revert(ctx) - - t.glEnable(ctx, GLenum_GL_LINE_SMOOTH) - t.glEnable(ctx, GLenum_GL_BLEND) - t.glBlendFunc(ctx, GLenum_GL_SRC_ALPHA, GLenum_GL_ONE_MINUS_SRC_ALPHA) - if err := drawWireframe(ctx, id, dc, s, out); err != nil { - log.E(ctx, "%v", err) - } - - t.revert(ctx) - } else { - return out.MutateAndWrite(ctx, id, cmd) - } - return nil - }) -} - -// wireframeOverlay returns a command transform that renders the wireframe of -// the mesh over of the specified draw call. -func wireframeOverlay(ctx context.Context, i api.CmdID) transform.Transformer { - ctx = log.Enter(ctx, "DrawMode_WIREFRAME_OVERLAY") - return transform.Transform("DrawMode_WIREFRAME_OVERLAY", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - if i == id { - if dc, ok := cmd.(drawCall); ok { - s := out.State() - out.MutateAndWrite(ctx, id, dc) - - dID := id.Derived() - cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - t := newTweaker(out, dID, cb) - t.glEnable(ctx, GLenum_GL_POLYGON_OFFSET_LINE) - t.glPolygonOffset(ctx, -1, -1) - t.glEnable(ctx, GLenum_GL_BLEND) - t.glBlendColor(ctx, 1.0, 0.5, 1.0, 1.0) - t.glBlendFunc(ctx, GLenum_GL_CONSTANT_COLOR, GLenum_GL_ZERO) - t.glEnable(ctx, GLenum_GL_LINE_SMOOTH) - t.glLineWidth(ctx, 1.5) - - if err := drawWireframe(ctx, i, dc, s, out); err != nil { - log.E(ctx, "%v", err) - } - - t.revert(ctx) - return nil - } - } - - return out.MutateAndWrite(ctx, id, cmd) - }) -} - -func drawWireframe(ctx context.Context, i api.CmdID, dc drawCall, s *api.GlobalState, out transform.Writer) error { - c := GetContext(s, dc.Thread()) - cb := CommandBuilder{Thread: dc.Thread(), Arena: s.Arena} - dID := i.Derived() - - dci, err := dc.getIndices(ctx, c, s) - if err != nil { - return err - } - indices, drawMode, err := makeWireframe(dci.indices, dci.drawMode) - if err != nil { - return err - } - - // Store the wire-frame data to a temporary address. - wireframeData, wireframeDataType := encodeIndices(indices) - resID, err := database.Store(ctx, wireframeData) - if err != nil { - return err - } - - // Unbind the index buffer - tmp := s.AllocOrPanic(ctx, uint64(len(wireframeData))) - oldIndexBuffer := c.Bound().VertexArray().ElementArrayBuffer() - out.MutateAndWrite(ctx, dID, - cb.GlBindBuffer(GLenum_GL_ELEMENT_ARRAY_BUFFER, 0). - AddRead(tmp.Range(), resID)) - - // Draw the wire-frame - out.MutateAndWrite(ctx, i, cb.GlDrawElements( - drawMode, GLsizei(len(indices)), wireframeDataType, tmp.Ptr())) - - // Rebind the old index buffer - out.MutateAndWrite(ctx, dID, cb.GlBindBuffer( - GLenum_GL_ELEMENT_ARRAY_BUFFER, oldIndexBuffer.GetID())) - - return nil -} - -// encodeIndices assumes little endian encoding -func encodeIndices(indices []uint32) ([]byte, GLenum) { - maxIndex := uint32(0) - for _, v := range indices { - if v > maxIndex { - maxIndex = v - } - } - buf := &bytes.Buffer{} - w := endian.Writer(buf, device.LittleEndian) - switch { - case maxIndex > 0xFFFF: - // TODO: GL_UNSIGNED_INT in glDrawElements is supported only since GLES 3.0 - for _, v := range indices { - w.Uint32(v) - } - return buf.Bytes(), GLenum_GL_UNSIGNED_INT - - case maxIndex > 0xFF: - for _, v := range indices { - w.Uint16(uint16(v)) - } - return buf.Bytes(), GLenum_GL_UNSIGNED_SHORT - - default: - for _, v := range indices { - w.Uint8(uint8(v)) - } - return buf.Bytes(), GLenum_GL_UNSIGNED_BYTE - } -} - -func appendWireframeOfTriangle(lines []uint32, v0, v1, v2 uint32) []uint32 { - if v0 == v1 || v1 == v2 || v2 == v0 { - return lines // Ignore degenerate triangle - } - return append(lines, v0, v1, v1, v2, v2, v0) -} - -func makeWireframe(indices []uint32, drawMode GLenum) ([]uint32, GLenum, error) { - switch drawMode { - case GLenum_GL_POINTS, GLenum_GL_LINES, GLenum_GL_LINE_STRIP, GLenum_GL_LINE_LOOP: - return indices, drawMode, nil - - case GLenum_GL_TRIANGLES: - numTriangles := len(indices) / 3 - lines := make([]uint32, 0, numTriangles*6) - for i := 0; i < numTriangles; i++ { - lines = appendWireframeOfTriangle(lines, indices[i*3], indices[i*3+1], indices[i*3+2]) - } - return lines, GLenum_GL_LINES, nil - - case GLenum_GL_TRIANGLE_STRIP: - numTriangles := len(indices) - 2 - if numTriangles > 0 { - lines := make([]uint32, 0, numTriangles*6) - for i := 0; i < numTriangles; i++ { - lines = appendWireframeOfTriangle(lines, indices[i], indices[i+1], indices[i+2]) - } - return lines, GLenum_GL_LINES, nil - } - return []uint32{}, GLenum_GL_LINES, nil - - case GLenum_GL_TRIANGLE_FAN: - numTriangles := len(indices) - 2 - if numTriangles > 0 { - lines := make([]uint32, 0, numTriangles*6) - for i := 0; i < numTriangles; i++ { - lines = appendWireframeOfTriangle(lines, indices[0], indices[i+1], indices[i+2]) - } - return lines, GLenum_GL_LINES, nil - } - return []uint32{}, GLenum_GL_LINES, nil - - default: - return nil, 0, fmt.Errorf("Unknown mode: %v", drawMode) - } -} diff --git a/gapis/api/gvr/BUILD.bazel b/gapis/api/gvr/BUILD.bazel deleted file mode 100644 index 4a1550089c..0000000000 --- a/gapis/api/gvr/BUILD.bazel +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("//tools/build:rules.bzl", "api_library", "apic_template") - -filegroup( - name = "api_files", - srcs = glob([ - "*.api", - ]), - visibility = ["//visibility:public"], -) - -api_library( - name = "api", - api = "gvr.api", - apiname = "gvr", - includes = [":api_files"], - visibility = ["//visibility:public"], - deps = ["//gapis/messages:api"], -) - -proto_library( - name = "gvr_proto", - srcs = ["resolvables.proto"], - visibility = ["//visibility:public"], - deps = ["//gapis/service/path:path_proto"], -) - -go_proto_library( - name = "gvr_go_proto", - importpath = "github.com/google/gapid/gapis/api/gvr", - proto = ":gvr_proto", - visibility = ["//visibility:public"], - deps = ["//gapis/service/path:go_default_library"], -) - -apic_template( - name = "generated", - api = ":api", - templates = [ - "//gapis/api/templates:api", - "//gapis/api/templates:api_types", - "//gapis/api/templates:mutate", - "//gapis/api/templates:constant_sets", - "//gapis/api/templates:convert", - "//gapis/api/templates:proto", - ], - visibility = ["//visibility:public"], -) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "extension.go", - "framebindings.go", - "gvr.go", - "importance.go", - ], - embed = [ - ":generated", # keep - ":gvr_go_proto", - ], - importpath = "github.com/google/gapid/gapis/api/gvr", - visibility = ["//visibility:public"], - deps = [ - "//core/data/dictionary:go_default_library", # keep - "//core/data/protoconv:go_default_library", # keep - "//core/event/task:go_default_library", # keep - "//core/image:go_default_library", - "//core/math/interval:go_default_library", - "//core/memory/arena:go_default_library", # keep - "//gapil/constset:go_default_library", # keep - "//gapis/api:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/api/gvr/gvr_pb:go_default_library", # keep - "//gapis/api/sync:go_default_library", - "//gapis/api/transform:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/database:go_default_library", - "//gapis/extensions:go_default_library", - "//gapis/memory/memory_pb:go_default_library", #keep - "//gapis/messages:go_default_library", # keep - "//gapis/replay:go_default_library", - "//gapis/resolve:go_default_library", - "//gapis/resolve/cmdgrouper:go_default_library", - "//gapis/service:go_default_library", - "//gapis/service/memory_box:go_default_library", #keep - "//gapis/service/path:go_default_library", - "//gapis/service/types:go_default_library", #keep - "//gapis/stringtable:go_default_library", # keep - ], -) diff --git a/gapis/api/gvr/doc.go b/gapis/api/gvr/doc.go deleted file mode 100644 index 3a5f6db86b..0000000000 --- a/gapis/api/gvr/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package gvr implementes the API interface for the Google VR library. -package gvr diff --git a/gapis/api/gvr/extension.go b/gapis/api/gvr/extension.go deleted file mode 100644 index 459aea5351..0000000000 --- a/gapis/api/gvr/extension.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gvr - -import ( - "context" - "reflect" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/extensions" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/resolve/cmdgrouper" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" -) - -func init() { - extensions.Register(extensions.Extension{ - Name: "GVR", - AdjustContexts: adjustContexts, - CmdGroupers: newReprojectionGroupers, - Events: newReprojectionEvents, - EventFilter: eventFilter, - }) -} - -type contextUsage int - -const ( - rendererCtx = contextUsage(iota) - reprojectionCtx -) - -func adjustContexts(ctx context.Context, ctxs []*api.ContextInfo) { - // Look for the renderer context. - tyGvrFrameSubmit := reflect.TypeOf(&Gvr_frame_submit{}) - tyGlFlush := reflect.TypeOf(&gles.GlFlush{}) - - renderer := findContextByCommand(ctxs, tyGvrFrameSubmit) - reprojection := findContextByCommand(ctxs, tyGlFlush) - - if renderer != nil { - renderer.UserData[rendererCtx] = true - if reprojection != nil && renderer != reprojection { - renderer.Name = "Main context (" + renderer.Name + ")" - reprojection.Name = "Reprojection context (" + reprojection.Name + ")" - reprojection.UserData[reprojectionCtx] = true - } - } -} - -func findContextByCommand(ctxs []*api.ContextInfo, ty reflect.Type) *api.ContextInfo { - highest, best := 0, (*api.ContextInfo)(nil) - for _, c := range ctxs { - if count := c.NumCommandsByType[ty]; count > highest { - highest, best = count, c - } - } - return best -} - -func isReprojectionContext(ctx context.Context, p *path.Context, r *path.ResolveConfig) bool { - if p == nil { - return false - } - c, err := resolve.Context(ctx, p, r) - if c == nil || err != nil { - return false - } - _, ok := c.UserData[reprojectionCtx] - return ok -} - -func getRenderContextID(ctx context.Context, p *path.Contexts, r *path.ResolveConfig) *api.ContextID { - if p == nil { - return nil - } - ctxs, err := resolve.Contexts(ctx, p, r) - if err != nil { - return nil - } - for _, c := range ctxs { - if _, ok := c.UserData[rendererCtx]; ok { - return &c.ID - } - } - return nil -} - -func newReprojectionGroupers(ctx context.Context, p *path.CommandTree, r *path.ResolveConfig) []cmdgrouper.Grouper { - if !isReprojectionContext(ctx, p.Capture.Context(p.GetFilter().GetContext().ID()), r) { - return nil - } - glFenceSync := func(cond gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlFenceSync) - return ok && c.Condition() == cond - } - } - glEndTilingQCOM := func(cond gles.GLbitfield) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlEndTilingQCOM) - return ok && c.PreserveMask() == cond - } - } - eglDestroySyncKHR := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.EglDestroySyncKHR) - return ok - } - } - glClientWaitSync := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlClientWaitSync) - return ok - } - } - glDeleteSync := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlDeleteSync) - return ok - } - } - glDrawElements := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlDrawElements) - return ok - } - } - notGlDrawElements := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlDrawElements) - return !ok - } - } - notGlFlush := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlFlush) - return !ok - } - } - return []cmdgrouper.Grouper{ - noSubFrameEventGrouper{cmdgrouper.Sequence("Left eye", - cmdgrouper.Rule{Pred: eglDestroySyncKHR()}, - cmdgrouper.Rule{Pred: glClientWaitSync()}, - cmdgrouper.Rule{Pred: glDeleteSync()}, - cmdgrouper.Rule{Pred: notGlDrawElements(), Repeats: true}, - cmdgrouper.Rule{Pred: glDrawElements()}, - )}, - noSubFrameEventGrouper{cmdgrouper.Sequence("Right eye", - cmdgrouper.Rule{Pred: glFenceSync(gles.GLenum_GL_SYNC_GPU_COMMANDS_COMPLETE)}, - cmdgrouper.Rule{Pred: glEndTilingQCOM(1), Optional: true}, - cmdgrouper.Rule{Pred: glClientWaitSync()}, - cmdgrouper.Rule{Pred: glDeleteSync()}, - cmdgrouper.Rule{Pred: notGlDrawElements(), Repeats: true}, - cmdgrouper.Rule{Pred: glDrawElements()}, - cmdgrouper.Rule{Pred: notGlFlush(), Repeats: true}, - )}, - } -} - -type noSubFrameEventGrouper struct { - cmdgrouper.Grouper -} - -func (n noSubFrameEventGrouper) Build(end api.CmdID) []cmdgrouper.Group { - out := n.Grouper.Build(end) - for i := range out { - out[i].UserData = &resolve.CmdGroupData{ - Representation: api.CmdNoID, - NoFrameEventGroups: true, - } - } - return out -} - -func newReprojectionEvents(ctx context.Context, p *path.Events, r *path.ResolveConfig) extensions.EventProvider { - if !isReprojectionContext(ctx, p.Capture.Context(p.GetFilter().GetContext().ID()), r) { - return nil - } - - var pending []service.EventKind - return func(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState) []*service.Event { - events := []*service.Event{} - for _, kind := range pending { - events = append(events, &service.Event{ - Kind: kind, - Command: p.Capture.Command(uint64(id)), - }) - } - pending = nil - if _, ok := cmd.(*gles.GlFlush); ok { - if p.LastInFrame { - events = append(events, &service.Event{ - Kind: service.EventKind_LastInFrame, - Command: p.Capture.Command(uint64(id)), - }) - } - if p.FirstInFrame { - pending = append(pending, service.EventKind_FirstInFrame) - } - } - return events - } -} - -func eventFilter(ctx context.Context, p *path.Events, r *path.ResolveConfig) extensions.EventFilter { - renderCtxID := getRenderContextID(ctx, p.Capture.Contexts(), r) - if renderCtxID == nil { - return nil - } - return func(id api.CmdID, cmd api.Cmd, s *api.GlobalState) bool { - _, isSwapBuffers := cmd.(*gles.EglSwapBuffers) - if isSwapBuffers { - if context := gles.GetContext(s, cmd.Thread()); !context.IsNil() { - ctxID := context.ID() - if ctxID == *renderCtxID { - // Strip out eglSwapBuffers from the render context. - // We don't want them appearing as frames. - return false - } - } - } - return true - } -} diff --git a/gapis/api/gvr/framebindings.go b/gapis/api/gvr/framebindings.go deleted file mode 100644 index d274bf3978..0000000000 --- a/gapis/api/gvr/framebindings.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gvr - -import ( - "context" - "fmt" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service/path" -) - -func getFramebuffer(ctx context.Context, id api.CmdID) (gles.FramebufferId, error) { - c := capture.Get(ctx) - cmds, err := resolve.Cmds(ctx, c) - if err != nil { - return 0, err - } - switch cmds[id].(type) { - case *Gvr_frame_submit: - bindings, err := getFrameBindings(ctx, c) - if err != nil { - return 0, err - } - return bindings.submitBuffer[id], nil - } - return 0, nil -} - -type frameBindings struct { - submitBuffer map[api.CmdID]gles.FramebufferId -} - -func getFrameBindings(ctx context.Context, c *path.Capture) (*frameBindings, error) { - obj, err := database.Build(ctx, &FrameBindingsResolvable{Capture: c}) - if err != nil { - return nil, err - } - return obj.(*frameBindings), nil -} - -// Resolve implements the database.Resolver interface. -func (r *FrameBindingsResolvable) Resolve(ctx context.Context) (interface{}, error) { - ctx = capture.Put(ctx, r.Capture) - - cmds, err := resolve.Cmds(ctx, r.Capture) - if err != nil { - return nil, err - } - - s, err := capture.NewState(ctx) - if err != nil { - return nil, err - } - - out := &frameBindings{ - submitBuffer: map[api.CmdID]gles.FramebufferId{}, - } - frameToBuffer := map[GvrFrameᵖ]gles.FramebufferId{} - - err = api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - switch cmd := cmd.(type) { - case *Gvr_frame_submit: - // Annoyingly gvr_frame_submit takes a pointer to the frame pointer, - // just so it can be nullified before returning. To avoid another - // state mutation just to get the pointer, cache them here. - cmd.extras.Observations().ApplyReads(s.Memory.ApplicationPool()) - frame, err := cmd.Frame().Read(ctx, cmd, s, nil) - if err != nil { - return err - } - out.submitBuffer[id] = frameToBuffer[frame] - case *Gvr_frame_get_framebuffer_object: - frameToBuffer[GvrFrameᵖ(cmd.Frame())] = gles.FramebufferId(cmd.Result()) - case *gles.GlBindFramebuffer: - if callerID := cmd.Caller(); callerID != api.CmdNoID { - switch caller := cmds[callerID].(type) { - case *Gvr_frame_bind_buffer: - if caller.Index() == 0 { // Only consider the 0'th frame index. - frameToBuffer[caller.Frame()] = cmd.Framebuffer() - } - } - } - } - if err := cmd.Mutate(ctx, id, s, nil, nil); err != nil { - return fmt.Errorf("Fail to mutate cmd %v: %v", cmd, err) - } - return nil - }) - - if err != nil { - return nil, err - } - - return out, nil -} diff --git a/gapis/api/gvr/gvr.api b/gapis/api/gvr/gvr.api deleted file mode 100644 index d0e4c74641..0000000000 --- a/gapis/api/gvr/gvr.api +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -api_index 3 - -import "types.api" - -@no_replay -cmd gvr_version gvr_get_version() { - return ? -} - -@no_replay -cmd const char* gvr_get_version_string() { - return ? -} - -@no_replay -cmd s32 gvr_get_error(gvr_context* gvr) { - return ? -} - -@no_replay -cmd s32 gvr_clear_error(gvr_context* gvr) { - return ? -} - -@no_replay -cmd const char* gvr_get_error_string(s32 error_code) { - return ? -} - -@no_replay -cmd const gvr_user_prefs* gvr_get_user_prefs(gvr_context* gvr) { - return ? -} - -@no_replay -cmd s32 gvr_user_prefs_get_controller_handedness(const gvr_user_prefs* user_prefs) { - return ? -} - -@no_replay -cmd void gvr_destroy(gvr_context** gvr) { - -} - -@no_replay -cmd void gvr_initialize_gl(gvr_context* gvr) { - -} - -@no_replay -cmd bool gvr_get_async_reprojection_enabled(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_get_recommended_buffer_viewports(const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list) { - -} - -@no_replay -cmd void gvr_get_screen_buffer_viewports(const gvr_context* gvr, gvr_buffer_viewport_list* viewport_list) { - -} - -@no_replay -cmd gvr_sizei gvr_get_maximum_effective_render_target_size(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd gvr_sizei gvr_get_screen_target_size(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_set_surface_size(gvr_context* gvr, gvr_sizei surface_size_pixels) { - -} - -@no_replay -cmd void gvr_distort_to_screen(gvr_context* gvr, s32 texture_id, - const gvr_buffer_viewport_list* viewport_list, - gvr_mat4f head_space_from_start_space, - gvr_clock_time_point target_presentation_time) { - -} - -@no_replay -cmd bool gvr_is_feature_supported(const gvr_context* gvr, s32 feature) { - return ? -} - - -// Viewports and viewport lists - -@no_replay -cmd gvr_buffer_viewport* gvr_buffer_viewport_create(gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_destroy(gvr_buffer_viewport** viewport) { - -} - -@no_replay -cmd gvr_rectf gvr_buffer_viewport_get_source_uv(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_source_uv(gvr_buffer_viewport* viewport, gvr_rectf uv) { - -} - -@no_replay -cmd gvr_rectf gvr_buffer_viewport_get_source_fov(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_source_fov(gvr_buffer_viewport* viewport, gvr_rectf fov) { - -} - -@no_replay -cmd gvr_mat4f gvr_buffer_viewport_get_transform(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_transform(gvr_buffer_viewport* viewport, gvr_mat4f transform) { - -} - -@no_replay -cmd s32 gvr_buffer_viewport_get_target_eye(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_target_eye(gvr_buffer_viewport* viewport, s32 index) { - -} - -@no_replay -cmd s32 gvr_buffer_viewport_get_source_buffer_index(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_source_buffer_index(gvr_buffer_viewport* viewport, s32 buffer_index) { - -} - -@no_replay -cmd s32 gvr_buffer_viewport_get_external_surface_id(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_external_surface_id(gvr_buffer_viewport* viewport, s32 external_surface_id) { - -} - -@no_replay -cmd s32 gvr_buffer_viewport_get_reprojection(const gvr_buffer_viewport* viewport) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_set_reprojection(gvr_buffer_viewport* viewport, s32 reprojection) { - -} - -@no_replay -cmd void gvr_buffer_viewport_set_source_layer(gvr_buffer_viewport* viewport, s32 layer_index) { - -} - -@no_replay -cmd bool gvr_buffer_viewport_equal(const gvr_buffer_viewport* a, const gvr_buffer_viewport* b) { - return ? -} - -@no_replay -cmd gvr_buffer_viewport_list* gvr_buffer_viewport_list_create(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_list_destroy(gvr_buffer_viewport_list** viewport_list) { - -} - -@no_replay -cmd size gvr_buffer_viewport_list_get_size(const gvr_buffer_viewport_list* viewport_list) { - return ? -} - -@no_replay -cmd void gvr_buffer_viewport_list_get_item(const gvr_buffer_viewport_list* viewport_list, size index, gvr_buffer_viewport* viewport) { - -} - -@no_replay -cmd void gvr_buffer_viewport_list_set_item(gvr_buffer_viewport_list* viewport_list, size index, const gvr_buffer_viewport* viewport) { - -} - - -// Swapchains and frames - -@no_replay -cmd gvr_buffer_spec* gvr_buffer_spec_create(gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_buffer_spec_destroy(gvr_buffer_spec** spec) { - -} - -@no_replay -cmd gvr_sizei gvr_buffer_spec_get_size(const gvr_buffer_spec* spec) { - return ? -} - -@no_replay -cmd void gvr_buffer_spec_set_size(gvr_buffer_spec* spec, gvr_sizei size) { - -} - -@no_replay -cmd s32 gvr_buffer_spec_get_samples(const gvr_buffer_spec* spec) { - return ? -} - -// multisampling should be disabled. -@no_replay -cmd void gvr_buffer_spec_set_samples(gvr_buffer_spec* spec, s32 num_samples) { - -} - -@no_replay -cmd void gvr_buffer_spec_set_color_format(gvr_buffer_spec* spec, s32 color_format) { - -} - -@no_replay -cmd void gvr_buffer_spec_set_depth_stencil_format(gvr_buffer_spec* spec, s32 depth_stencil_format) { - -} - -@no_replay -cmd void gvr_buffer_spec_set_multiview_layers(gvr_buffer_spec* spec, s32 num_layers) { - -} - -@no_replay -cmd gvr_swap_chain* gvr_swap_chain_create(gvr_context* gvr, - const gvr_buffer_spec** buffers, - s32 count) { - return ? -} - -@no_replay -cmd void gvr_swap_chain_destroy(gvr_swap_chain** swap_chain) { - -} - -@no_replay -cmd s32 gvr_swap_chain_get_buffer_count(const gvr_swap_chain* swap_chain) { - return ? -} - -@no_replay -cmd gvr_sizei gvr_swap_chain_get_buffer_size(gvr_swap_chain* swap_chain, s32 index) { - return ? -} - -@no_replay -cmd void gvr_swap_chain_resize_buffer(gvr_swap_chain* swap_chain, s32 index, gvr_sizei size) { - -} - -@no_replay -cmd gvr_frame* gvr_swap_chain_acquire_frame(gvr_swap_chain* swap_chain) { - return ? -} - -@no_replay -cmd void gvr_frame_bind_buffer(gvr_frame* frame, s32 index) { - -} - -@no_replay -cmd void gvr_frame_unbind(gvr_frame* frame) { - -} - -@no_replay -cmd gvr_sizei gvr_frame_get_buffer_size(const gvr_frame* frame, s32 index) { - return ? -} - -@no_replay -cmd s32 gvr_frame_get_framebuffer_object(const gvr_frame* frame, s32 index) { - return ? -} - -@no_replay -@frame_end -cmd void gvr_frame_submit(gvr_frame** frame, const gvr_buffer_viewport_list* list, - gvr_mat4f head_space_from_start_space) { - read(frame[0:1]) - write(frame[0:1]) // frame pointer is nullified on returning. -} - -@no_replay -cmd void gvr_bind_default_framebuffer(gvr_context* gvr) { - -} - - -// Head tracking - -@no_replay -cmd gvr_clock_time_point gvr_get_time_point_now() { - return ? -} - -@no_replay -cmd gvr_mat4f gvr_get_head_space_from_start_space_rotation(const gvr_context* gvr, gvr_clock_time_point time) { - return ? -} - -@no_replay -cmd gvr_mat4f gvr_apply_neck_model(const gvr_context* gvr, - gvr_mat4f head_space_from_start_space_rotation, - f32 factor) { - return ? -} - -@no_replay -cmd void gvr_pause_tracking(gvr_context* gvr) { - -} - -@no_replay -cmd void gvr_resume_tracking(gvr_context* gvr) { - -} - -@no_replay -cmd void gvr_reset_tracking(gvr_context* gvr) { - -} - -@no_replay -cmd void gvr_recenter_tracking(gvr_context* gvr) { - -} - -// Head mounted display. - -@no_replay -cmd bool gvr_set_default_viewer_profile(gvr_context* gvr, - const char* viewer_profile_uri) { - _ = as!string(viewer_profile_uri) - return ? -} - -@no_replay -cmd void gvr_refresh_viewer_profile(gvr_context* gvr) { - -} - -@no_replay -cmd const char* gvr_get_viewer_vendor(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd const char* gvr_get_viewer_model(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd s32 gvr_get_viewer_type(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd gvr_mat4f gvr_get_eye_from_head_matrix(const gvr_context* gvr, s32 eye) { - return ? -} - -@no_replay -cmd gvr_recti gvr_get_window_bounds(const gvr_context* gvr) { - return ? -} - -@no_replay -cmd void gvr_compute_distorted_point(const gvr_context* gvr, s32 eye, gvr_vec2f uv_in, gvr_vec2f[3] uv_out) { - -} - diff --git a/gapis/api/gvr/gvr.go b/gapis/api/gvr/gvr.go deleted file mode 100644 index 67979a36a4..0000000000 --- a/gapis/api/gvr/gvr.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gvr - -import ( - "context" - - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/math/interval" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/api/sync" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" -) - -var _ = replay.QueryFramebufferAttachment(API{}) - -// Root returns the path to the root of the state to display. It can vary based -// on filtering mode. Returning nil, nil indicates there is no state to show at -// this point in the capture. -func (s *State) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) (path.Node, error) { - return nil, nil -} - -// SetupInitialState sanitizes deserialized state to make it valid. -// It can fill in any derived data which we choose not to serialize, -// or it can apply backward-compatibility fixes for older traces. -func (State) SetupInitialState(ctx context.Context) {} - -func (s *State) preMutate(ctx context.Context, g *api.GlobalState, cmd api.Cmd) error { - return nil -} - -type customState struct{} - -func (customState) init(*State) {} - -// RebuildState is a no-op to conform to the api.API interface. -func (API) RebuildState(ctx context.Context, g *api.GlobalState) ([]api.Cmd, interval.U64RangeList) { - return nil, nil -} - -func (API) QueryFramebufferAttachment( - ctx context.Context, - intent replay.Intent, - mgr replay.Manager, - after []uint64, - width, height uint32, - attachment api.FramebufferAttachment, - framebufferIndex uint32, - drawMode service.DrawMode, - disableReplayOptimization bool, - displayToSurface bool, - hints *service.UsageHints) (*image.Data, error) { - - if framebufferIndex == 0 { - fb, err := getFramebuffer(ctx, api.CmdID(after[0])) - if err != nil { - return nil, err - } - framebufferIndex = uint32(fb) - } - return gles.API{}.QueryFramebufferAttachment( - ctx, - intent, - mgr, - after, - width, height, - attachment, - framebufferIndex, - drawMode, - disableReplayOptimization, - displayToSurface, - hints, - ) -} - -// GetFramebufferAttachmentInfo returns the width, height and format of the -// specified framebuffer attachment. -func (API) GetFramebufferAttachmentInfo( - ctx context.Context, - after []uint64, - state *api.GlobalState, - thread uint64, - attachment api.FramebufferAttachment) (inf api.FramebufferAttachmentInfo, err error) { - - fb, err := getFramebuffer(ctx, api.CmdID(after[0])) - if err != nil { - return api.FramebufferAttachmentInfo{}, err - } - return gles.GetFramebufferAttachmentInfoByID(state, thread, attachment, fb) -} - -// Context returns the active context for the given state and thread. -func (API) Context(ctx context.Context, s *api.GlobalState, thread uint64) api.Context { - return gles.API{}.Context(ctx, s, thread) -} - -// Mesh implements the api.MeshProvider interface. -func (API) Mesh(ctx context.Context, o interface{}, p *path.Mesh, r *path.ResolveConfig) (*api.Mesh, error) { - return nil, nil -} - -var _ sync.SynchronizedAPI = API{} - -// GetTerminator returns a transform that will allow the given capture to be terminated -// after a command -func (API) GetTerminator(ctx context.Context, c *path.Capture) (transform.Terminator, error) { - return nil, nil -} - -// ResolveSynchronization resolve all of the synchronization information for -// the given API -func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Capture) error { - return nil -} - -// FlattenSubcommandIdx flattens grouped ids to their flattened linear ids if possible. -func (API) FlattenSubcommandIdx(idx api.SubCmdIdx, data *sync.Data, unused bool) (api.CmdID, bool) { - sg, ok := data.SubcommandReferences[api.CmdID(idx[0])] - if !ok { - return api.CmdID(0), false - } - for _, v := range sg { - if v.Index.Equals(idx[1:]) { - if v.IsCallerGroup { - return v.GeneratingCmd, true - } - break - } - } - return api.CmdID(0), false -} - -// IsTrivialTerminator returns true if the terminator is just stopping at the given index -func (API) IsTrivialTerminator(ctx context.Context, p *path.Capture, command api.SubCmdIdx) (bool, error) { - return true, nil -} - -// RecoverMidExecutionCommand returns a virtual command, used to describe the -// a subcommand that was created before the start of the trace -// GVR has no subcommands of this type, so this should never be called -func (API) RecoverMidExecutionCommand(ctx context.Context, c *path.Capture, i interface{}) (api.Cmd, error) { - return nil, sync.NoMECSubcommandsError{} -} - -// MutateSubcommands mutates the given Cmd and calls callbacks for subcommands -// called before and after executing each subcommand callback. -func (API) MutateSubcommands(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState, - preSubCmdCallback func(*api.GlobalState, api.SubCmdIdx, api.Cmd), - postSubCmdCallback func(*api.GlobalState, api.SubCmdIdx, api.Cmd)) error { - - return nil -} diff --git a/gapis/api/gvr/gvr_pb/BUILD.bazel b/gapis/api/gvr/gvr_pb/BUILD.bazel deleted file mode 100644 index 557fca56dc..0000000000 --- a/gapis/api/gvr/gvr_pb/BUILD.bazel +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("//tools/build:rules.bzl", "apic_template") - -apic_template( - name = "api_proto", - api = "//gapis/api/gvr:api", - templates = ["//gapis/api/templates:proto"], - visibility = ["//visibility:public"], -) - -go_library( - name = "go_default_library", - srcs = ["doc.go"], - embed = [":gvr_pb_go_proto"], # keep - importpath = "github.com/google/gapid/gapis/api/gvr/gvr_pb", - visibility = ["//visibility:public"], -) - -proto_library( - name = "gvr_pb_proto", - srcs = [":api_proto"], # keep - visibility = ["//visibility:public"], - deps = ["//gapis/memory/memory_pb:memory_pb_proto"], # keep -) - -cc_proto_library( - name = "gvr_pb_cc_proto", - visibility = ["//visibility:public"], - deps = [":gvr_pb_proto"], -) - -# keep -go_proto_library( - name = "gvr_pb_go_proto", - importpath = "github.com/google/gapid/gapis/api/gvr/gvr_pb", - proto = ":gvr_pb_proto", - visibility = ["//visibility:public"], - deps = ["//gapis/memory/memory_pb:go_default_library"], -) diff --git a/gapis/api/gvr/gvr_pb/doc.go b/gapis/api/gvr/gvr_pb/doc.go deleted file mode 100644 index 456bd46c9a..0000000000 --- a/gapis/api/gvr/gvr_pb/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package gvr_pb describes the serialization format for the gvr api. -package gvr_pb diff --git a/gapis/api/gvr/importance.go b/gapis/api/gvr/importance.go deleted file mode 100644 index 394729ddbf..0000000000 --- a/gapis/api/gvr/importance.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package gvr - -import "github.com/google/gapid/gapis/resolve" - -var _ = []resolve.Importance{ - &Gvr_frame_submit{}, -} - -func (*Gvr_frame_submit) Importance() int { return 100 } diff --git a/gapis/api/gvr/resolvables.proto b/gapis/api/gvr/resolvables.proto deleted file mode 100644 index acc76a4018..0000000000 --- a/gapis/api/gvr/resolvables.proto +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -import "gapis/service/path/path.proto"; - -package gvr; -option go_package = "github.com/google/gapid/gapis/api/gvr"; - -// GAPIS internal structure. -message FrameBindingsResolvable { - path.Capture capture = 1; -} diff --git a/gapis/api/gvr/templates/BUILD.bazel b/gapis/api/gvr/templates/BUILD.bazel deleted file mode 100644 index d37fd65621..0000000000 --- a/gapis/api/gvr/templates/BUILD.bazel +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("//tools/build:rules.bzl", "api_template") - -package(default_visibility = ["//visibility:public"]) - -api_template( - name = "api_exports.h", - includes = ["//gapis/api/templates"], - outputs = ["{api}_exports.h"], - template = "api_exports.h.tmpl", -) - -api_template( - name = "api_exports.cpp", - includes = ["//gapis/api/templates"], - outputs = ["{api}_exports.cpp"], - template = "api_exports.cpp.tmpl", -) - -api_template( - name = "api_imports.cpp", - includes = ["//gapis/api/templates"], - outputs = ["{api}_imports.cpp"], - template = "api_imports.cpp.tmpl", -) - -api_template( - name = "api_install.cpp", - includes = ["//gapis/api/templates"], - outputs = ["{api}_install.cpp"], - template = "api_install.cpp.tmpl", -) diff --git a/gapis/api/gvr/templates/api_exports.cpp.tmpl b/gapis/api/gvr/templates/api_exports.cpp.tmpl deleted file mode 100644 index 90b56b4569..0000000000 --- a/gapis/api/gvr/templates/api_exports.cpp.tmpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl"}} - -{{$filename := print (Global "API") "_exports.cpp" }} -{{$ | Macro "Exports" | Reflow 4 | Write $filename}} - -{{define "Exports"}} - {{AssertType $ "API"}} - {{Template "C++.Copyright"}} -¶ -#include "gapii/cc/{{Global "API"}}_exports.h" -#include "gapii/cc/{{Global "API"}}_imports.h" -#include "gapii/cc/{{Global "API"}}_types.h" -#include "gapii/cc/spy.h" -¶ -#include "core/cc/log.h" -#include "core/cc/target.h" // STDCALL -¶ -#include -¶ -#include -¶ -using namespace gapii; -¶ -const uint8_t GvrAPI = {{$.Index}}; -¶ -namespace gapii {« -¶ - {{range $c := AllCommands $}} - {{$name := Macro "CmdName" $c}} - {{$imports := print (Title (Global "API")) "Spy::imports()"}} - EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}) { - GAPID_DEBUG({{Template "C++.PrintfCommandCall" $c}}); - Spy* s = Spy::get(); - auto spy_ctx = s->enter("{{$name}}", GvrAPI); - {{if not (IsVoid $c.Return.Type)}}auto _result_ = §{{end}} - s->{{$name}}({{Macro "C++.CallArguments" $c | Strings "spy_ctx" | JoinWith ", "}}); - s->exit(); - GAPID_DEBUG("{{$name}}() -- done"); - {{if not (IsVoid $c.Return.Type)}}return _result_;{{end}} - } - {{end}} -¶ -»} // namespace gapii -¶ -{{end}} \ No newline at end of file diff --git a/gapis/api/gvr/templates/api_exports.h.tmpl b/gapis/api/gvr/templates/api_exports.h.tmpl deleted file mode 100644 index 3711a557c3..0000000000 --- a/gapis/api/gvr/templates/api_exports.h.tmpl +++ /dev/null @@ -1,40 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl"}} - -{{$filename := print (Global "API") "_exports.h" }} -{{$ | Macro "Exports" | Reflow 4 | Write $filename}} - -{{define "Exports"}} - {{AssertType $ "API"}} - {{Template "C++.Copyright"}} -¶ -#include "gapii/cc/{{Global "API"}}_types.h" -¶ -#include "core/cc/target.h" // STDCALL -¶ -namespace gapii {« -¶ -{{range $c := AllCommands $}} - {{$name := Macro "CmdName" $c}} - EXPORT {{Template "C++.ReturnType" $c}} STDCALL {{$name}}({{Template "C++.CallParameters" $c}}); -{{end}} -¶ -»} // namespace gapii -¶ -{{end}} diff --git a/gapis/api/gvr/templates/api_imports.cpp.tmpl b/gapis/api/gvr/templates/api_imports.cpp.tmpl deleted file mode 100644 index a014868972..0000000000 --- a/gapis/api/gvr/templates/api_imports.cpp.tmpl +++ /dev/null @@ -1,45 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl" }} -{{Include "../../templates/api_classnames.tmpl"}} - -{{$filename := print (Global "API") "_imports.cpp" }} -{{$ | Macro "imports.cpp" | Reflow 4 | Write $filename}} - -{{/* -------------------------------------------------------------------------------- - Entry point. -------------------------------------------------------------------------------- -*/}} -{{define "imports.cpp"}} -{{template "C++.Copyright"}} -¶ -#include "{{Global "API"}}_imports.h" -¶ -#include -¶ -namespace gapii {« -¶ - {{$name := Macro "ApiClassnames.Imports"}} - {{$name}}::{{$name}}() { - memset(this, 0, sizeof(*this)); - } -¶ -»} // namespace gapii -¶ -{{end}} diff --git a/gapis/api/gvr/templates/api_install.cpp.tmpl b/gapis/api/gvr/templates/api_install.cpp.tmpl deleted file mode 100644 index c2714fd1af..0000000000 --- a/gapis/api/gvr/templates/api_install.cpp.tmpl +++ /dev/null @@ -1,63 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* ---- Includes ---- */}} -{{Include "../../templates/cpp_common.tmpl"}} - -{{$filename := print "gvr_install.cpp" }} -{{$ | Macro "Install" | Reflow 4 | Write $filename}} - -{{define "Install"}} - {{AssertType $ "API"}} - {{Template "C++.Copyright"}} -¶ -#include "gapii/cc/android/gvr_install.h" -¶ -#include "gapii/cc/gvr_exports.h" -#include "gapii/cc/gvr_imports.h" -#include "gapii/cc/android/installer.h" -¶ -#include -¶ -namespace gapii {« -¶ -bool install_gvr(Installer* installer, void* gvr_lib, GvrImports* imports) { - struct func_t { - const char* name; - void** imp; - const void* exp; - }; -¶ - func_t funcs[] = { - {{range $c := AllCommands $}} - {{$name := Macro "CmdName" $c}} - { "{{$name}}", reinterpret_cast(&imports->{{$name}}), reinterpret_cast({{$name}}) }, - {{end}} - }; -¶ - for (auto func : funcs) { - if (auto import = dlsym(gvr_lib, func.name)) { - GAPID_INFO("Installing '%s'...", func.name); - *func.imp = installer->install(import, func.exp); - } else { - GAPID_WARNING("Could not find GVR function '%s'", func.name); - } - } - return true; -} -¶ -»} // namespace gapii -{{end}} diff --git a/gapis/api/gvr/types.api b/gapis/api/gvr/types.api deleted file mode 100644 index d01b9bd97e..0000000000 --- a/gapis/api/gvr/types.api +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -class gvr_context {} - -enum gvr_eye { - GVR_LEFT_EYE = 0 - GVR_RIGHT_EYE = 1 - GVR_NUM_EYES = 2 -} - -enum gvr_viewer_type { - GVR_VIEWER_TYPE_CARDBOARD = 0, - GVR_VIEWER_TYPE_DAYDREAM = 1, -} - -enum gvr_feature { - GVR_FEATURE_ASYNC_REPROJECTION = 0, - GVR_FEATURE_MULTIVIEW = 1, - GVR_FEATURE_EXTERNAL_SURFACE = 2 -} - -class gvr_version { - s32 major - s32 minor - s32 patch -} - -class gvr_sizei { - s32 width - s32 height -} - -class gvr_recti { - s32 left - s32 right - s32 bottom - s32 top -} - -class gvr_rectf { - f32 left - f32 right - f32 bottom - f32 top -} - -class gvr_vec2f { - f32 x - f32 y -} - -class gvr_vec3f { - f32 x - f32 y - f32 z -} - -// gvr_mat4f is used as a parameter and return value. -// clang seems to change the method of passing parameters of -// this type when there's a copy-constructor on the StaticArray. -// Work around this by using a different type for the interface. -@abi_type("gvr_mat4_abi") -class gvr_mat4f { - f32[16] m -} - -class gvr_quatf { - f32 qx - f32 qy - f32 qz - f32 qw -} - -class gvr_clock_time_point { - s64 monotonic_system_time_nanos -} - -class gvr_buffer_viewport {} - -class gvr_buffer_viewport_list {} - -class gvr_buffer_spec {} - -class gvr_swap_chain {} - -class gvr_frame {} - -enum gvr_error { - GVR_ERROR_NONE = 0 - GVR_ERROR_CONTROLLER_CREATE_FAILED = 2 - GVR_ERROR_NO_FRAME_AVAILABLE = 3 -} - -enum gvr_controller_flags { - GVR_CONTROLLER_ENABLE_ORIENTATION = 0x001 - GVR_CONTROLLER_ENABLE_TOUCH = 0x002 - GVR_CONTROLLER_ENABLE_GYRO = 0x004 - GVR_CONTROLLER_ENABLE_ACCEL = 0x008 - GVR_CONTROLLER_ENABLE_GESTURES = 0x010 - GVR_CONTROLLER_ENABLE_POSE_PREDICTION = 0x020 - GVR_CONTROLLER_ENABLE_POSITION = 0x040 - GVR_CONTROLLER_ENABLE_BATTERY = 0x080 - GVR_CONTROLLER_ENABLE_ARM_MODEL = 0x100 -} - -enum gvr_controller_api_status { - GVR_CONTROLLER_API_OK = 0, - GVR_CONTROLLER_API_UNSUPPORTED = 1, - GVR_CONTROLLER_API_NOT_AUTHORIZED = 2, - GVR_CONTROLLER_API_UNAVAILABLE = 3, - GVR_CONTROLLER_API_SERVICE_OBSOLETE = 4, - GVR_CONTROLLER_API_CLIENT_OBSOLETE = 5, - GVR_CONTROLLER_API_MALFUNCTION = 6, -} - -enum gvr_controller_connection_state { - GVR_CONTROLLER_DISCONNECTED = 0, - GVR_CONTROLLER_SCANNING = 1, - GVR_CONTROLLER_CONNECTING = 2, - GVR_CONTROLLER_CONNECTED = 3, -} - -enum gvr_controller_button { - GVR_CONTROLLER_BUTTON_NONE = 0, - GVR_CONTROLLER_BUTTON_CLICK = 1, - GVR_CONTROLLER_BUTTON_HOME = 2, - GVR_CONTROLLER_BUTTON_APP = 3, - GVR_CONTROLLER_BUTTON_VOLUME_UP = 4, - GVR_CONTROLLER_BUTTON_VOLUME_DOWN = 5, - GVR_CONTROLLER_BUTTON_COUNT = 6, -} - -enum gvr_controller_battery_level { - GVR_CONTROLLER_BATTERY_LEVEL_UNKNOWN = 0, - GVR_CONTROLLER_BATTERY_LEVEL_CRITICAL_LOW = 1, - GVR_CONTROLLER_BATTERY_LEVEL_LOW = 2, - GVR_CONTROLLER_BATTERY_LEVEL_MEDIUM = 3, - GVR_CONTROLLER_BATTERY_LEVEL_ALMOST_FULL = 4, - GVR_CONTROLLER_BATTERY_LEVEL_FULL = 5, - GVR_CONTROLLER_BATTERY_LEVEL_COUNT = 6, -} - -enum gvr_audio_rendering_mode { - GVR_AUDIO_RENDERING_STEREO_PANNING = 0, - GVR_AUDIO_RENDERING_BINAURAL_LOW_QUALITY = 1, - GVR_AUDIO_RENDERING_BINAURAL_HIGH_QUALITY = 2, -} - -enum gvr_audio_material_type { - GVR_AUDIO_MATERIAL_TRANSPARENT = 0, - GVR_AUDIO_MATERIAL_ACOUSTIC_CEILING_TILES = 1, - GVR_AUDIO_MATERIAL_BRICK_BARE = 2, - GVR_AUDIO_MATERIAL_BRICK_PAINTED = 3, - GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_COARSE = 4, - GVR_AUDIO_MATERIAL_CONCRETE_BLOCK_PAINTED = 5, - GVR_AUDIO_MATERIAL_CURTAIN_HEAVY = 6, - GVR_AUDIO_MATERIAL_FIBER_GLASS_INSULATION = 7, - GVR_AUDIO_MATERIAL_GLASS_THIN = 8, - GVR_AUDIO_MATERIAL_GLASS_THICK = 9, - GVR_AUDIO_MATERIAL_GRASS = 10, - GVR_AUDIO_MATERIAL_LINOLEUM_ON_CONCRETE = 11, - GVR_AUDIO_MATERIAL_MARBLE = 12, - GVR_AUDIO_MATERIAL_METAL = 13, - GVR_AUDIO_MATERIAL_PARQUET_ON_CONCRETE = 14, - GVR_AUDIO_MATERIAL_PLASTER_ROUGH = 15, - GVR_AUDIO_MATERIAL_PLASTER_SMOOTH = 16, - GVR_AUDIO_MATERIAL_PLYWOOD_PANEL = 17, - GVR_AUDIO_MATERIAL_POLISHED_CONCRETE_OR_TILE = 18, - GVR_AUDIO_MATERIAL_SHEET_ROCK = 19, - GVR_AUDIO_MATERIAL_WATER_OR_ICE_SURFACE = 20, - GVR_AUDIO_MATERIAL_WOOD_CEILING = 21, - GVR_AUDIO_MATERIAL_WOOD_PANEL = 22, -} - -enum gvr_audio_distance_rolloff_type { - GVR_AUDIO_ROLLOFF_LOGARITHMIC = 0, - GVR_AUDIO_ROLLOFF_LINEAR = 1, - GVR_AUDIO_ROLLOFF_NONE = 2, -} - -type s32 gvr_audio_source_id - -enum gvr_audio_surround_format_type { - GVR_AUDIO_SURROUND_FORMAT_INVALID = 0, - GVR_AUDIO_SURROUND_FORMAT_SURROUND_MONO = 1, - GVR_AUDIO_SURROUND_FORMAT_SURROUND_STEREO = 2, - GVR_AUDIO_SURROUND_FORMAT_SURROUND_FIVE_DOT_ONE = 3, - GVR_AUDIO_SURROUND_FORMAT_FIRST_ORDER_AMBISONICS = 4, - GVR_AUDIO_SURROUND_FORMAT_SECOND_ORDER_AMBISONICS = 5, - GVR_AUDIO_SURROUND_FORMAT_THIRD_ORDER_AMBISONICS = 6, -} - -enum gvr_color_format_type { - GVR_COLOR_FORMAT_RGBA_8888 = 0, - GVR_COLOR_FORMAT_RGB_565 = 1, -} - -enum gvr_depth_stencil_format_type { - GVR_DEPTH_STENCIL_FORMAT_NONE = 255, - GVR_DEPTH_STENCIL_FORMAT_DEPTH_16 = 0, - GVR_DEPTH_STENCIL_FORMAT_DEPTH_24 = 1, - GVR_DEPTH_STENCIL_FORMAT_DEPTH_24_STENCIL_8 = 2, - GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F = 3, - GVR_DEPTH_STENCIL_FORMAT_DEPTH_32_F_STENCIL_8 = 4, - GVR_DEPTH_STENCIL_FORMAT_STENCIL_8 = 5, -} - -enum gvr_reprojection { - GVR_REPROJECTION_NONE = 0, - GVR_REPROJECTION_FULL = 1, -} - -enum gvr_controller_handedness { - GVR_CONTROLLER_RIGHT_HANDED = 0, - GVR_CONTROLLER_LEFT_HANDED = 1, -} - -enum gvr_arm_model_behavior { - GVR_ARM_MODEL_SYNC_GAZE = 0, - GVR_ARM_MODEL_FOLLOW_GAZE = 1, - GVR_ARM_MODEL_IGNORE_GAZE = 2, -} - -class gvr_user_prefs {} - -// Anonymous enum for miscellaneous integer constants. -@analyze_usage -enum gvr_enum { - GVR_EXTERNAL_SURFACE_ID_NONE = 0xffffffff, - GVR_BUFFER_INDEX_EXTERNAL_SURFACE = 0xffffffff, - GVR_AUDIO_INVALID_SOURCE_ID = 0xffffffff, -} diff --git a/gapis/api/service.proto b/gapis/api/service.proto index 2ce9b06e39..d0e448ce9d 100644 --- a/gapis/api/service.proto +++ b/gapis/api/service.proto @@ -18,7 +18,6 @@ import "core/image/image.proto"; import "core/data/pod/pod.proto"; import "gapis/service/box/box.proto"; import "gapis/service/path/path.proto"; -import "gapis/service/types/types.proto"; import "gapis/vertex/vertex.proto"; package api; diff --git a/gapis/api/templates/api_spy.h.tmpl b/gapis/api/templates/api_spy.h.tmpl index 71d61f5db2..9c6105fa70 100644 --- a/gapis/api/templates/api_spy.h.tmpl +++ b/gapis/api/templates/api_spy.h.tmpl @@ -38,11 +38,7 @@ #include "{{Global "API"}}_imports.h" #include "{{Global "API"}}_types.h" ¶ -{{if (eq (Global "API") "gles")}} #include "gapii/cc/spy_base.h" -{{else}} - #include "gapii/cc/gles_spy.h" -{{end}} #include "gapii/cc/call_observer.h" #include "gapii/cc/state_serializer.h" ¶ diff --git a/gapis/extensions/unity/BUILD.bazel b/gapis/extensions/unity/BUILD.bazel deleted file mode 100644 index e579d8a3d1..0000000000 --- a/gapis/extensions/unity/BUILD.bazel +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "state_reset_grouper.go", - "unity.go", - ], - importpath = "github.com/google/gapid/gapis/extensions/unity", - visibility = ["//visibility:public"], - deps = [ - "//gapis/api:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/extensions:go_default_library", - "//gapis/resolve/cmdgrouper:go_default_library", - "//gapis/service/path:go_default_library", - ], -) diff --git a/gapis/extensions/unity/state_reset_grouper.go b/gapis/extensions/unity/state_reset_grouper.go deleted file mode 100644 index a4aa187930..0000000000 --- a/gapis/extensions/unity/state_reset_grouper.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package unity - -import ( - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/resolve/cmdgrouper" -) - -func newStateResetGrouper() cmdgrouper.Grouper { - eglGetCurrentContext := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.EglGetCurrentContext) - return ok - } - } - glDisable := func(capability gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlDisable) - return ok && c.Capability() == capability - } - } - glEnable := func(capability gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlEnable) - return ok && c.Capability() == capability - } - } - glFrontFace := func(orientation gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlFrontFace) - return ok && c.Orientation() == orientation - } - } - glDepthFunc := func(function gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlDepthFunc) - return ok && c.Function() == function - } - } - glColorMask := func(r, g, b, a gles.GLboolean) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlColorMask) - return ok && c.Red() == r && c.Green() == g && c.Blue() == b && c.Alpha() == a - } - } - glBlendFuncSeparate := func(srcFactorRGB, dstFactorRGB, srcFactorA, dstFactorA gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBlendFuncSeparate) - return ok && - c.SrcFactorRgb() == srcFactorRGB && - c.DstFactorRgb() == dstFactorRGB && - c.SrcFactorAlpha() == srcFactorA && - c.DstFactorAlpha() == dstFactorA - } - } - glBlendEquationSeparate := func(rgb, alpha gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBlendEquationSeparate) - return ok && c.Rgb() == rgb && c.Alpha() == alpha - } - } - glStencilFuncSeparate := func(face, function gles.GLenum, referenceValue gles.GLint, mask gles.GLuint) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlStencilFuncSeparate) - return ok && - c.Face() == face && - c.Function() == function && - c.ReferenceValue() == referenceValue && - c.Mask() == mask - } - } - glStencilOpSeparate := func(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlStencilOpSeparate) - return ok && - c.Face() == face && - c.StencilFail() == stencilFail && - c.StencilPassDepthFail() == stencilPassDepthFail && - c.StencilPassDepthPass() == stencilPassDepthPass - } - } - glStencilMask := func(mask gles.GLuint) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlStencilMask) - return ok && c.Mask() == mask - } - } - glCullFace := func(mode gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlCullFace) - return ok && c.Mode() == mode - } - } - glDepthMask := func(enabled gles.GLboolean) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlDepthMask) - return ok && c.Enabled() == enabled - } - } - glBindSampler := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBindSampler) - p, _ := prev.(*gles.GlBindSampler) - return ok && c.Sampler() == 0 && (p == nil || c.Index() == p.Index()+1) - } - } - glBindBuffer := func(target gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBindBuffer) - return ok && c.Buffer() == 0 && c.Target() == target - } - } - glBindBufferBase := func(target gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBindBufferBase) - p, _ := prev.(*gles.GlBindBufferBase) - return ok && c.Buffer() == 0 && c.Target() == target && - (p == nil || c.Target() != p.Target() || c.Index() == p.Index()+1) - } - } - glUseProgram := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlUseProgram) - return ok && c.Program() == 0 - } - } - glActiveTextureOrBindTexture := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - if _, ok := cmd.(*gles.GlActiveTexture); ok { - return true - } - if cmd, ok := cmd.(*gles.GlBindTexture); ok && cmd.Texture() == 0 { - return true - } - return false - } - } - glPixelStorei := func(param gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlPixelStorei) - return ok && c.Parameter() == param - } - } - glBindFramebuffer := func(target gles.GLenum) func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlBindFramebuffer) - return ok && c.Target() == target - } - } - glIsVertexArrayRuleOrGenVertexArrays := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - if _, ok := cmd.(*gles.GlIsVertexArray); ok { - return true - } - if _, ok := cmd.(*gles.GlGenVertexArrays); ok { - return true - } - return false - } - } - glBindVertexArray := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - _, ok := cmd.(*gles.GlBindVertexArray) - return ok - } - } - glDisableVertexAttribArray := func() func(cmd, prev api.Cmd) bool { - return func(cmd, prev api.Cmd) bool { - c, ok := cmd.(*gles.GlDisableVertexAttribArray) - p, _ := prev.(*gles.GlDisableVertexAttribArray) - return ok && ((p == nil && c.Location() == 0) || (p != nil && c.Location() == p.Location()+1)) - } - } - - return cmdgrouper.Sequence("Unity state reset", - cmdgrouper.Rule{Pred: eglGetCurrentContext()}, // eglGetCurrentContext() - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_DEPTH_TEST)}, // glDisable(GL_DEPTH_TEST) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_BLEND)}, // glDisable(GL_BLEND) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_SAMPLE_ALPHA_TO_COVERAGE)}, // glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_STENCIL_TEST)}, // glDisable(GL_STENCIL_TEST) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_POLYGON_OFFSET_FILL)}, // glDisable(GL_POLYGON_OFFSET_FILL) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_SCISSOR_TEST)}, // glDisable(GL_SCISSOR_TEST) - cmdgrouper.Rule{Pred: glDisable(gles.GLenum_GL_FRAMEBUFFER_SRGB_EXT), Optional: true}, // glDisable(GL_FRAMEBUFFER_SRGB_EXT) - cmdgrouper.Rule{Pred: glEnable(gles.GLenum_GL_DITHER)}, // glEnable(GL_DITHER) - cmdgrouper.Rule{Pred: glDepthFunc(gles.GLenum_GL_NEVER), Optional: true}, // glDepthFunc(GL_NEVER) - cmdgrouper.Rule{Pred: glDepthMask(0)}, // glDepthMask(0) - cmdgrouper.Rule{Pred: glEnable(gles.GLenum_GL_DEPTH_TEST), Optional: true}, // glEnable(GL_DEPTH_TEST) - cmdgrouper.Rule{Pred: glDepthFunc(gles.GLenum_GL_ALWAYS), Optional: true}, // glDepthFunc(GL_ALWAYS) - cmdgrouper.Rule{Pred: glColorMask(1, 1, 1, 1)}, // glColorMask(1, 1, 1, 1) - cmdgrouper.Rule{Pred: glBlendFuncSeparate(gles.GLenum_GL_ONE, gles.GLenum_GL_ZERO, gles.GLenum_GL_ONE, gles.GLenum_GL_ZERO)}, // glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO) - cmdgrouper.Rule{Pred: glBlendEquationSeparate(gles.GLenum_GL_FUNC_ADD, gles.GLenum_GL_FUNC_ADD)}, // glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD) - cmdgrouper.Rule{Pred: glStencilFuncSeparate(gles.GLenum_GL_FRONT, gles.GLenum_GL_ALWAYS, 0, 255)}, // glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 255) - cmdgrouper.Rule{Pred: glStencilOpSeparate(gles.GLenum_GL_FRONT, gles.GLenum_GL_KEEP, gles.GLenum_GL_KEEP, gles.GLenum_GL_KEEP)}, // glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP) - cmdgrouper.Rule{Pred: glStencilFuncSeparate(gles.GLenum_GL_BACK, gles.GLenum_GL_ALWAYS, 0, 255)}, // glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 255) - cmdgrouper.Rule{Pred: glStencilOpSeparate(gles.GLenum_GL_BACK, gles.GLenum_GL_KEEP, gles.GLenum_GL_KEEP, gles.GLenum_GL_KEEP)}, // glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP) - cmdgrouper.Rule{Pred: glStencilMask(255)}, // glStencilMask(255) - cmdgrouper.Rule{Pred: glCullFace(gles.GLenum_GL_BACK)}, // glCullFace(GL_BACK) - cmdgrouper.Rule{Pred: glEnable(gles.GLenum_GL_CULL_FACE)}, // glEnable(GL_CULL_FACE) - cmdgrouper.Rule{Pred: glFrontFace(gles.GLenum_GL_CW)}, // glFrontFace(orientation: GL_CW) - cmdgrouper.Rule{Pred: glBindSampler(), Repeats: true}, // glBindSampler(0..N, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_ARRAY_BUFFER)}, // glBindBuffer(GL_ARRAY_BUFFER, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_ELEMENT_ARRAY_BUFFER)}, // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_DRAW_INDIRECT_BUFFER)}, // glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_COPY_READ_BUFFER)}, // glBindBuffer(GL_COPY_READ_BUFFER, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_COPY_WRITE_BUFFER)}, // glBindBuffer(GL_COPY_WRITE_BUFFER, 0) - cmdgrouper.Rule{Pred: glBindBufferBase(gles.GLenum_GL_UNIFORM_BUFFER), Repeats: true}, // glBindBufferBase(GL_UNIFORM_BUFFER, 0..N, 0) - cmdgrouper.Rule{Pred: glBindBufferBase(gles.GLenum_GL_TRANSFORM_FEEDBACK_BUFFER)}, // glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0) - cmdgrouper.Rule{Pred: glBindBufferBase(gles.GLenum_GL_SHADER_STORAGE_BUFFER), Repeats: true}, // glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0..N, 0) - cmdgrouper.Rule{Pred: glBindBufferBase(gles.GLenum_GL_ATOMIC_COUNTER_BUFFER), Repeats: true}, // glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0..N, 0) - cmdgrouper.Rule{Pred: glBindBuffer(gles.GLenum_GL_DISPATCH_INDIRECT_BUFFER)}, // glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0) - cmdgrouper.Rule{Pred: glUseProgram()}, // glUseProgram(0) - cmdgrouper.Rule{Pred: glActiveTextureOrBindTexture(), Repeats: true}, // glActiveTexture(GL_TEXTURE31 .. 0), glBindTexture(GL_TEXTURE_2D, 0) - cmdgrouper.Rule{Pred: glPixelStorei(gles.GLenum_GL_UNPACK_ROW_LENGTH)}, // glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) - cmdgrouper.Rule{Pred: glPixelStorei(gles.GLenum_GL_PACK_ALIGNMENT)}, // glPixelStorei(GL_PACK_ALIGNMENT, 1) - cmdgrouper.Rule{Pred: glPixelStorei(gles.GLenum_GL_UNPACK_ALIGNMENT)}, // glPixelStorei(GL_UNPACK_ALIGNMENT, 1) - cmdgrouper.Rule{Pred: glBindFramebuffer(gles.GLenum_GL_DRAW_FRAMEBUFFER)}, // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) - cmdgrouper.Rule{Pred: glBindFramebuffer(gles.GLenum_GL_READ_FRAMEBUFFER)}, // glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) - cmdgrouper.Rule{Pred: glIsVertexArrayRuleOrGenVertexArrays(), Repeats: true}, // glIsVertexArray(array: 1) → 0, glGenVertexArrays(count: 1, arrays: 0xcab3ff84) - cmdgrouper.Rule{Pred: glBindVertexArray()}, // glBindVertexArray(array: 2) - cmdgrouper.Rule{Pred: glDisableVertexAttribArray(), Repeats: true}, // glDisableVertexAttribArray(0 .. N) - cmdgrouper.Rule{Pred: glFrontFace(gles.GLenum_GL_CW), Optional: true}, // glFrontFace(orientation: GL_CW) - ) -} diff --git a/gapis/extensions/unity/unity.go b/gapis/extensions/unity/unity.go deleted file mode 100644 index 6a3d8bb122..0000000000 --- a/gapis/extensions/unity/unity.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package unity provides GAPIS extensions that handle Unity engine features. -package unity - -import ( - "context" - - "github.com/google/gapid/gapis/extensions" - "github.com/google/gapid/gapis/resolve/cmdgrouper" - "github.com/google/gapid/gapis/service/path" -) - -func init() { - extensions.Register(extensions.Extension{ - Name: "Unity", - CmdGroupers: func(ctx context.Context, p *path.CommandTree, r *path.ResolveConfig) []cmdgrouper.Grouper { - return []cmdgrouper.Grouper{ - newStateResetGrouper(), - } - }, - }) -} diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 088efab801..7f82f14616 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -54,11 +54,9 @@ function build { echo $(date): Build completed. } -# Build each API package separately first, as the go-compiler needs ~8GB of -# RAM for each of the big API packages. -for api in gles vulkan gvr; do - build //gapis/api/$api:go_default_library -done +# Build the Vulkan API package separately first, as the go-compiler needs ~8GB +# of RAM for this +build //gapis/api/vulkan:go_default_library # Build the package and symbol file. build //:pkg //:symbols diff --git a/kokoro/macos/build.sh b/kokoro/macos/build.sh index 63714d92c4..df7c9f0645 100755 --- a/kokoro/macos/build.sh +++ b/kokoro/macos/build.sh @@ -58,9 +58,7 @@ function build { # Build each API package separately first, as the go-compiler needs ~8GB of # RAM for each of the big API packages. -for api in gles vulkan gvr; do - build //gapis/api/$api:go_default_library -done +build //gapis/api/vulkan:go_default_library # Build the package and symbol file. build //:pkg //:symbols diff --git a/kokoro/windows/build.bat b/kokoro/windows/build.bat index 8e336b5920..59d2108d38 100644 --- a/kokoro/windows/build.bat +++ b/kokoro/windows/build.bat @@ -70,13 +70,6 @@ if "%KOKORO_GITHUB_COMMIT%." == "." ( set BUILD_SHA=%DEV_PREFIX%%KOKORO_GITHUB_COMMIT% ) -REM Build each API package separately first, as the go-compiler needs ~8GB of RAM for each package. -%BUILD_ROOT%\bazel build -c opt --config symbols ^ - --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ - --define AGI_BUILD_SHA="%BUILD_SHA%" ^ - //gapis/api/gles:go_default_library -if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% - %BUILD_ROOT%\bazel build -c opt --config symbols ^ --define AGI_BUILD_NUMBER="%KOKORO_BUILD_NUMBER%" ^ --define AGI_BUILD_SHA="%BUILD_SHA%" ^ diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index f9e5e7baaa..8ef0c3cc79 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -312,15 +312,6 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): actual = "@androidndk//:toolchain-libcpp", ) - maybe_repository( - http_archive, - name = "libinterceptor", - locals = locals, - url = "https://github.com/google/gapid/releases/download/libinterceptor-v1.0/libinterceptor.zip", - build_file = "@gapid//tools/build/third_party:libinterceptor.BUILD", - sha256 = "307e0e3ec7451a244811b4edf21453d55d1e90a5f868a73dc42d4975ef74aec9", - ) - if mingw: cc_configure() From 6b99debadd5107fa2f6cbca2c416d6860a51b8e0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 10 Mar 2020 18:22:47 -0700 Subject: [PATCH 0165/1218] Tweak macos build --- gapii/cc/BUILD.bazel | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gapii/cc/BUILD.bazel b/gapii/cc/BUILD.bazel index c446220f97..7aaa053858 100644 --- a/gapii/cc/BUILD.bazel +++ b/gapii/cc/BUILD.bazel @@ -50,10 +50,7 @@ cc_library( exclude = [ "*_test.cpp", ], - ) + select({ - "//tools/build:darwin": [":osx_opengl_framework"], - "//conditions:default": [], - }) + [ + ) + [ ":apis_compiled", ":vulkan_templated", ], From 18f2cce4b562529206253cbb232d26b55732509d Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 11 Mar 2020 08:29:55 -0700 Subject: [PATCH 0166/1218] Remove GLESisms from test suite --- BUILD.bazel | 4 - gapis/api/BUILD.bazel | 2 - test/integration/gles/replay/BUILD.bazel | 89 ----- test/integration/gles/replay/check.go | 205 ----------- test/integration/gles/replay/clear_test.go | 43 --- test/integration/gles/replay/doc.go | 16 - test/integration/gles/replay/draw_test.go | 52 --- .../gles/replay/fb_texture_test.go | 76 ----- test/integration/gles/replay/gles_test.go | 320 ------------------ test/integration/gles/replay/image.go | 155 --------- test/integration/gles/replay/issues_test.go | 95 ------ .../gles/replay/reference/one-depth.png | Bin 124 -> 0 bytes .../gles/replay/reference/solid-black.png | Bin 148 -> 0 bytes .../gles/replay/reference/solid-blue.png | Bin 158 -> 0 bytes .../gles/replay/reference/solid-green.png | Bin 157 -> 0 bytes .../gles/replay/reference/solid-red.png | Bin 157 -> 0 bytes .../gles/replay/reference/textured-square.png | Bin 414 -> 0 bytes .../gles/replay/reference/triangle-180.png | Bin 274 -> 0 bytes .../gles/replay/reference/triangle-depth.png | Bin 485 -> 0 bytes .../gles/replay/reference/triangle.png | Bin 255 -> 0 bytes .../gles/replay/reference/triangle_2.png | Bin 258 -> 0 bytes .../gles/replay/reference/undef-fb.png | Bin 290 -> 0 bytes test/integration/gles/replay/shaders.go | 64 ---- test/integration/gles/snippets/BUILD.bazel | 37 -- test/integration/gles/snippets/builder.go | 109 ------ .../gles/snippets/clear_backbuffer.go | 44 --- test/integration/gles/snippets/context.go | 87 ----- .../gles/snippets/draw_textured_square.go | 113 ------- test/integration/gles/snippets/shaders.go | 87 ----- test/integration/gles/snippets/snippets.go | 16 - test/integration/service/BUILD.bazel | 4 - test/integration/service/service_test.go | 30 +- test/robot/scheduler/scheduler.go | 2 - 33 files changed, 2 insertions(+), 1648 deletions(-) delete mode 100644 test/integration/gles/replay/BUILD.bazel delete mode 100644 test/integration/gles/replay/check.go delete mode 100644 test/integration/gles/replay/clear_test.go delete mode 100644 test/integration/gles/replay/doc.go delete mode 100644 test/integration/gles/replay/draw_test.go delete mode 100644 test/integration/gles/replay/fb_texture_test.go delete mode 100644 test/integration/gles/replay/gles_test.go delete mode 100644 test/integration/gles/replay/image.go delete mode 100644 test/integration/gles/replay/issues_test.go delete mode 100644 test/integration/gles/replay/reference/one-depth.png delete mode 100644 test/integration/gles/replay/reference/solid-black.png delete mode 100644 test/integration/gles/replay/reference/solid-blue.png delete mode 100644 test/integration/gles/replay/reference/solid-green.png delete mode 100644 test/integration/gles/replay/reference/solid-red.png delete mode 100644 test/integration/gles/replay/reference/textured-square.png delete mode 100644 test/integration/gles/replay/reference/triangle-180.png delete mode 100644 test/integration/gles/replay/reference/triangle-depth.png delete mode 100644 test/integration/gles/replay/reference/triangle.png delete mode 100644 test/integration/gles/replay/reference/triangle_2.png delete mode 100644 test/integration/gles/replay/reference/undef-fb.png delete mode 100644 test/integration/gles/replay/shaders.go delete mode 100644 test/integration/gles/snippets/BUILD.bazel delete mode 100644 test/integration/gles/snippets/builder.go delete mode 100644 test/integration/gles/snippets/clear_backbuffer.go delete mode 100644 test/integration/gles/snippets/context.go delete mode 100644 test/integration/gles/snippets/draw_textured_square.go delete mode 100644 test/integration/gles/snippets/shaders.go delete mode 100644 test/integration/gles/snippets/snippets.go diff --git a/BUILD.bazel b/BUILD.bazel index 46b9993d01..e121661e33 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -312,7 +312,6 @@ test_suite( name = "tests-gapis-api", tests = [ "//gapis/api:go_default_test", - "//gapis/api/gles:go_default_test", "//gapis/api/test:go_default_test", "//gapis/api/transform:go_default_test", "//gapis/api/vulkan:go_default_test", @@ -357,7 +356,6 @@ test_suite( test_suite( name = "tests-general", tests = [ - "//test/integration/gles/replay:go_default_test", "//test/integration/replay:go_default_test", "//test/integration/service:go_default_test", "//test/robot/stash/grpc:go_default_test", @@ -438,7 +436,6 @@ test_suite( "//gapil/validate:go_default_test", "//gapir/cc:tests", "//gapis/api:go_default_test", - "//gapis/api/gles:go_default_test", "//gapis/api/test:go_default_test", "//gapis/api/transform:go_default_test", "//gapis/api/vulkan:go_default_test", @@ -458,7 +455,6 @@ test_suite( "//gapis/stringtable/minidown/scanner:go_default_test", "//gapis/stringtable/parser:go_default_test", "//gapis/vertex:go_default_test", - "//test/integration/gles/replay:go_default_test", "//test/integration/replay:go_default_test", "//test/integration/service:go_default_test", "//test/robot/stash/grpc:go_default_test", diff --git a/gapis/api/BUILD.bazel b/gapis/api/BUILD.bazel index 5f26c04ec1..e855b0fa05 100644 --- a/gapis/api/BUILD.bazel +++ b/gapis/api/BUILD.bazel @@ -122,7 +122,6 @@ proto_library( "//core/image:image_proto", "//gapis/service/box:box_proto", "//gapis/service/path:path_proto", - "//gapis/service/types:types_proto", "//gapis/vertex:vertex_proto", ], ) @@ -143,7 +142,6 @@ go_proto_library( "//core/image:go_default_library", "//gapis/service/box:go_default_library", "//gapis/service/path:go_default_library", - "//gapis/service/types:go_default_library", "//gapis/vertex:go_default_library", ], ) diff --git a/test/integration/gles/replay/BUILD.bazel b/test/integration/gles/replay/BUILD.bazel deleted file mode 100644 index a5ace53eda..0000000000 --- a/test/integration/gles/replay/BUILD.bazel +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("//tools/build:rules.bzl", "embed") - -embed( - name = "embed", - srcs = glob([ - "reference/*.png", - ]), -) - -go_library( - name = "go_default_library", - srcs = [ - "check.go", - "doc.go", - "image.go", - "shaders.go", - ":embed", # keep - ], - importpath = "github.com/google/gapid/test/integration/gles/replay", - visibility = ["//visibility:public"], - deps = [ - "//core/assert:go_default_library", - "//core/data/endian:go_default_library", - "//core/event/task:go_default_library", - "//core/image:go_default_library", - "//core/log:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//core/stream:go_default_library", - "//gapis/api:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/replay:go_default_library", - "//gapis/resolve:go_default_library", - "//gapis/service:go_default_library", - "//gapis/service/path:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = [ - "clear_test.go", - "draw_test.go", - "fb_texture_test.go", - "gles_test.go", - "issues_test.go", - ], - data = [ - "//cmd/gapir/cc:gapir", - "//core/vulkan/vk_virtual_swapchain/cc:json", - "//core/vulkan/vk_virtual_swapchain/cc:libVkLayer_VirtualSwapchain", - ], - embed = [":go_default_library"], - tags = [ - "integration", - "manual", - "needs_gpu", - ], - deps = [ - "//core/assert:go_default_library", - "//core/log:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//gapis/api:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/database:go_default_library", - "//gapis/memory:go_default_library", - "//gapis/replay:go_default_library", - "//gapis/resolve:go_default_library", - "//gapis/service/path:go_default_library", - "//test/integration/gles/snippets:go_default_library", - ], -) diff --git a/test/integration/gles/replay/check.go b/test/integration/gles/replay/check.go deleted file mode 100644 index 69d8654fd7..0000000000 --- a/test/integration/gles/replay/check.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "context" - "fmt" - "sync" - - "github.com/google/gapid/core/os/device" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" -) - -type intentCfg struct { - intent replay.Intent - config replay.Config -} - -func (c intentCfg) String() string { - return fmt.Sprintf("Context: %+v, Config: %+v", c.intent, c.config) -} - -func checkImage(ctx context.Context, name string, got *image.Data, threshold float64) { - if *generateReferenceImages != "" { - storeReferenceImage(ctx, *generateReferenceImages, name, got) - } else { - quantized := quantizeImage(got) - expected := loadReferenceImage(ctx, name) - diff, err := image.Difference(quantized, expected) - assert.For(ctx, "CheckImage").ThatError(err).Succeeded() - assert.For(ctx, "CheckImage").ThatFloat(float64(diff)).IsAtMost(threshold) - } -} - -func checkIssues(ctx context.Context, c *path.Capture, d *device.Instance, expected []replay.Issue, done *sync.WaitGroup) { - mgr := replay.GetManager(ctx) - if done != nil { - defer done.Done() - } - ctx, _ = task.WithTimeout(ctx, replayTimeout) - intent := replay.Intent{ - Capture: c, - Device: path.NewDevice(d.ID.ID()), - } - issues, err := gles.API{}.QueryIssues(ctx, intent, mgr, 1, false, nil) - if assert.For(ctx, "err").ThatError(err).Succeeded() { - assert.For(ctx, "issues").ThatSlice(issues).DeepEquals(expected) - } -} - -func checkReport(ctx context.Context, c *path.Capture, d *device.Instance, cmds []api.Cmd, expected []string, done *sync.WaitGroup) { - if done != nil { - defer done.Done() - } - - report, err := resolve.Report(ctx, c.Report(path.NewDevice(d.ID.ID()), nil, false), nil) - assert.For(ctx, "err").ThatError(err).Succeeded() - - got := []string{} - for _, e := range report.Items { - if e.Command != nil { - got = append(got, fmt.Sprintf("%s@%d: %s: %v", e.Severity.String(), e.Command.Indices, cmds[e.Command.Indices[0]], report.Msg(e.Message).Text(nil))) - } else { - got = append(got, fmt.Sprintf("%s /%v", e.Severity.String(), report.Msg(e.Message).Text(nil))) - } - } - assert.For(ctx, "got").ThatSlice(got).Equals(expected) -} - -func checkColorBuffer(ctx context.Context, c *path.Capture, d *device.Instance, w, h uint32, threshold float64, name string, after api.CmdID, done *sync.WaitGroup) { - mgr := replay.GetManager(ctx) - ctx = log.Enter(ctx, "ColorBuffer") - ctx = log.V{"name": name, "after": after}.Bind(ctx) - if done != nil { - defer done.Done() - } - ctx, _ = task.WithTimeout(ctx, replayTimeout) - intent := replay.Intent{ - Capture: c, - Device: path.NewDevice(d.ID.ID()), - } - img, err := gles.API{}.QueryFramebufferAttachment( - ctx, intent, mgr, []uint64{uint64(after)}, w, h, api.FramebufferAttachment_Color0, 0, service.DrawMode_NORMAL, false, false, nil) - if !assert.For(ctx, "err").ThatError(err).Succeeded() { - return - } - checkImage(ctx, name, img, threshold) -} - -func checkTextureBuffer(ctx context.Context, c *path.Capture, d *device.Instance, w, h uint32, threshold float64, name string, after api.CmdID, tex gles.TextureId, done *sync.WaitGroup) { - ctx = log.Enter(ctx, "TextureBuffer") - ctx = log.V{"name": name, "after": after}.Bind(ctx) - if done != nil { - defer done.Done() - } - ctx, _ = task.WithTimeout(ctx, replayTimeout) - - cmdPath := c.Command(uint64(after)) - - cmd, err := resolve.Cmd(ctx, cmdPath, nil) - if !assert.For(ctx, "resolve cmd").ThatError(err).Succeeded() { - return - } - - thread := cmd.Thread() - - globalState, err := resolve.GlobalState(ctx, cmdPath.GlobalStateAfter(), nil) - if !assert.For(ctx, "resolve global state").ThatError(err).Succeeded() { - return - } - - state := gles.GetState(globalState) - - context, ok := state.Contexts().Lookup(thread) - if !assert.For(ctx, "lookup context").That(ok).Equals(true) { - return - } - - t := context.Objects().Textures().Get(tex) - if !assert.For(ctx, "texture found").That(!t.IsNil()).Equals(true) { - return - } - - res, err := t.ResourceData(ctx, globalState, cmdPath) - if !assert.For(ctx, "resource data").ThatError(err).Succeeded() { - return - } - - imginfo := res.GetTexture().GetTexture_2D().GetLevels()[0] - - img, err := imginfo.Data(ctx) - if !assert.For(ctx, "image data").ThatError(err).Succeeded() { - return - } - - checkImage(ctx, name, img, threshold) -} - -func checkDepthBuffer(ctx context.Context, c *path.Capture, d *device.Instance, w, h uint32, threshold float64, name string, after api.CmdID, done *sync.WaitGroup) { - mgr := replay.GetManager(ctx) - ctx = log.Enter(ctx, "DepthBuffer") - ctx = log.V{"name": name, "after": after}.Bind(ctx) - if done != nil { - defer done.Done() - } - ctx, _ = task.WithTimeout(ctx, replayTimeout) - intent := replay.Intent{ - Capture: c, - Device: path.NewDevice(d.ID.ID()), - } - img, err := gles.API{}.QueryFramebufferAttachment( - ctx, intent, mgr, []uint64{uint64(after)}, w, h, api.FramebufferAttachment_Depth, 0, service.DrawMode_NORMAL, false, false, nil) - if !assert.For(ctx, "err").ThatError(err).Succeeded() { - return - } - checkImage(ctx, name, img, threshold) -} - -func checkReplay(ctx context.Context, c *path.Capture, d *device.Instance, expectedBatchCount int, doReplay func()) { - expectedIntent := replay.Intent{ - Capture: c, - Device: path.NewDevice(d.ID.ID()), - } - - batchCount := 0 - uniqueIntentConfigs := map[intentCfg]struct{}{} - replay.Events.OnReplay = func(device bind.Device, intent replay.Intent, config replay.Config) { - assert.For(ctx, "Replay intent").That(intent).DeepEquals(expectedIntent) - batchCount++ - uniqueIntentConfigs[intentCfg{intent, config}] = struct{}{} - } - - doReplay() - - replay.Events.OnReplay = nil // Avoid stale assertions in subsequent tests that don't use checkReplay. - if assert.For(ctx, "Batch count").That(batchCount).Equals(expectedBatchCount) { - log.I(ctx, "%d unique intent-config pairs:", len(uniqueIntentConfigs)) - for cc := range uniqueIntentConfigs { - log.I(ctx, " • %v", cc) - } - } -} diff --git a/test/integration/gles/replay/clear_test.go b/test/integration/gles/replay/clear_test.go deleted file mode 100644 index bd3e6ec6fd..0000000000 --- a/test/integration/gles/replay/clear_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "sync" - "testing" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/integration/gles/snippets" -) - -func TestClear(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, false) - - red, green, blue, black := b.ClearBackbuffer(ctx) - c := buildAndMaybeExportCapture(ctx, b, "clear") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - done := &sync.WaitGroup{} - done.Add(4) - go checkColorBuffer(ctx, c, d, 64, 64, 0, "solid-red", red, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0, "solid-green", green, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0, "solid-blue", blue, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0, "solid-black", black, done) - done.Wait() - }) -} diff --git a/test/integration/gles/replay/doc.go b/test/integration/gles/replay/doc.go deleted file mode 100644 index 7994de0083..0000000000 --- a/test/integration/gles/replay/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package replay contains the OpenGL ES integration tests with the replay system. -package replay diff --git a/test/integration/gles/replay/draw_test.go b/test/integration/gles/replay/draw_test.go deleted file mode 100644 index 867a738d94..0000000000 --- a/test/integration/gles/replay/draw_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "testing" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/integration/gles/snippets" -) - -func TestDrawTexturedSquare(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(128, 128, false, false) - draw, _ := b.DrawTexturedSquare(ctx) - c := buildAndMaybeExportCapture(ctx, b, "textured-square") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkColorBuffer(ctx, c, d, 128, 128, 0.01, "textured-square", draw, nil) - }) -} - -func TestDrawTexturedSquareWithSharedContext(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(128, 128, true, false) - draw, _ := b.DrawTexturedSquare(ctx) - c := buildAndMaybeExportCapture(ctx, b, "textured-square-shared-context") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkColorBuffer(ctx, c, d, 128, 128, 0.01, "textured-square", draw, nil) - }) -} - -func TestDrawTriangle(t *testing.T) { - test(t, "draw-triangle", generateDrawTriangleCapture) -} diff --git a/test/integration/gles/replay/fb_texture_test.go b/test/integration/gles/replay/fb_texture_test.go deleted file mode 100644 index c3e27d5d16..0000000000 --- a/test/integration/gles/replay/fb_texture_test.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "testing" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/test/integration/gles/snippets" -) - -func TestClearFramebuffer(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, false) - - tex := gles.TextureId(10) - fbo := gles.FramebufferId(20) - - texR := b.Data(ctx, tex) - fboR := b.Data(ctx, fbo) - - b.Add( - b.CB.GlGenTextures(1, texR.Ptr()).AddRead(texR.Data()), - b.CB.GlBindTexture(gles.GLenum_GL_TEXTURE_2D, tex), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_WRAP_S, gles.GLint(gles.GLenum_GL_CLAMP_TO_EDGE)), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_WRAP_T, gles.GLint(gles.GLenum_GL_CLAMP_TO_EDGE)), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MAG_FILTER, gles.GLint(gles.GLenum_GL_LINEAR)), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MIN_FILTER, gles.GLint(gles.GLenum_GL_LINEAR)), - b.CB.GlTexImage2D( - gles.GLenum_GL_TEXTURE_2D, - 0, - gles.GLint(gles.GLenum_GL_RGBA), - 64, 64, 0, - gles.GLenum_GL_RGBA, - gles.GLenum_GL_UNSIGNED_BYTE, - memory.Nullptr), - - b.CB.GlGenFramebuffers(1, fboR.Ptr()).AddRead(fboR.Data()), - b.CB.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, fbo), - b.CB.GlFramebufferTexture2D( - gles.GLenum_GL_FRAMEBUFFER, - gles.GLenum_GL_COLOR_ATTACHMENT0, - gles.GLenum_GL_TEXTURE_2D, - tex, - 0), - - b.CB.GlBindFramebuffer(gles.GLenum_GL_FRAMEBUFFER, fbo), - ) - clear := b.ClearColor(1, 0, 0, 1) - - c := b.Capture(ctx, "clear-framebuffer") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkColorBuffer(ctx, c, d, 64, 64, 0, "solid-red", clear, nil) - }) - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkTextureBuffer(ctx, c, d, 64, 64, 0, "solid-red", clear, tex, nil) - }) -} diff --git a/test/integration/gles/replay/gles_test.go b/test/integration/gles/replay/gles_test.go deleted file mode 100644 index aea38e2310..0000000000 --- a/test/integration/gles/replay/gles_test.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "bytes" - "context" - "flag" - "math" - "os" - "path/filepath" - "sync" - "testing" - "time" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/service/path" - "github.com/google/gapid/test/integration/gles/snippets" -) - -const replayTimeout = time.Second * 5 - -var ( - triangleVertices = []float32{ - +0.0, -0.5, 0.1, - -0.5, +0.5, 0.5, - +0.5, +0.5, 0.9, - } - - squareVertices = []float32{ - -0.5, -0.5, 0.5, - -0.5, +0.5, 0.5, - +0.5, +0.5, 0.5, - +0.5, -0.5, 0.5, - } - - squareIndices = []uint16{ - 0, 1, 2, 0, 2, 3, - } - - generateReferenceImages = flag.String("generate", "", "directory in which to generate reference images, empty to disable") - exportCaptures = flag.String("export-captures", "", "directory to export captures to, empty to disable") -) - -func TestMain(m *testing.M) { - flag.Parse() - os.Exit(m.Run()) -} - -func setup(ctx context.Context) (context.Context, *device.Instance) { - r := bind.NewRegistry() - ctx = bind.PutRegistry(ctx, r) - m := replay.New(ctx) - ctx = replay.PutManager(ctx, m) - ctx = database.Put(ctx, database.NewInMemory(ctx)) - bind.GetRegistry(ctx).AddDevice(ctx, bind.Host(ctx)) - return ctx, r.DefaultDevice().Instance() -} - -func buildAndMaybeExportCapture(ctx context.Context, b *snippets.Builder, name string) *path.Capture { - c := b.Capture(ctx, name) - maybeExportCapture(ctx, c) - return c -} - -func maybeExportCapture(ctx context.Context, c *path.Capture) { - if *exportCaptures == "" { - return - } - cap, err := capture.ResolveFromPath(ctx, c) - assert.For(ctx, "err").ThatError(err).Succeeded() - f, err := os.Create(filepath.Join(*exportCaptures, cap.Name()+".gfxtrace")) - assert.For(ctx, "err").ThatError(err).Succeeded() - defer f.Close() - err = capture.Export(ctx, c, f) - assert.For(ctx, "err").ThatError(err).Succeeded() -} - -func p(addr uint64) memory.Pointer { return memory.BytePtr(addr) } - -type verifier func(context.Context, *path.Capture, *device.Instance) -type generator func(context.Context, *device.Instance) (*path.Capture, verifier) - -// mergeCaptures creates a capture from the cmds of several existing captures, -// by interleaving them arbitrarily, on different threads. -func mergeCaptures(ctx context.Context, captures ...*path.Capture) *path.Capture { - lists := [][]api.Cmd{} - threads := []uint64{} - remainingCmds := 0 - - if len(captures) == 0 { - panic("mergeCaptures requires at least one capture") - } - - var d *device.Instance - for i, path := range captures { - c, err := capture.ResolveFromPath(ctx, path) - assert.For(ctx, "err").ThatError(err).Succeeded() - gc := c.(*capture.GraphicsCapture) - lists = append(lists, gc.Commands) - remainingCmds += len(gc.Commands) - threads = append(threads, uint64(0x10000+i)) - if i == 0 { - d = gc.Header.Device - } - } - - merged := snippets.NewBuilder(ctx, d) - threadIndex := 0 - cmdsUntilSwitchThread, modFourCounter := 4, 3 - for remainingCmds > 0 { - if cmdsUntilSwitchThread > 0 && len(lists[threadIndex]) > 0 { - cmd := lists[threadIndex][0] - cmd.SetThread(threads[threadIndex]) - merged.Add(cmd) - lists[threadIndex] = lists[threadIndex][1:] - remainingCmds-- - cmdsUntilSwitchThread-- - } else { - threadIndex = (threadIndex + 1) % len(lists) - for len(lists[threadIndex]) == 0 { - threadIndex = (threadIndex + 1) % len(lists) - } - // We don't want to always switch threads after the same number of commands, - // but we want it to be predictable. This should do. - cmdsUntilSwitchThread = 2 + modFourCounter - modFourCounter = (modFourCounter + 1) % 4 - } - } - return merged.Capture(ctx, "merged") -} - -func generateDrawTriangleCapture(ctx context.Context, d *device.Instance) (*path.Capture, verifier) { - return generateDrawTriangleCaptureEx(ctx, d, - 0.0, 1.0, 0.0, - 1.0, 0.0, 0.0) -} - -// generateDrawTriangleCaptureEx generates a capture with several frames containing -// a rotating triangle of color RGB(fr, fg, fb) on a RGB(br, bg, bb) background. -func generateDrawTriangleCaptureEx(ctx context.Context, d *device.Instance, - br, bg, bb gles.GLfloat, - fr, fg, fb gles.GLfloat) (*path.Capture, verifier) { - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, false) - - b.Add(b.CB.GlEnable(gles.GLenum_GL_DEPTH_TEST)) // Required for depth-writing - b.ClearColor(br, bg, bb, 1.0) - clear := b.ClearDepth() - - prog := b.CreateProgram(ctx, simpleVSSource, simpleFSSource(fr, fg, fb)) - angleLoc := b.AddUniformSampler(ctx, prog, "angle") - posLoc := b.AddAttributeVec3(ctx, prog, "position") - - triangleVerticesR := b.Data(ctx, triangleVertices) - - b.Add( - b.CB.GlUseProgram(prog), - b.CB.GlUniform1f(angleLoc, gles.GLfloat(0)), - b.CB.GlEnableVertexAttribArray(posLoc), - b.CB.GlVertexAttribPointer(posLoc, 3, gles.GLenum_GL_FLOAT, gles.GLboolean(0), 0, triangleVerticesR.Ptr()), - b.CB.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 3).AddRead(triangleVerticesR.Data()), - ) - triangle := b.Last() - - angle := 0.0 - for i := 0; i < 30; i++ { - angle += math.Pi / 30.0 - b.SwapBuffers() - b.Add( - b.CB.GlUniform1f(angleLoc, gles.GLfloat(angle)), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT|gles.GLbitfield_GL_DEPTH_BUFFER_BIT), - b.CB.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 3).AddRead(triangleVerticesR.Data()), - ) - } - rotatedTriangle := b.Last() - - verify := func(ctx context.Context, c *path.Capture, d *device.Instance) { - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - done := &sync.WaitGroup{} - done.Add(5) - go checkColorBuffer(ctx, c, d, 64, 64, 0.0, "solid-green", clear, done) - go checkDepthBuffer(ctx, c, d, 64, 64, 0.0, "one-depth", clear, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0.01, "triangle", triangle, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0.01, "triangle-180", rotatedTriangle, done) - go checkDepthBuffer(ctx, c, d, 64, 64, 0.01, "triangle-depth", triangle, done) - done.Wait() - }) - } - - return buildAndMaybeExportCapture(ctx, b, "draw-triangle"), verify -} - -func test(t *testing.T, name string, tg generator) { - ctx, d := setup(log.Testing(t)) - c, verify := tg(ctx, d) - verify(ctx, c, d) -} - -func TestMultiContextCapture(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - t1, _ := generateDrawTriangleCaptureEx(ctx, d, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0) - t2, _ := generateDrawTriangleCaptureEx(ctx, d, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - t3, _ := generateDrawTriangleCaptureEx(ctx, d, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0) - c := mergeCaptures(ctx, t1, t2, t3) - maybeExportCapture(ctx, c) - - contexts, err := resolve.Contexts(ctx, c.Contexts(), nil) - assert.For(ctx, "err").ThatError(err).Succeeded() - assert.For(ctx, "len").That(len(contexts)).Equals(3) -} - -func TestExportAndImportCapture(t *testing.T) { - ctx, d := setup(log.Testing(t)) - c, verify := generateDrawTriangleCapture(ctx, d) - - var exported bytes.Buffer - err := capture.Export(ctx, c, &exported) - assert.For(ctx, "err").ThatError(err).Succeeded() - - ctx, d = setup(log.Testing(t)) - src := &capture.Blob{Data: exported.Bytes()} - recoveredCapture, err := capture.Import(ctx, "key", "recovered", src) - assert.For(ctx, "err").ThatError(err).Succeeded() - verify(ctx, recoveredCapture, d) -} - -// TestResizeRenderer checks that backbuffers can be resized without destroying -// the current context. -func TestResizeRenderer(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(8, 8, false, false) // start with a small backbuffer - - triangleVerticesR := b.Data(ctx, triangleVertices) - - prog := b.CreateProgram(ctx, simpleVSSource, simpleFSSource(1.0, 0.0, 0.0)) - posLoc := b.AddAttributeVec3(ctx, prog, "position") - - b.Add( - b.CB.GlUseProgram(prog), - b.CB.GlEnableVertexAttribArray(posLoc), - b.CB.GlVertexAttribPointer(posLoc, 3, gles.GLenum_GL_FLOAT, gles.GLboolean(0), 0, triangleVerticesR.Ptr()), - ) - - b.ResizeBackbuffer(64, 64) - b.Add(b.CB.GlViewport(0, 0, 64, 64)) - b.ClearColor(0, 0, 1, 1) - triangle := b.Add(b.CB.GlDrawArrays(gles.GLenum_GL_TRIANGLES, 0, 3).AddRead(triangleVerticesR.Data())) - c := buildAndMaybeExportCapture(ctx, b, "resize-renderer") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkColorBuffer(ctx, c, d, 64, 64, 0.01, "triangle_2", triangle, nil) - }) -} - -// TestNewContextUndefined checks that a new context is filled with the -// undefined framebuffer pattern. -func TestNewContextUndefined(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, false) - makeCurrent := b.Last() - c := buildAndMaybeExportCapture(ctx, b, "new-context-undefined") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkColorBuffer(ctx, c, d, 64, 64, 0.01, "undef-fb", makeCurrent, nil) - }) -} - -// TestPreserveBuffersOnSwap checks that when the preserveBuffersOnSwap flag is -// set, the backbuffer is preserved between calls to eglSwapBuffers(). -func TestPreserveBuffersOnSwap(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, true) - - clear := b.ClearColor(0, 0, 1, 1) - swapA := b.SwapBuffers() - swapB := b.SwapBuffers() - swapC := b.SwapBuffers() - c := buildAndMaybeExportCapture(ctx, b, "preserve-buffers-on-swap") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - done := &sync.WaitGroup{} - done.Add(4) - go checkColorBuffer(ctx, c, d, 64, 64, 0.0, "solid-blue", clear, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0.0, "solid-blue", swapA, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0.0, "solid-blue", swapB, done) - go checkColorBuffer(ctx, c, d, 64, 64, 0.0, "solid-blue", swapC, done) - done.Wait() - }) -} diff --git a/test/integration/gles/replay/image.go b/test/integration/gles/replay/image.go deleted file mode 100644 index 8046af6b92..0000000000 --- a/test/integration/gles/replay/image.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "bytes" - "context" - "encoding/base64" - "fmt" - goimg "image" - "image/color" - "image/png" - "io/ioutil" - "os" - "path/filepath" - - "github.com/google/gapid/core/data/endian" - gpuimg "github.com/google/gapid/core/image" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/stream" -) - -// storeReferenceImage replaces the reference image with img. -func storeReferenceImage(ctx context.Context, outputDir string, name string, img *gpuimg.Data) { - ctx = log.V{"name": name}.Bind(ctx) - data := &bytes.Buffer{} - i, err := toGoImage(img) - if err != nil { - log.F(ctx, true, "Failed to convert GPU image to Go image: %v", err) - } - if err := png.Encode(data, i); err != nil { - log.F(ctx, true, "Failed to encode reference image: %v", err) - } - if err := os.MkdirAll(outputDir, 0755); err != nil { - log.F(ctx, true, "Failed to create reference image directory: %v", err) - } - path := filepath.Join(outputDir, name+".png") - if err := ioutil.WriteFile(path, data.Bytes(), 0666); err != nil { - log.F(ctx, true, "Failed to store reference image: %v", err) - } -} - -// loadReferenceImage loads the reference image with the specified name. -func loadReferenceImage(ctx context.Context, name string) *gpuimg.Data { - ctx = log.V{"name": name}.Bind(ctx) - b64, found := embedded[name+".png"] - if !found { - log.F(ctx, true, "Embedded reference image '%s' not found", name) - } - data, err := base64.StdEncoding.DecodeString(b64) - if err != nil { - log.F(ctx, true, "Failed to load reference image: %v", err) - } - img, err := png.Decode(bytes.NewBuffer(data)) - if err != nil { - log.F(ctx, true, "Failed to decode reference image: %v", err) - } - out, err := toGPUImage(img) - if err != nil { - log.F(ctx, true, "Failed to convert Go image to GPU image: %v", err) - } - return out -} - -func toGoImage(in *gpuimg.Data) (goimg.Image, error) { - rect := goimg.Rect(0, 0, int(in.Width), int(in.Height)) - switch in.Format.Key() { - case gpuimg.RGBA_U8_NORM.Key(): - out := goimg.NewNRGBA(rect) - out.Pix = in.Bytes - return out, nil - - case gpuimg.D_U16_NORM.Key(): - out := goimg.NewGray16(rect) - out.Pix = make([]byte, len(in.Bytes)) - // Endian-swap. - for i, c := 0, len(in.Bytes); i < c; i += 2 { - out.Pix[i+0], out.Pix[i+1] = in.Bytes[i+1], in.Bytes[i+0] - } - return out, nil - - default: - uncompressed := in.Format.GetUncompressed() - var converted *gpuimg.Data - var err error - if depth, _ := uncompressed.Format.Component(stream.Channel_Depth); depth != nil { - converted, err = in.Convert(gpuimg.D_U16_NORM) - } else { - converted, err = in.Convert(gpuimg.RGBA_U8_NORM) - } - if err != nil { - return nil, err - } - return toGoImage(converted) - } -} - -func toGPUImage(in goimg.Image) (*gpuimg.Data, error) { - w, h := in.Bounds().Dx(), in.Bounds().Dy() - out := &gpuimg.Data{Width: uint32(w), Height: uint32(h), Depth: 1} - buf := &bytes.Buffer{} - e := endian.Writer(buf, device.BigEndian) - - switch in.ColorModel() { - case color.RGBAModel, color.NRGBAModel: - out.Format = gpuimg.RGBA_U8_NORM - for y := 0; y < h; y++ { - for x := 0; x < w; x++ { - r, g, b, a := in.At(x, y).RGBA() - e.Uint8(uint8(r >> 8)) - e.Uint8(uint8(g >> 8)) - e.Uint8(uint8(b >> 8)) - e.Uint8(uint8(a >> 8)) - } - } - case color.Gray16Model: - out.Format = gpuimg.D_U16_NORM - for y := 0; y < h; y++ { - for x := 0; x < w; x++ { - d, _, _, _ := in.At(x, y).RGBA() - e.Uint16(uint16(d)) - } - } - default: - return nil, fmt.Errorf("Unsupported color model %v", in.ColorModel()) - } - - out.Bytes = buf.Bytes() - return out, nil -} - -func quantizeImage(in *gpuimg.Data) *gpuimg.Data { - tmp, err := toGoImage(in) - if err != nil { - panic(err) - } - out, err := toGPUImage(tmp) - if err != nil { - panic(err) - } - return out -} diff --git a/test/integration/gles/replay/issues_test.go b/test/integration/gles/replay/issues_test.go deleted file mode 100644 index cffb8c323a..0000000000 --- a/test/integration/gles/replay/issues_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "testing" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/replay" - "github.com/google/gapid/test/integration/gles/snippets" -) - -// TestNoIssues tests the QueryIssues replay command returns with no issues for -// a clean capture. -func TestNoIssues(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, true) - b.Add( - b.CB.GlClearColor(0.0, 0.0, 1.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) - c := buildAndMaybeExportCapture(ctx, b, "issues") - - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkIssues(ctx, c, d, []replay.Issue{}, nil) - }) -} - -// TestWithIssues tests the QueryIssues replay command returns expected issues. -func TestWithIssues(t *testing.T) { - ctx, d := setup(log.Testing(t)) - - b := snippets.NewBuilder(ctx, d) - b.CreateContext(64, 64, false, false) - - missingProg := gles.ProgramId(1234) - - textureNames := []gles.TextureId{1} - textureNamesR := b.Data(ctx, textureNames) - - squareIndicesR := b.Data(ctx, squareIndices) - squareVerticesR := b.Data(ctx, squareVertices) - - someString := b.Data(ctx, "hello world") - - prog := b.CreateProgram(ctx, textureVSSource, textureFSSource) - texLoc := b.AddUniformSampler(ctx, prog, "tex") - posLoc := b.AddAttributeVec3(ctx, prog, "position") - - b.Add( - b.CB.GlEnable(gles.GLenum_GL_DEPTH_TEST), // Required for depth-writing - b.CB.GlClearColor(0.0, 1.0, 0.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT|gles.GLbitfield_GL_2X_BIT_ATI), // INVALID - b.CB.GlUseProgram(missingProg), // INVALID - b.CB.GlLabelObjectEXT(gles.GLenum_GL_TEXTURE, 123, gles.GLsizei(someString.Range().Size), someString.Ptr()).AddRead(someString.Data()), // INVALID - b.CB.GlGetError(0), - b.CB.GlUseProgram(prog), - b.CB.GlGenTextures(1, textureNamesR.Ptr()).AddWrite(textureNamesR.Data()), - b.CB.GlActiveTexture(gles.GLenum_GL_TEXTURE0), - b.CB.GlBindTexture(gles.GLenum_GL_TEXTURE_2D, textureNames[0]), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MIN_FILTER, gles.GLint(gles.GLenum_GL_NEAREST)), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MAG_FILTER, gles.GLint(gles.GLenum_GL_NEAREST)), - b.CB.GlUniform1i(texLoc, 0), - b.CB.GlEnableVertexAttribArray(posLoc), - b.CB.GlVertexAttribPointer(posLoc, 3, gles.GLenum_GL_FLOAT, gles.GLboolean(0), 0, squareVerticesR.Ptr()), - b.CB.GlDrawElements(gles.GLenum_GL_TRIANGLES, 6, gles.GLenum_GL_UNSIGNED_SHORT, squareIndicesR.Ptr()). - AddRead(squareIndicesR.Data()). - AddRead(squareVerticesR.Data()), - ) - b.SwapBuffers() - - c := buildAndMaybeExportCapture(ctx, b, "with-issues") - checkReplay(ctx, c, d, 1, func() { // expect a single replay batch. - checkReport(ctx, c, d, b.Cmds, []string{ - "ErrorLevel@[18]: glClear(mask: GLbitfield(16385)): ", - "ErrorLevel@[19]: glUseProgram(program: 1234): ", - "ErrorLevel@[20]: glLabelObjectEXT(type: GL_TEXTURE, object: 123, length: 12, label: 4216): ", - }, nil) - }) -} diff --git a/test/integration/gles/replay/reference/one-depth.png b/test/integration/gles/replay/reference/one-depth.png deleted file mode 100644 index 0ab154bb4029f9ef3173fefec20b07326a643c07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^4j?Q5BpB{b`s4_toIPC}Ln`LHIp@gBU?6aKLzYzi vDO-uZ7A%kMr`@{!juE63H<-lD!0`Y7#obJezk|IaK0 diff --git a/test/integration/gles/replay/reference/solid-red.png b/test/integration/gles/replay/reference/solid-red.png deleted file mode 100644 index 99fa0ddbdb3d76e6f6f2bbf3149a590952684294..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGJM6i*k&kcv5P&IfWbD2NwZqn{*hAO@Yi}y6kb!e{jd7B{e3}}F98>Pm1{6%#P7gs y)eP5I@VozpjJN#5TfdsvDDy5?gDo(u|NlRAl)b)N@dzl~89ZJ6T-G@yGywqc=YPil diff --git a/test/integration/gles/replay/reference/triangle-180.png b/test/integration/gles/replay/reference/triangle-180.png deleted file mode 100644 index da5174fe4bf00fdd5fa6856e92989ebcf19c99a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGJMo1QL?Ar*7p%zDdp$biQ+{O0fd zpI8zf9be`>xq#F1`TmXH<(6jO+?C^*}w@+$TCI=@RGF)0nU6 zpOB0Dr*0yw;CblIjcIH~Dn9&gvJ}Fa(nFG&1BK=|S4n^P{=EFgy@usSC+rtslk+K& z+}fLvaQsTf1HHaRalLO+zg4;$%l~bYuA6Y+fVjQYISZfU2OWo(O@3!&P;kioe&zQ{ z35(}9t6r66RWdhU&pjgGz{_|AnehF|@Ez!{|Nr+GC^d1#{|p9l7(8A5T-G@yGywoD C@oql= diff --git a/test/integration/gles/replay/reference/triangle-depth.png b/test/integration/gles/replay/reference/triangle-depth.png deleted file mode 100644 index e662b92848fe6236af9d5caf382f4c64bb1d3dcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 485 zcmV{lXh`(a&vO?3sjnG zN>UT^-aDHjzCg=ca{awO$$x2YFik6BlzvL;|}C%rF6M45v^aO+yItJ`p7{?z7XKpj?5HQ-mLQv100S>+P<@m#NnQbr#EWoh;s!u?eI2QwO z)X(>?A>8<%XJymx^NIQjMhmI?Q6ZQ20cuzN94JCO)D&7d*QKX=b zzzri+r{7EmMIQ@RiF^DMVDC54oA4u7%JS+~hhOJ^J#5zH7O{<&u)e+C;brr=#>bog ki#MUUAVZIlf#Lsu(O{*9@)v900DZ*Z>FVdQ&MBb@0GAwL8vplD@rGt{&VoXk2jG7!{V`-)A@gzYmdKlRu|Z{JJN6ddm+B*x!q4o zY$T6mSnj>&FMfJu$Jy5@mPe28?fAR3Zo)NjN!z`v`{io;e|_#=vvm7e`<^-X?skCq zwo6vaACp+}b!uM5%h=j4FRHK1uYb1X%hPZVzxPQmE`DEezrW<`XDims+NIJ_RpIis zzvRBYVb{B6Zt~Q%f8O7QCHod?>Q{Yv!>$50LVDJxMegV89D?p&m?Cal^^JMbFE8^g lUwC~hFUBwX&&t5?|NpujG8#T_Zh}IC!PC{xWt~$(695RPg<}8! diff --git a/test/integration/gles/replay/shaders.go b/test/integration/gles/replay/shaders.go deleted file mode 100644 index bef01aac75..0000000000 --- a/test/integration/gles/replay/shaders.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "fmt" - - "github.com/google/gapid/gapis/api/gles" -) - -const ( - simpleVSSource = ` -precision mediump float; -attribute vec3 position; -uniform float angle; - -void main() { - float c = cos(angle); - float s = sin(angle); - mat3 rotation = mat3(vec3(c, -s, 0.0), vec3(s, c, 0.0), vec3(0.0, 0.0, 1.0)); - gl_Position = vec4(rotation * position, 1.0); -}` - - textureVSSource = ` -precision mediump float; -attribute vec3 position; -varying vec2 texcoord; -void main() { - gl_Position = vec4(position, 1.0); - texcoord = position.xy + vec2(0.5, 0.5); -}` - - textureFSSource = ` -precision mediump float; -uniform sampler2D tex; -varying vec2 texcoord; -void main() { - gl_FragColor = texture2D(tex, texcoord); -}` -) - -// simpleFSSource returns a simple fragment shader that returns the given -// constant color. -func simpleFSSource(r, g, b gles.GLfloat) string { - const template = ` -precision mediump float; -void main() { - gl_FragColor = vec4(%f, %f, %f, 1.0); -}` - - return fmt.Sprintf(template, r, g, b) -} diff --git a/test/integration/gles/snippets/BUILD.bazel b/test/integration/gles/snippets/BUILD.bazel deleted file mode 100644 index 62ba6eab87..0000000000 --- a/test/integration/gles/snippets/BUILD.bazel +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "builder.go", - "clear_backbuffer.go", - "context.go", - "draw_textured_square.go", - "shaders.go", - "snippets.go", - ], - importpath = "github.com/google/gapid/test/integration/gles/snippets", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//gapis/api:go_default_library", - "//gapis/api/gles:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/memory:go_default_library", - "//gapis/service/path:go_default_library", - ], -) diff --git a/test/integration/gles/snippets/builder.go b/test/integration/gles/snippets/builder.go deleted file mode 100644 index c281e5f0b9..0000000000 --- a/test/integration/gles/snippets/builder.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package snippets - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/memory" - "github.com/google/gapid/gapis/service/path" -) - -// Builder is used to build OpenGL ES command snippets. -type Builder struct { - Cmds []api.Cmd - CB gles.CommandBuilder - - device *device.Instance - abi *device.ABI - state *api.GlobalState - lastID uint - programResources map[gles.ProgramId]gles.ActiveProgramResourcesʳ - eglDisplay memory.Pointer - eglSurface memory.Pointer - eglContext memory.Pointer -} - -// NewBuilder returns a new builder. -func NewBuilder(ctx context.Context, dev *device.Instance) *Builder { - abi := dev.Configuration.ABIs[0] - state := api.NewStateWithEmptyAllocator(abi.MemoryLayout) - return &Builder{ - CB: gles.CommandBuilder{Arena: state.Arena}, - device: dev, - abi: abi, - state: state, - programResources: map[gles.ProgramId]gles.ActiveProgramResourcesʳ{}, - } -} - -// Add appends cmds to the command list, returning the command identifier of the -// first added command. -func (b *Builder) Add(cmds ...api.Cmd) api.CmdID { - start := api.CmdID(len(b.Cmds)) - b.Cmds = append(b.Cmds, cmds...) - return start -} - -// Last returns the command identifier of the last added command. -func (b *Builder) Last() api.CmdID { - return api.CmdID(len(b.Cmds) - 1) -} - -// Capture encodes and writes the command list to the database, returning -// an identifier to the newly constructed and stored Capture. -func (b *Builder) Capture(ctx context.Context, name string) *path.Capture { - h := &capture.Header{ - Device: b.device, - ABI: b.abi, - } - out, err := capture.NewGraphicsCapture(ctx, b.CB.Arena, name, h, nil, b.Cmds) - if err != nil { - panic(err) - } - path, err := out.Path(ctx) - if err != nil { - panic(err) - } - return path -} - -func (b *Builder) newID() uint { - b.lastID++ - return b.lastID -} - -func (b *Builder) newShaderID() gles.ShaderId { return gles.ShaderId(b.newID()) } -func (b *Builder) newProgramID() gles.ProgramId { return gles.ProgramId(b.newID()) } - -// p returns a unique pointer. Meant to be used to generate -// pointers representing driver-side data, so the allocation -// itself is not relevant. -func (b *Builder) p() memory.Pointer { - base, err := b.state.Allocator.Alloc(8, 8) - if err != nil { - panic(err) - } - return memory.BytePtr(base) -} - -// Data allocates memory for the given values. -func (b *Builder) Data(ctx context.Context, v ...interface{}) api.AllocResult { - return b.state.AllocDataOrPanic(ctx, v...) -} diff --git a/test/integration/gles/snippets/clear_backbuffer.go b/test/integration/gles/snippets/clear_backbuffer.go deleted file mode 100644 index 55f69105be..0000000000 --- a/test/integration/gles/snippets/clear_backbuffer.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package snippets - -import ( - "context" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" -) - -// ClearBackbuffer returns the command list needed to sequentially clear the -// backbuffer to red, green, blue and black. -func (b *Builder) ClearBackbuffer(ctx context.Context) (red, green, blue, black api.CmdID) { - red = b.Add( - b.CB.GlClearColor(1.0, 0.0, 0.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) + 1 - green = b.Add( - b.CB.GlClearColor(0.0, 1.0, 0.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) + 1 - blue = b.Add( - b.CB.GlClearColor(0.0, 0.0, 1.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) + 1 - black = b.Add( - b.CB.GlClearColor(0.0, 0.0, 0.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) + 1 - return red, green, blue, black -} diff --git a/test/integration/gles/snippets/context.go b/test/integration/gles/snippets/context.go deleted file mode 100644 index 80b09c5283..0000000000 --- a/test/integration/gles/snippets/context.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package snippets - -import ( - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" - "github.com/google/gapid/gapis/memory" -) - -// CreateContext appends the commands to create a new EGL context with the -// given parameters. -func (b *Builder) CreateContext(width, height int, shared, preserveBuffersOnSwap bool) (eglContext, eglSurface, eglDisplay memory.Pointer) { - eglContext, eglSurface, eglDisplay = b.p(), b.p(), b.p() - eglConfig := b.p() - - // TODO: We don't observe attribute lists properly. We should. - b.Cmds = append(b.Cmds, - b.CB.EglGetDisplay(gles.EGLNativeDisplayType(0), eglDisplay), - b.CB.EglInitialize(eglDisplay, memory.Nullptr, memory.Nullptr, gles.EGLBoolean(1)), - b.CB.EglCreateContext(eglDisplay, eglConfig, memory.Nullptr, b.p(), eglContext), - ) - - // Switch to new context which shares resources with the first one - if shared { - sharedContext := eglContext - eglContext = b.p() - b.Cmds = append(b.Cmds, - b.CB.EglCreateContext(eglDisplay, eglConfig, sharedContext, b.p(), eglContext), - ) - } - - b.makeCurrent(eglDisplay, eglSurface, eglContext, width, height, preserveBuffersOnSwap) - return eglContext, eglSurface, eglDisplay -} - -// SwapBuffers appends a call to eglSwapBuffers. -func (b *Builder) SwapBuffers() api.CmdID { - return b.Add(b.CB.EglSwapBuffers(b.eglDisplay, b.eglSurface, gles.EGLBoolean(1))) -} - -// ResizeBackbuffer appends the commands to resize the backbuffer to the given -// dimensions. -func (b *Builder) ResizeBackbuffer(width, height int) api.CmdID { - b.makeCurrent(b.eglDisplay, b.eglSurface, b.eglContext, width, height, true) - return b.Last() -} - -// ClearColor appends a the commands to clear the backbuffer with the given -// color. -func (b *Builder) ClearColor(red, green, blue, alpha gles.GLfloat) api.CmdID { - b.Add( - b.CB.GlClearColor(red, green, blue, alpha), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT), - ) - return b.Last() -} - -// ClearDepth appends a the commands to clear the backbuffer depth map. -func (b *Builder) ClearDepth() api.CmdID { - return b.Add(b.CB.GlClear(gles.GLbitfield_GL_DEPTH_BUFFER_BIT)) -} - -func (b *Builder) makeCurrent(eglDisplay, eglSurface, eglContext memory.Pointer, width, height int, preserveBuffersOnSwap bool) { - a := b.state.Arena - eglTrue := gles.EGLBoolean(1) - b.Cmds = append(b.Cmds, api.WithExtras( - b.CB.EglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext, eglTrue), - gles.NewStaticContextStateForTest(a), - gles.NewDynamicContextStateForTest(a, width, height, preserveBuffersOnSwap), - )) - b.eglDisplay = eglDisplay - b.eglSurface = eglSurface - b.eglContext = eglContext -} diff --git a/test/integration/gles/snippets/draw_textured_square.go b/test/integration/gles/snippets/draw_textured_square.go deleted file mode 100644 index 9bdfcde902..0000000000 --- a/test/integration/gles/snippets/draw_textured_square.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package snippets - -import ( - "context" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" -) - -// DrawTexturedSquare returns the command list needed draw a textured square. -func (b *Builder) DrawTexturedSquare(ctx context.Context) (draw, swap api.CmdID) { - squareVertices := []float32{ - -0.5, -0.5, 0.5, - -0.5, +0.5, 0.5, - +0.5, +0.5, 0.5, - +0.5, -0.5, 0.5, - } - - squareIndices := []uint16{ - 0, 1, 2, 0, 2, 3, - } - - textureVSSource := ` - precision mediump float; - attribute vec3 position; - varying vec2 texcoord; - void main() { - gl_Position = vec4(position, 1.0); - texcoord = position.xy + vec2(0.5, 0.5); - }` - - textureFSSource := ` - precision mediump float; - uniform sampler2D tex; - varying vec2 texcoord; - void main() { - gl_FragColor = texture2D(tex, texcoord); - }` - - textureNames := []gles.TextureId{1} - textureNamesPtr := b.Data(ctx, textureNames) - texData := make([]uint8, 3*64*64) - for y := 0; y < 64; y++ { - for x := 0; x < 64; x++ { - texData[y*64*3+x*3] = uint8(x * 4) - texData[y*64*3+x*3+1] = uint8(y * 4) - texData[y*64*3+x*3+2] = 255 - } - } - - textureData := b.Data(ctx, texData) - squareIndicesPtr := b.Data(ctx, squareIndices) - squareVerticesPtr := b.Data(ctx, squareVertices) - - // Build the program resource - - prog := b.CreateProgram(ctx, textureVSSource, textureFSSource) - texLoc := b.AddUniformSampler(ctx, prog, "tex") - posLoc := b.AddAttributeVec3(ctx, prog, "position") - - // Build the texture resource - b.Add( - b.CB.GlGenTextures(1, textureNamesPtr.Ptr()).AddWrite(textureNamesPtr.Data()), - b.CB.GlBindTexture(gles.GLenum_GL_TEXTURE_2D, textureNames[0]), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MIN_FILTER, gles.GLint(gles.GLenum_GL_NEAREST)), - b.CB.GlTexParameteri(gles.GLenum_GL_TEXTURE_2D, gles.GLenum_GL_TEXTURE_MAG_FILTER, gles.GLint(gles.GLenum_GL_NEAREST)), - b.CB.GlTexImage2D( - gles.GLenum_GL_TEXTURE_2D, - 0, - gles.GLint(gles.GLenum_GL_RGB), - 64, - 64, - 0, - gles.GLenum_GL_RGB, - gles.GLenum_GL_UNSIGNED_BYTE, - textureData.Ptr(), - ).AddRead(textureData.Data()), - ) - - // Render square using the build program and texture - b.Add( - b.CB.GlEnable(gles.GLenum_GL_DEPTH_TEST), // Required for depth-writing - b.CB.GlClearColor(0.0, 1.0, 0.0, 1.0), - b.CB.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT|gles.GLbitfield_GL_DEPTH_BUFFER_BIT), - b.CB.GlUseProgram(prog), - b.CB.GlActiveTexture(gles.GLenum_GL_TEXTURE0), - b.CB.GlBindTexture(gles.GLenum_GL_TEXTURE_2D, textureNames[0]), - b.CB.GlUniform1i(texLoc, 0), - b.CB.GlEnableVertexAttribArray(posLoc), - b.CB.GlVertexAttribPointer(posLoc, 3, gles.GLenum_GL_FLOAT, gles.GLboolean(0), 0, squareVerticesPtr.Ptr()), - b.CB.GlDrawElements(gles.GLenum_GL_TRIANGLES, 6, gles.GLenum_GL_UNSIGNED_SHORT, squareIndicesPtr.Ptr()). - AddRead(squareIndicesPtr.Data()). - AddRead(squareVerticesPtr.Data()), - ) - draw = b.Last() - swap = b.SwapBuffers() - - return draw, swap -} diff --git a/test/integration/gles/snippets/shaders.go b/test/integration/gles/snippets/shaders.go deleted file mode 100644 index c60592cce2..0000000000 --- a/test/integration/gles/snippets/shaders.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package snippets - -import ( - "context" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/gles" -) - -// CreateProgram appends the commands to create and link a new program. -func (b *Builder) CreateProgram(ctx context.Context, - vertexShaderSource, fragmentShaderSource string) gles.ProgramId { - - a := b.state.Arena - - vs, fs, prog := b.newShaderID(), b.newShaderID(), b.newProgramID() - - b.Add(gles.BuildProgram(ctx, b.state, b.CB, vs, fs, prog, - vertexShaderSource, fragmentShaderSource)..., - ) - - resources := gles.MakeActiveProgramResourcesʳ(a) - - lpe := gles.MakeLinkProgramExtra(a) - lpe.SetLinkStatus(gles.GLboolean_GL_TRUE) - lpe.SetActiveResources(resources) - - cmd := api.WithExtras(b.CB.GlLinkProgram(prog), lpe) - b.programResources[prog] = resources - b.Add(cmd) - - return prog -} - -// AddUniformSampler adds a sampler 2D uniform to the given program. -func (b *Builder) AddUniformSampler(ctx context.Context, prog gles.ProgramId, name string) gles.UniformLocation { - a := b.state.Arena - - resources := b.programResources[prog] - index := resources.DefaultUniformBlock().Len() - - uniform := gles.MakeProgramResourceʳ(a) - uniform.SetType(gles.GLenum_GL_SAMPLER_2D) - uniform.SetName(name) - uniform.SetArraySize(1) - uniform.Locations().Add(0, gles.GLint(index)) - - resources.DefaultUniformBlock().Add(gles.UniformIndex(index), uniform) - - location := gles.UniformLocation(index) - b.Add(gles.GetUniformLocation(ctx, b.state, b.CB, prog, name, location)) - return location -} - -// AddAttributeVec3 adds a vec3 attribute to the given program. -func (b *Builder) AddAttributeVec3(ctx context.Context, prog gles.ProgramId, name string) gles.AttributeLocation { - a := b.state.Arena - - resources := b.programResources[prog] - index := resources.ProgramInputs().Len() - - attribute := gles.MakeProgramResourceʳ(a) - attribute.SetType(gles.GLenum_GL_FLOAT_VEC3) - attribute.SetName(name) - attribute.SetArraySize(1) - attribute.Locations().Add(0, gles.GLint(index)) - - resources.ProgramInputs().Add(uint32(index), attribute) - - location := gles.AttributeLocation(index) - b.Add(gles.GetAttribLocation(ctx, b.state, b.CB, prog, name, location)) - return location -} diff --git a/test/integration/gles/snippets/snippets.go b/test/integration/gles/snippets/snippets.go deleted file mode 100644 index 1d8f641663..0000000000 --- a/test/integration/gles/snippets/snippets.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package snippets exposes functions for building simple GLES command streams. -package snippets diff --git a/test/integration/service/BUILD.bazel b/test/integration/service/BUILD.bazel index 3850625455..34d89e8c18 100644 --- a/test/integration/service/BUILD.bazel +++ b/test/integration/service/BUILD.bazel @@ -32,13 +32,10 @@ go_test( deps = [ "//core/app/auth:go_default_library", "//core/assert:go_default_library", - "//core/event/task:go_default_library", "//core/log:go_default_library", "//core/net/grpcutil:go_default_library", "//core/os/device/bind:go_default_library", - "//core/os/device/host:go_default_library", "//gapis/api:go_default_library", - "//gapis/capture:go_default_library", "//gapis/client:go_default_library", "//gapis/database:go_default_library", "//gapis/replay:go_default_library", @@ -46,7 +43,6 @@ go_test( "//gapis/service:go_default_library", "//gapis/service/path:go_default_library", "//gapis/stringtable:go_default_library", - "//test/integration/gles/snippets:go_default_library", "@org_golang_google_grpc//:go_default_library", ], ) diff --git a/test/integration/service/service_test.go b/test/integration/service/service_test.go index 54abd5e0fc..608681a857 100644 --- a/test/integration/service/service_test.go +++ b/test/integration/service/service_test.go @@ -23,13 +23,12 @@ import ( "github.com/google/gapid/core/app/auth" "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/event/task" + //"github.com/google/gapid/core/event/task" "github.com/google/gapid/core/log" "github.com/google/gapid/core/net/grpcutil" "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/core/os/device/host" + //"github.com/google/gapid/core/os/device/host" "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/capture" gapis "github.com/google/gapid/gapis/client" "github.com/google/gapid/gapis/database" "github.com/google/gapid/gapis/replay" @@ -37,7 +36,6 @@ import ( "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" "github.com/google/gapid/gapis/stringtable" - "github.com/google/gapid/test/integration/gles/snippets" "google.golang.org/grpc" ) @@ -112,30 +110,6 @@ var ( swapCmdIndex uint64 ) -func init() { - check := func(err error) { - if err != nil { - panic(err) - } - } - ctx := context.Background() - - deviceScanDone, onDeviceScanDone := task.NewSignal() - onDeviceScanDone(ctx) - cfg.DeviceScanDone = deviceScanDone - - ctx = database.Put(ctx, database.NewInMemory(ctx)) - dev := host.Instance(ctx) - - b := snippets.NewBuilder(ctx, dev) - b.CreateContext(128, 128, false, false) - draw, swap := b.DrawTexturedSquare(ctx) - - buf := bytes.Buffer{} - check(capture.Export(ctx, b.Capture(ctx, "test-capture"), &buf)) - testCaptureData, drawCmdIndex, swapCmdIndex = buf.Bytes(), uint64(draw), uint64(swap) -} - func TestGetServerInfo(t *testing.T) { ctx, server, shutdown := setup(t) defer shutdown() diff --git a/test/robot/scheduler/scheduler.go b/test/robot/scheduler/scheduler.go index 3914f914c1..3613b98101 100644 --- a/test/robot/scheduler/scheduler.go +++ b/test/robot/scheduler/scheduler.go @@ -149,8 +149,6 @@ func (s schedule) canReplay(t *monitor.Trace) bool { // Gles trace must be replayed on host while Vulkan trace must be replayed // on the same device where the trace was captured. switch t.Input.Hints.API { - case "gles": - return s.worker.GetTarget() == t.GetHost() case "vulkan": return s.worker.GetTarget() == t.GetTarget() } From 9e798024ab4329c497dbaa6cf3d9a5360697a911 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 13 Mar 2020 14:09:23 -0700 Subject: [PATCH 0167/1218] Tidy up some more leftover GLESisms --- cmd/regres/main.go | 16 +++++++-------- gapii/cc/spy.cpp | 2 -- gapii/cc/spy.h | 4 ---- gapii/client/capture.go | 6 ------ gapis/api/templates/specific_gfx_api.cpp.tmpl | 20 ------------------- gapis/trace/tracer/tracer.go | 5 ----- 6 files changed, 8 insertions(+), 45 deletions(-) diff --git a/cmd/regres/main.go b/cmd/regres/main.go index afc94e15b8..2cae60ac43 100644 --- a/cmd/regres/main.go +++ b/cmd/regres/main.go @@ -193,7 +193,7 @@ func run(ctx context.Context) error { // Gather incremental build stats if *incBuild { - if err := withTouchedGLES(ctx, rnd, func() error { + if err := withTouchedVulkan(ctx, rnd, func() error { log.I(ctx, "HEAD~%.2d: Building incremental change at %v: %v", i, sha, cl.Subject) if duration, err := build(ctx); err == nil { r.IncrementalBuildTime = duration.Seconds() @@ -257,19 +257,19 @@ func run(ctx context.Context) error { return nil } -func withTouchedGLES(ctx context.Context, r *rand.Rand, f func() error) error { - glesAPIPath := filepath.Join(*root, "gapis", "api", "gles", "gles.api") - fi, err := os.Stat(glesAPIPath) +func withTouchedVulkan(ctx context.Context, r *rand.Rand, f func() error) error { + vulkanAPIPath := filepath.Join(*root, "gapis", "api", "vulkan", "vulkan.api") + fi, err := os.Stat(vulkanAPIPath) if err != nil { return err } - glesAPI, err := ioutil.ReadFile(glesAPIPath) + vulkanAPI, err := ioutil.ReadFile(vulkanAPIPath) if err != nil { return err } - modGlesAPI := []byte(fmt.Sprintf("%v\ncmd void fake_cmd_%d() {}\n", string(glesAPI), r.Int())) - ioutil.WriteFile(glesAPIPath, modGlesAPI, fi.Mode().Perm()) - defer ioutil.WriteFile(glesAPIPath, glesAPI, fi.Mode().Perm()) + modVulkanAPI := []byte(fmt.Sprintf("%v\ncmd void fake_cmd_%d() {}\n", string(vulkanAPI), r.Int())) + ioutil.WriteFile(vulkanAPIPath, modVulkanAPI, fi.Mode().Perm()) + defer ioutil.WriteFile(vulkanAPIPath, vulkanAPI, fi.Mode().Perm()) return f() } diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index f0d066b3a0..99f08b6127 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -225,8 +225,6 @@ Spy::~Spy() { endTraceIfRequested(); } -void Spy::resolveImports() {} - CallObserver* Spy::enter(const char* name, uint32_t api) { lock(); auto ctx = new CallObserver(this, gContext, api); diff --git a/gapii/cc/spy.h b/gapii/cc/spy.h index 3c736da6a7..d7f7e276f5 100644 --- a/gapii/cc/spy.h +++ b/gapii/cc/spy.h @@ -33,10 +33,6 @@ class Spy : public VulkanSpy { static Spy* get(); ~Spy(); - // resolve the imported functions. Call if the functions change due to - // external factors. - void resolveImports(); - CallObserver* enter(const char* name, uint32_t api); void exit(); diff --git a/gapii/client/capture.go b/gapii/client/capture.go index 8a2e4cb084..388dcbfca7 100644 --- a/gapii/client/capture.go +++ b/gapii/client/capture.go @@ -54,15 +54,9 @@ const ( // DisableCoherentMemoryTracker disables the coherent memory tracker from running. DisableCoherentMemoryTracker Flags = 0x000000100 - // GlesAPI is hard-coded bit mask for GLES API, it needs to be kept in sync - // with the api_index in the gles.api file. - GlesAPI = uint32(1 << 1) // VulkanAPI is hard-coded bit mask for Vulkan API, it needs to be kept in sync // with the api_index in the vulkan.api file. VulkanAPI = uint32(1 << 2) - // GvrAPI is hard-coded bit mask for GVR API, it needs to be kept in sync - // with the api_index in the gvr.api file. - GvrAPI = uint32(1 << 3) ) // Options to use when creating a capture. diff --git a/gapis/api/templates/specific_gfx_api.cpp.tmpl b/gapis/api/templates/specific_gfx_api.cpp.tmpl index 28432a3673..3e803966a3 100644 --- a/gapis/api/templates/specific_gfx_api.cpp.tmpl +++ b/gapis/api/templates/specific_gfx_api.cpp.tmpl @@ -168,26 +168,6 @@ {{else}} {{Template "Call" $}}; {{end}} - - {{if and 0 (eq (Global "API") "gles")}} {{/* Enable for debugging */}} - const Gles::GLenum err = mFunctionStubs.glGetError(); - if (err != Gles::GLenum::GL_NO_ERROR) { - GAPID_ERROR({{Template "C++.PrintfCommandCall" $}}); - GAPID_ERROR("{{$name}} returned error: 0x%x", err); - return false; - } - {{if eq $name "glShaderSource"}} - GAPID_DEBUG("Shader source: %s", source[0]); - {{else if eq $name "glCompileShader"}} - int success = 0; - mFunctionStubs.glGetShaderiv(shader, Gles::GLenum::GL_COMPILE_STATUS, &success); - if (success == 0) { - char buf[2048]; - mFunctionStubs.glGetShaderInfoLog(shader, 2048, nullptr, buf); - GAPID_ERROR("Shader failed to compile: %s", buf); - } - {{end}} - {{end}} } else { GAPID_ERROR("Attempted to call unsupported function {{$name}}"); } diff --git a/gapis/trace/tracer/tracer.go b/gapis/trace/tracer/tracer.go index 0a1636d184..a31c43a431 100644 --- a/gapis/trace/tracer/tracer.go +++ b/gapis/trace/tracer/tracer.go @@ -105,11 +105,6 @@ func LayersFromOptions(ctx context.Context, o *service.TraceOptions) []string { func GapiiOptions(o *service.TraceOptions) gapii.Options { apis := uint32(0) for _, api := range o.Apis { - if api == "OpenGLES" || - api == "GVR" { - apis |= gapii.GlesAPI - apis |= gapii.GvrAPI - } if api == "Vulkan" { apis |= gapii.VulkanAPI } From ef6dd97ca356000f554a7f7027ce2d90f79ecfa0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Fri, 13 Mar 2020 14:09:50 -0700 Subject: [PATCH 0168/1218] Remove JDWP path as it is no longer used AGI does not support Android devices which predate support for rootless layer injection. Remove those paths and the JDWP implementation which underpinned them. Bug: b/148057231 --- BUILD.bazel | 4 - core/java/jdbg/BUILD.bazel | 49 --- core/java/jdbg/assignable.go | 71 --- core/java/jdbg/errors.go | 31 -- core/java/jdbg/failure.go | 51 --- core/java/jdbg/jdbg.go | 405 ------------------ core/java/jdbg/jdbg_test.go | 115 ----- core/java/jdbg/marshal.go | 142 ------ core/java/jdbg/method_signature.go | 59 --- core/java/jdbg/methods.go | 69 --- core/java/jdbg/resolve_overload.go | 119 ----- core/java/jdbg/signature.go | 75 ---- core/java/jdbg/type.go | 354 --------------- core/java/jdbg/value.go | 105 ----- core/java/jdwp/BUILD.bazel | 77 ---- core/java/jdwp/class_status.go | 50 --- core/java/jdwp/cmdset_arrayreference.go | 44 -- core/java/jdwp/cmdset_arraytype.go | 26 -- core/java/jdwp/cmdset_classobjectreference.go | 28 -- core/java/jdwp/cmdset_classtype.go | 62 --- core/java/jdwp/cmdset_eventrequest.go | 218 ---------- core/java/jdwp/cmdset_method.go | 27 -- core/java/jdwp/cmdset_objectreference.go | 63 --- core/java/jdwp/cmdset_referencetypes.go | 54 --- core/java/jdwp/cmdset_stackframe.go | 62 --- core/java/jdwp/cmdset_stringreference.go | 22 - core/java/jdwp/cmdset_threadreference.go | 75 ---- core/java/jdwp/cmdset_vm.go | 115 ----- core/java/jdwp/cmdsets.go | 298 ------------- core/java/jdwp/coder.go | 275 ------------ core/java/jdwp/debug.go | 24 -- core/java/jdwp/errors.go | 197 --------- core/java/jdwp/event.go | 179 -------- core/java/jdwp/event_kind.go | 134 ------ core/java/jdwp/field.go | 72 ---- core/java/jdwp/helpers.go | 104 ----- core/java/jdwp/invoke_options.go | 42 -- core/java/jdwp/jdwp.go | 199 --------- core/java/jdwp/jdwp_test.go | 180 -------- core/java/jdwp/method.go | 61 --- core/java/jdwp/modbits.go | 90 ---- core/java/jdwp/packet.go | 100 ----- core/java/jdwp/recv.go | 89 ---- core/java/jdwp/suspend_policy.go | 42 -- core/java/jdwp/tag.go | 78 ---- core/java/jdwp/test/BUILD.bazel | 29 -- core/java/jdwp/test/test.go | 133 ------ core/java/jdwp/thread_status.go | 62 --- core/java/jdwp/type_tag.go | 39 -- core/java/jdwp/types.go | 167 -------- core/java/jdwp/value.go | 30 -- core/os/android/adb/forward.go | 8 - gapii/client/BUILD.bazel | 4 - gapii/client/adb.go | 48 +-- gapii/client/jdwp_loader.go | 327 -------------- gapii/vulkan/vk_graphics_spy/cc/layer.cpp | 15 +- 56 files changed, 12 insertions(+), 5586 deletions(-) delete mode 100644 core/java/jdbg/BUILD.bazel delete mode 100644 core/java/jdbg/assignable.go delete mode 100644 core/java/jdbg/errors.go delete mode 100644 core/java/jdbg/failure.go delete mode 100644 core/java/jdbg/jdbg.go delete mode 100644 core/java/jdbg/jdbg_test.go delete mode 100644 core/java/jdbg/marshal.go delete mode 100644 core/java/jdbg/method_signature.go delete mode 100644 core/java/jdbg/methods.go delete mode 100644 core/java/jdbg/resolve_overload.go delete mode 100644 core/java/jdbg/signature.go delete mode 100644 core/java/jdbg/type.go delete mode 100644 core/java/jdbg/value.go delete mode 100644 core/java/jdwp/BUILD.bazel delete mode 100644 core/java/jdwp/class_status.go delete mode 100644 core/java/jdwp/cmdset_arrayreference.go delete mode 100644 core/java/jdwp/cmdset_arraytype.go delete mode 100644 core/java/jdwp/cmdset_classobjectreference.go delete mode 100644 core/java/jdwp/cmdset_classtype.go delete mode 100644 core/java/jdwp/cmdset_eventrequest.go delete mode 100644 core/java/jdwp/cmdset_method.go delete mode 100644 core/java/jdwp/cmdset_objectreference.go delete mode 100644 core/java/jdwp/cmdset_referencetypes.go delete mode 100644 core/java/jdwp/cmdset_stackframe.go delete mode 100644 core/java/jdwp/cmdset_stringreference.go delete mode 100644 core/java/jdwp/cmdset_threadreference.go delete mode 100644 core/java/jdwp/cmdset_vm.go delete mode 100644 core/java/jdwp/cmdsets.go delete mode 100644 core/java/jdwp/coder.go delete mode 100644 core/java/jdwp/debug.go delete mode 100644 core/java/jdwp/errors.go delete mode 100644 core/java/jdwp/event.go delete mode 100644 core/java/jdwp/event_kind.go delete mode 100644 core/java/jdwp/field.go delete mode 100644 core/java/jdwp/helpers.go delete mode 100644 core/java/jdwp/invoke_options.go delete mode 100644 core/java/jdwp/jdwp.go delete mode 100644 core/java/jdwp/jdwp_test.go delete mode 100644 core/java/jdwp/method.go delete mode 100644 core/java/jdwp/modbits.go delete mode 100644 core/java/jdwp/packet.go delete mode 100644 core/java/jdwp/recv.go delete mode 100644 core/java/jdwp/suspend_policy.go delete mode 100644 core/java/jdwp/tag.go delete mode 100644 core/java/jdwp/test/BUILD.bazel delete mode 100644 core/java/jdwp/test/test.go delete mode 100644 core/java/jdwp/thread_status.go delete mode 100644 core/java/jdwp/type_tag.go delete mode 100644 core/java/jdwp/types.go delete mode 100644 core/java/jdwp/value.go delete mode 100644 gapii/client/jdwp_loader.go diff --git a/BUILD.bazel b/BUILD.bazel index e121661e33..51e9e4ba32 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -256,8 +256,6 @@ test_suite( "//core/fault/stacktrace/crunch:go_default_test", "//core/git:go_default_test", "//core/image:go_default_test", - # "//core/java/jdbg:go_default_test", # disabled: flaky on Kokoro - "//core/java/jdwp:go_default_test", "//core/langsvr:go_default_test", "//core/log:go_default_test", "//core/math/f16:go_default_test", @@ -391,8 +389,6 @@ test_suite( "//core/fault/stacktrace/crunch:go_default_test", "//core/git:go_default_test", "//core/image:go_default_test", - "//core/java/jdbg:go_default_test", - "//core/java/jdwp:go_default_test", "//core/langsvr:go_default_test", "//core/log:go_default_test", "//core/math/f16:go_default_test", diff --git a/core/java/jdbg/BUILD.bazel b/core/java/jdbg/BUILD.bazel deleted file mode 100644 index f61135e886..0000000000 --- a/core/java/jdbg/BUILD.bazel +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "assignable.go", - "errors.go", - "failure.go", - "jdbg.go", - "marshal.go", - "method_signature.go", - "methods.go", - "resolve_overload.go", - "signature.go", - "type.go", - "value.go", - ], - importpath = "github.com/google/gapid/core/java/jdbg", - visibility = ["//visibility:public"], - deps = ["//core/java/jdwp:go_default_library"], -) - -go_test( - name = "go_default_test", - size = "small", - srcs = ["jdbg_test.go"], - embed = [":go_default_library"], - tags = ["integration"], - deps = [ - "//core/assert:go_default_library", - "//core/java/jdwp:go_default_library", - "//core/java/jdwp/test:go_default_library", - "//core/log:go_default_library", - ], -) diff --git a/core/java/jdbg/assignable.go b/core/java/jdbg/assignable.go deleted file mode 100644 index 8f18a27738..0000000000 --- a/core/java/jdbg/assignable.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "fmt" - "reflect" -) - -// assignable returns true if the type of val can be assigned to dst. -func (j *JDbg) assignable(dst Type, val interface{}) bool { - if v, ok := val.(Value); ok { - if v.ty.CastableTo(dst) { - return true - } - if dst.Signature() == v.ty.Signature() { - // Sanity check. - panic(fmt.Sprint("Two different types found with identical signatures! ", dst.Signature())) - } - return j.assignable(dst, v.val) - } - return j.assignableT(dst, reflect.TypeOf(val)) -} - -func (j *JDbg) assignableT(dst Type, src reflect.Type) bool { - if dst == j.cache.objTy { - return true // Anything goes in an object! - } - if src == nil { - _, isClass := dst.(*Class) - return isClass - } - switch src.Kind() { - case reflect.Ptr, reflect.Interface: - return j.assignableT(dst, src.Elem()) - case reflect.Bool: - return dst == j.cache.boolTy - case reflect.Int8, reflect.Uint8: - return dst == j.cache.byteTy - case reflect.Int16: - return dst == j.cache.charTy || dst == j.cache.shortTy - case reflect.Int32, reflect.Int: - return dst == j.cache.intTy - case reflect.Int64: - return dst == j.cache.longTy - case reflect.Float32: - return dst == j.cache.floatTy - case reflect.Float64: - return dst == j.cache.doubleTy - case reflect.String: - return dst == j.cache.stringTy - case reflect.Array, reflect.Slice: - if dstArray, ok := dst.(*Array); ok { - return j.assignableT(dstArray.el, src.Elem()) - } - } - - return false -} diff --git a/core/java/jdbg/errors.go b/core/java/jdbg/errors.go deleted file mode 100644 index 11f9c78156..0000000000 --- a/core/java/jdbg/errors.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "fmt" - "strings" -) - -// Errors is a collection of errors. -type Errors []error - -func (l Errors) Error() string { - lines := make([]string, len(l)) - for i, e := range l { - lines[i] = e.Error() - } - return fmt.Sprintf("%d errors:\n%v", len(lines), strings.Join(lines, "\n")) -} diff --git a/core/java/jdbg/failure.go b/core/java/jdbg/failure.go deleted file mode 100644 index 0b50b42959..0000000000 --- a/core/java/jdbg/failure.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import "fmt" - -// failure is the error type that can be thrown as a panic by JDbg.fail() and -// JDbg.err() and is caught by catchFailures(). It is used to immediately -// terminate execution of Do(), and return the error. -type failure struct { - error -} - -// fail panics with a failure error formed from msg and args, immediately -// terminating execution of Do(). -func (j *JDbg) fail(msg string, args ...interface{}) { - j.err(fmt.Errorf(msg, args...)) -} - -// err panics with a failure error holding err, immediately terminating -// execution of Do(). -func (j *JDbg) err(err error) { - panic(failure{err}) -} - -// Try calls f, catching and returning any exceptions thrown. -func Try(f func() error) (err error) { - defer func() { - switch r := recover().(type) { - case nil: - case failure: - err = r - default: - panic(r) - } - }() - err = f() - return err -} diff --git a/core/java/jdbg/jdbg.go b/core/java/jdbg/jdbg.go deleted file mode 100644 index 21e509be8b..0000000000 --- a/core/java/jdbg/jdbg.go +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package jdbg provides a simpler interface to the jdwp package, offering -// simple type resolving and method invoking functions. -package jdbg - -import ( - "fmt" - "strings" - - "github.com/google/gapid/core/java/jdwp" -) - -type cache struct { - arrays map[string]*Array - classes map[string]*Class - idToSig map[jdwp.ReferenceTypeID]string - - objTy *Class - stringTy *Class - numberTy *Class - boolObjTy *Class - byteObjTy *Class - charObjTy *Class - shortObjTy *Class - intObjTy *Class - longObjTy *Class - floatObjTy *Class - doubleObjTy *Class - boolTy *Simple - byteTy *Simple - charTy *Simple - shortTy *Simple - intTy *Simple - longTy *Simple - floatTy *Simple - doubleTy *Simple - - voidTy *Simple -} - -// JDbg is a wrapper around a JDWP connection that provides an easier interface -// for usage. -type JDbg struct { - conn *jdwp.Connection - thread jdwp.ThreadID - cache cache - objects []jdwp.ObjectID // Objects created that have GC disabled -} - -// Do calls f with a JDbg instance, returning the error returned by f. -// If any JDWP errors are raised during the call to f, then execution of f is -// immediately terminated, and the JDWP error is returned. -func Do(conn *jdwp.Connection, thread jdwp.ThreadID, f func(jdbg *JDbg) error) error { - j := &JDbg{ - conn: conn, - thread: thread, - cache: cache{ - arrays: map[string]*Array{}, - classes: map[string]*Class{}, - idToSig: map[jdwp.ReferenceTypeID]string{}, - }, - } - defer func() { - // Reenable GC for all objects used during the call to f() - for _, o := range j.objects { - conn.EnableGC(o) - } - }() - - return Try(func() error { - // Prime the cache with basic types. - j.cache.voidTy = &Simple{j: j, ty: jdwp.TagVoid} - j.cache.boolTy = &Simple{j: j, ty: jdwp.TagBoolean} - j.cache.byteTy = &Simple{j: j, ty: jdwp.TagByte} - j.cache.charTy = &Simple{j: j, ty: jdwp.TagChar} - j.cache.shortTy = &Simple{j: j, ty: jdwp.TagShort} - j.cache.intTy = &Simple{j: j, ty: jdwp.TagInt} - j.cache.longTy = &Simple{j: j, ty: jdwp.TagLong} - j.cache.floatTy = &Simple{j: j, ty: jdwp.TagFloat} - j.cache.doubleTy = &Simple{j: j, ty: jdwp.TagDouble} - j.cache.objTy = j.Class("java.lang.Object") - j.cache.stringTy = j.Class("java.lang.String") - j.cache.numberTy = j.Class("java.lang.Number") - j.cache.boolObjTy = j.Class("java.lang.Boolean") - j.cache.byteObjTy = j.Class("java.lang.Byte") - j.cache.charObjTy = j.Class("java.lang.Character") - j.cache.shortObjTy = j.Class("java.lang.Short") - j.cache.intObjTy = j.Class("java.lang.Integer") - j.cache.longObjTy = j.Class("java.lang.Long") - j.cache.floatObjTy = j.Class("java.lang.Float") - j.cache.doubleObjTy = j.Class("java.lang.Double") - - // Call f - return f(j) - }) -} - -// Connection returns the JDWP connection. -func (j *JDbg) Connection() *jdwp.Connection { return j.conn } - -// ObjectType returns the Java java.lang.Object type. -func (j *JDbg) ObjectType() *Class { return j.cache.objTy } - -// StringType returns the Java java.lang.String type. -func (j *JDbg) StringType() *Class { return j.cache.stringTy } - -// NumberType returns the Java java.lang.Number type. -func (j *JDbg) NumberType() *Class { return j.cache.numberTy } - -// BoolObjectType returns the Java java.lang.Boolean type. -func (j *JDbg) BoolObjectType() *Class { return j.cache.boolObjTy } - -// ByteObjectType returns the Java java.lang.Byte type. -func (j *JDbg) ByteObjectType() *Class { return j.cache.byteObjTy } - -// CharObjectType returns the Java java.lang.Character type. -func (j *JDbg) CharObjectType() *Class { return j.cache.charObjTy } - -// ShortObjectType returns the Java java.lang.Short type. -func (j *JDbg) ShortObjectType() *Class { return j.cache.shortObjTy } - -// IntObjectType returns the Java java.lang.Integer type. -func (j *JDbg) IntObjectType() *Class { return j.cache.intObjTy } - -// LongObjectType returns the Java java.lang.Long type. -func (j *JDbg) LongObjectType() *Class { return j.cache.longObjTy } - -// FloatObjectType returns the Java java.lang.Float type. -func (j *JDbg) FloatObjectType() *Class { return j.cache.floatObjTy } - -// DoubleObjectType returns the Java java.lang.Double type. -func (j *JDbg) DoubleObjectType() *Class { return j.cache.doubleObjTy } - -// BoolType returns the Java java.lang.Boolean type. -func (j *JDbg) BoolType() *Simple { return j.cache.boolTy } - -// ByteType returns the Java byte type. -func (j *JDbg) ByteType() *Simple { return j.cache.byteTy } - -// CharType returns the Java char type. -func (j *JDbg) CharType() *Simple { return j.cache.charTy } - -// ShortType returns the Java short type. -func (j *JDbg) ShortType() *Simple { return j.cache.shortTy } - -// IntType returns the Java int type. -func (j *JDbg) IntType() *Simple { return j.cache.intTy } - -// LongType returns the Java long type. -func (j *JDbg) LongType() *Simple { return j.cache.longTy } - -// FloatType returns the Java float type. -func (j *JDbg) FloatType() *Simple { return j.cache.floatTy } - -// DoubleType returns the Java double type. -func (j *JDbg) DoubleType() *Simple { return j.cache.doubleTy } - -// Type looks up the specified type by signature. -// For example: "Ljava/io/File;" -func (j *JDbg) Type(sig string) Type { - offset := 0 - ty, err := j.parseSignature(sig, &offset) - if err != nil { - j.fail("Failed to parse signature: %v", err) - } - return ty -} - -// Class looks up the specified class by name. -// For example: "java.io.File" -func (j *JDbg) Class(name string) *Class { - ty := j.Type(fmt.Sprintf("L%s;", strings.Replace(name, ".", "/", -1))) - if class, ok := ty.(*Class); ok { - return class - } - j.fail("Resolved type was not array but %T", ty) - return nil -} - -// AllClasses returns all the loaded classes. -func (j *JDbg) AllClasses() []*Class { - classes, err := j.conn.GetAllClasses() - if err != nil { - j.fail("Couldn't get all classes: %v", err) - } - out := []*Class{} - for _, class := range classes { - c, err := j.class(class) - if err != nil { - j.fail("Couldn't get class '%v': %v", class.Signature, err) - } - out = append(out, c) - } - return out -} - -// ArrayOf returns the type of the array with specified element type. -func (j *JDbg) ArrayOf(elTy Type) *Array { - ty := j.Type("[" + elTy.Signature()) - if array, ok := ty.(*Array); ok { - return array - } - j.fail("Resolved type was not array but %T", ty) - return nil -} - -// classFromSig looks up the specified class type by signature. -func (j *JDbg) classFromSig(sig string) (*Class, error) { - if class, ok := j.cache.classes[sig]; ok { - return class, nil - } - class, err := j.conn.GetClassBySignature(sig) - if err != nil { - return nil, err - } - return j.class(class) -} - -func (j *JDbg) class(class jdwp.ClassInfo) (*Class, error) { - sig := class.Signature - if cached, ok := j.cache.classes[class.Signature]; ok { - return cached, nil - } - - name := strings.Replace(strings.TrimRight(strings.TrimLeft(sig, "[L"), ";"), "/", ".", -1) - - ty := &Class{j: j, signature: sig, name: name, class: class} - j.cache.classes[sig] = ty - j.cache.idToSig[class.TypeID] = sig - - superid, err := j.conn.GetSuperClass(class.ClassID()) - if err != nil { - return nil, err - } - - if superid != 0 { - ty.super = j.typeFromID(jdwp.ReferenceTypeID(superid)).(*Class) - } - - implementsids, err := j.conn.GetImplemented(class.TypeID) - if err != nil { - return nil, err - } - - ty.implements = make([]*Class, len(implementsids)) - for i, id := range implementsids { - ty.implements[i] = j.typeFromID(jdwp.ReferenceTypeID(id)).(*Class) - } - - ty.fields, err = j.conn.GetFields(class.TypeID) - if err != nil { - return nil, err - } - - return ty, nil -} - -func (j *JDbg) typeFromID(id jdwp.ReferenceTypeID) Type { - sig, ok := j.cache.idToSig[id] - if !ok { - var err error - sig, err = j.conn.GetTypeSignature(id) - if err != nil { - j.fail("GetTypeSignature() returned: %v", err) - } - j.cache.idToSig[id] = sig - } - return j.Type(sig) -} - -// This returns the this object for the current stack frame. -func (j *JDbg) This() Value { - frames, err := j.conn.GetFrames(j.thread, 0, 1) - if err != nil { - j.fail("GetFrames() returned: %v", err) - } - - this, err := j.conn.GetThisObject(j.thread, frames[0].Frame) - if err != nil { - j.fail("GetThisObject() returned: %v", err) - } - - return j.object(this.Object) -} - -func (j *JDbg) String(val string) Value { - str, err := j.conn.CreateString(val) - if err != nil { - j.fail("CreateString() returned: %v", err) - } - return j.object(str) -} - -// findArg finds the argument with the given name/index in the given frame -func (j *JDbg) findArg(name string, index int, frame jdwp.FrameInfo) jdwp.VariableRequest { - table, err := j.conn.VariableTable( - jdwp.ReferenceTypeID(frame.Location.Class), - frame.Location.Method) - - if err != nil { - j.fail("VariableTable returned: %v", err) - } - - variable := jdwp.VariableRequest{-1, 0} - - for _, slot := range table.Slots { - if name == slot.Name { - variable.Index = slot.Slot - variable.Tag = slot.Signature[0] - } - } - - if variable.Index != -1 { - return variable - } - - // Fallback to looking for the argument by index. - slots := table.ArgumentSlots() - - // Find the "this" argument. It is always labeled and the first argument slot. - thisSlot := -1 - for i, slot := range slots { - if slot.Name == "this" { - thisSlot = i - break - } - } - if thisSlot < 0 { - j.fail("Could not find argument with name %s (no 'this' found)", name) - } - - if thisSlot+1+index >= len(slots) { - j.fail("Could not find argument with name %s (not enough slots)", name) - } - - variable.Index = slots[thisSlot+1+index].Slot - variable.Tag = slots[thisSlot+1+index].Signature[0] - return variable -} - -// GetArgument returns the method argument of the given name and index. First, -// this attempts to retrieve the argument by name, but falls back to looking for -// the argument by index (e.g. in the case the names have been stripped from the -// debug info). -func (j *JDbg) GetArgument(name string, index int) Variable { - frames, err := j.conn.GetFrames(j.thread, 0, 1) - if err != nil { - j.fail("GetFrames() returned: %v", err) - } - variable := j.findArg(name, index, frames[0]) - - values, err := j.conn.GetValues(j.thread, frames[0].Frame, []jdwp.VariableRequest{variable}) - if err != nil { - j.fail("GetValues() returned: %v", err) - } - return Variable{j.value(values[0]), variable} -} - -// SetVariable sets the value of the given variable. -func (j *JDbg) SetVariable(variable Variable, val Value) { - frames, err := j.conn.GetFrames(j.thread, 0, 1) - if err != nil { - j.fail("GetFrames() returned: %v", err) - } - - v := val.val.(jdwp.Value) - assign := jdwp.VariableAssignmentRequest{variable.variable.Index, v} - err = j.conn.SetValues(j.thread, frames[0].Frame, []jdwp.VariableAssignmentRequest{assign}) - if err != nil { - j.fail("GetValues() returned: %v", err) - } -} - -func (j *JDbg) object(id jdwp.Object) Value { - tyID, err := j.conn.GetObjectType(id.ID()) - if err != nil { - j.fail("GetObjectType() returned: %v", err) - } - - ty := j.typeFromID(tyID.Type) - return newValue(ty, id) -} - -func (j *JDbg) value(o interface{}) Value { - switch v := o.(type) { - case jdwp.Object: - return j.object(v) - default: - j.fail("Unhandled variable type %T", o) - return Value{} - } -} diff --git a/core/java/jdbg/jdbg_test.go b/core/java/jdbg/jdbg_test.go deleted file mode 100644 index 95918e3fb6..0000000000 --- a/core/java/jdbg/jdbg_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg_test - -import ( - "context" - "os" - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/java/jdbg" - "github.com/google/gapid/core/java/jdwp" - "github.com/google/gapid/core/java/jdwp/test" - "github.com/google/gapid/core/log" -) - -var source = map[string]string{ - "main.java": ` -public class main { - static { - Calculator.register(); - } - public static void main(String[] args) throws Exception { - System.out.print("Doing stuff\n"); - Thread.sleep(1000); - } -}`, - "Calculator.java": ` -public class Calculator { - public static void register() {} - - private int value = 0; - - public static int Add(int a, int b) { return a + b; } - public void Add(int a) { value += a; } - - public int Result() { return value; } -} -`, -} - -func TestMain(m *testing.M) { - ctx := context.Background() - ctx = log.PutHandler(ctx, log.Normal.Handler(log.Std())) - os.Exit(test.BuildRunAndConnect(ctx, source, func(ctx context.Context, c *jdwp.Connection) int { - if err := c.ResumeAll(); err != nil { - log.F(ctx, true, "Failed resume VM. Error: %v", err) - return -1 - } - - // Wait for java to load the prepare class - t, err := c.WaitForClassPrepare(ctx, "Calculator") - if err != nil { - log.F(ctx, true, "Failed to wait for Calculator prepare. Error: %v", err) - return -1 - } - - conn, thread = c, t - return m.Run() - })) -} - -var conn *jdwp.Connection -var thread jdwp.ThreadID - -func TestInvokeStringFormat(t *testing.T) { - assert := assert.To(t) - err := jdbg.Do(conn, thread, func(j *jdbg.JDbg) error { - res := j.Class("java/lang/String").Call("format", "%s says '%s' %d times", - []interface{}{"bob", "hello world", 5}).Get() - assert.For("res").That(res).Equals("bob says 'hello world' 5 times") - return nil - }) - assert.For("err").That(err).Equals(nil) -} - -func TestInvokeStaticMethod(t *testing.T) { - assert := assert.To(t) - err := jdbg.Do(conn, thread, func(j *jdbg.JDbg) error { - res := j.Class("Calculator").Call("Add", 3, 7).Get() - assert.For("res").That(res).Equals(10) - return nil - }) - assert.For("err").That(err).Equals(nil) -} - -func TestInvokeMethod(t *testing.T) { - assert := assert.To(t) - err := jdbg.Do(conn, thread, func(j *jdbg.JDbg) error { - calcTy := j.Class("Calculator") - - calc := calcTy.New() - for _, i := range []int{3, 6, 8} { - calc.Call("Add", i) - } - - res := calc.Call("Result").Get() - assert.For("res").That(res).Equals(3 + 6 + 8) - return nil - }) - assert.For("err").That(err).Equals(nil) - -} diff --git a/core/java/jdbg/marshal.go b/core/java/jdbg/marshal.go deleted file mode 100644 index a847c14dea..0000000000 --- a/core/java/jdbg/marshal.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "reflect" - - "github.com/google/gapid/core/java/jdwp" -) - -// marshal transforms o into a jdwp.Value. -func (j *JDbg) marshal(o interface{}) jdwp.Value { - switch o := o.(type) { - case bool, jdwp.Char, int, int8, - int16, int32, int64, float32, float64: - return o - - case nil: - return jdwp.ObjectID(0) - - case jdwp.Object: - return o.ID() - - case Value: - return j.marshal(o.val) - - case string: - id, err := j.conn.CreateString(o) - if err != nil { - j.fail("Failed to marshal string: %v", err) - } - return id - - case []byte: - return j.newArray(j.cache.byteTy, o) - - case []interface{}: - return j.newArray(j.cache.objTy, o) - - default: - j.fail("Unhandled type %T", o) - return nil - } -} - -// newArray creates a new array with element type elTy, filled with values. -func (j *JDbg) newArray(elTy Type, values interface{}) jdwp.ArrayID { - array := j.ArrayOf(elTy).New(reflect.ValueOf(values).Len()) - array.SetArrayValues(values) - return array.val.(jdwp.ArrayID) -} - -// toObjectType returns the corresponding java.lang.Object type for ty, or nil -// if there is no corresponding object type. -func (j *JDbg) toObjectType(ty reflect.Type) *Class { - switch ty.Kind() { - case reflect.Int: - return j.cache.intObjTy - case reflect.Int8, reflect.Uint8: - return j.cache.byteObjTy - case reflect.Int16: - return j.cache.shortObjTy - case reflect.Int32: - return j.cache.intObjTy - case reflect.Int64: - return j.cache.longObjTy - case reflect.Float32: - return j.cache.floatObjTy - case reflect.Float64: - return j.cache.doubleObjTy - default: - return nil - } -} - -// toObject returns the value of o transformed to a java.lang.Object held in a -// jdwp.Value. -func (j *JDbg) toObject(o interface{}) jdwp.Value { - if obj := j.toObjectType(reflect.TypeOf(o)); obj != nil { - return j.marshal(obj.New(o)) - } - - switch o := j.marshal(o).(type) { - case jdwp.ObjectID, jdwp.StringID, jdwp.ArrayID: - return o - case jdwp.TaggedObjectID: - return o.Object - default: - j.fail("Cannot convert %v (%T) to Object", o, o) - return nil - } -} - -func (j *JDbg) toObjects(l []interface{}) []interface{} { - objects := make([]interface{}, len(l)) - for i, v := range l { - objects[i] = j.toObject(v) - } - return objects -} - -// unmarshal unboxes the jdwp.Value into a corresponding golang value. -func (j *JDbg) unmarshal(v jdwp.Value) interface{} { - switch v := v.(type) { - case jdwp.StringID: - str, err := j.conn.GetString(v) - if err != nil { - j.fail("Failed to unmarshal string") - } - return str - default: - return v - } -} - -func (j *JDbg) marshalN(v []interface{}) []jdwp.Value { - out := make([]jdwp.Value, len(v)) - for i, v := range v { - out[i] = j.marshal(v) - } - return out -} - -func (j *JDbg) unmarshalN(v []jdwp.Value) []interface{} { - out := make([]interface{}, len(v)) - for i, v := range v { - out[i] = j.unmarshal(v) - } - return out -} diff --git a/core/java/jdbg/method_signature.go b/core/java/jdbg/method_signature.go deleted file mode 100644 index 20000469c7..0000000000 --- a/core/java/jdbg/method_signature.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import "fmt" - -// methodSignature represents a method signature -type methodSignature struct { - Parameters []Type - Return Type -} - -// accepts returns true if the signature accepts the list of arguments. -func (j *JDbg) accepts(s methodSignature, args []interface{}) bool { - if len(args) != len(s.Parameters) { - return false - } - for i := range args { - if !j.assignable(s.Parameters[i], args[i]) { - return false - } - } - return true -} - -// parseMethodSignature returns the signature from the string str. -func (j *JDbg) parseMethodSignature(str string) (methodSignature, error) { - s := methodSignature{} - if str[0] != '(' { - return methodSignature{}, fmt.Errorf("Method signature doesn't start with '('") - } - i := 1 - for str[i] != ')' { - ty, err := j.parseSignature(str, &i) - if err != nil { - return methodSignature{}, err - } - s.Parameters = append(s.Parameters, ty) - } - i++ - ty, err := j.parseSignature(str, &i) - if err != nil { - return methodSignature{}, err - } - s.Return = ty - return s, nil -} diff --git a/core/java/jdbg/methods.go b/core/java/jdbg/methods.go deleted file mode 100644 index 24a24b37d5..0000000000 --- a/core/java/jdbg/methods.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "fmt" - "strings" - - "github.com/google/gapid/core/java/jdwp" -) - -const ( - constructor = "" -) - -// method describes a Java function. -type method struct { - id jdwp.MethodID - mod jdwp.ModBits - name string - sig methodSignature - class *Class -} - -func (m method) String() string { - args := make([]string, len(m.sig.Parameters)) - for i, a := range m.sig.Parameters { - args[i] = fmt.Sprintf("%v", a) - } - if m.name == constructor { - return fmt.Sprintf("%v %v(%v)", m.mod, m.class.String(), strings.Join(args, ", ")) - } - return fmt.Sprintf("%v %v %v.%v(%v)", m.mod, m.sig.Return, m.class.String(), m.name, strings.Join(args, ", ")) -} - -// methods is a list of methods. -type methods []method - -func (m methods) String() string { - lines := make([]string, len(m)) - for i, m := range m { - lines[i] = m.String() - } - return strings.Join(lines, "\n") -} - -// filter returns a copy of the method list with the methods that fail the -// predicate test removed. -func (m methods) filter(predicate func(m method) bool) methods { - out := make(methods, 0, len(m)) - for _, m := range m { - if predicate(m) { - out = append(out, m) - } - } - return out -} diff --git a/core/java/jdbg/resolve_overload.go b/core/java/jdbg/resolve_overload.go deleted file mode 100644 index cb33189c83..0000000000 --- a/core/java/jdbg/resolve_overload.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "bytes" - "fmt" - "strings" -) - -// resolveMethodErr is the error used when resolveMethod() fails. -type resolveMethodErr struct { - class *Class - name string - args []interface{} - candidates methods - problem string -} - -func (e resolveMethodErr) Error() string { - name := e.name - if name == constructor { - name = e.class.name - } - argTys := make([]string, len(e.args)) - for i, a := range e.args { - switch a := a.(type) { - case Value: - argTys[i] = fmt.Sprintf("%v", a.Type()) - default: - argTys[i] = fmt.Sprintf("%T", a) - } - } - sig := fmt.Sprintf("%v(%v)", name, strings.Join(argTys, ", ")) - problem := fmt.Sprintf(e.problem, sig) - if len(e.candidates) == 0 { - return problem - } - msg := bytes.Buffer{} - msg.WriteString(problem) - msg.WriteString("\n") - for _, candidate := range e.candidates { - line, marks := bytes.Buffer{}, bytes.Buffer{} - line.WriteString(candidate.name) - line.WriteRune('(') - marks.WriteString(strings.Repeat(" ", line.Len())) - for i, param := range candidate.sig.Parameters { - if i > 0 { - line.WriteString(", ") - marks.WriteString(" ") - } - ty := param.String() - line.WriteString(ty) - if i < len(e.args) && e.class.j.assignable(param, e.args[i]) { - marks.WriteString(strings.Repeat(" ", len(ty))) - } else { - marks.WriteString(strings.Repeat("^", len(ty))) - } - } - msg.WriteString(line.String()) - msg.WriteString(")\n") - msg.WriteString(marks.String()) - msg.WriteString("\n") - } - return msg.String() -} - -// resolveMethod attempts to unambiguously resolve a single method with the -// specified name and arguments from the class's method list. -// If considerSuper is true then the all base types will also be searched. -func (j *JDbg) resolveMethod(considerSuper bool, class *Class, name string, args []interface{}) method { - var methods []method - for search := class; search != nil; search = search.super { - methods = j.resolveMethods(search, name, args) - switch len(methods) { - case 0: - break - case 1: - return methods[0] - default: - j.err(resolveMethodErr{class, name, args, methods, "Ambiguous call to %v. Candidates:"}) - } - if !considerSuper { - break - } - } - resolved := class.resolve() - sameName := resolved.allMethods.filter(func(m method) bool { return m.name == name }) - if len(sameName) > 0 { - j.err(resolveMethodErr{class, name, args, sameName, "No methods match %v. Candidates:"}) - } - if considerSuper { - j.err(resolveMethodErr{class, name, args, resolved.allMethods, "No methods match %v. All methods:"}) - } - j.err(resolveMethodErr{class, name, args, resolved.methods, "No methods match %v. All methods:"}) - return method{} -} - -func (j *JDbg) resolveMethods(t *Class, name string, args []interface{}) []method { - candidates := t.resolve().methods.filter(func(m method) bool { - return m.name == name && len(m.sig.Parameters) == len(args) - }) - if len(candidates) == 0 { - return nil - } - return candidates.filter(func(m method) bool { return j.accepts(m.sig, args) }) -} diff --git a/core/java/jdbg/signature.go b/core/java/jdbg/signature.go deleted file mode 100644 index e69a9f4a3f..0000000000 --- a/core/java/jdbg/signature.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import "fmt" - -// parseSignature returns the type for the signature string starting at offset. -// offset will be modified so that it is one byte beyond the end of the parsed -// string. -func (j *JDbg) parseSignature(sig string, offset *int) (Type, error) { - r := sig[*offset] - *offset++ - switch r { - case 'V': - return j.cache.voidTy, nil - case 'Z': - return j.cache.boolTy, nil - case 'B': - return j.cache.byteTy, nil - case 'C': - return j.cache.charTy, nil - case 'S': - return j.cache.shortTy, nil - case 'I': - return j.cache.intTy, nil - case 'J': - return j.cache.longTy, nil - case 'F': - return j.cache.floatTy, nil - case 'D': - return j.cache.doubleTy, nil - case 'L': - // fully-qualified-class - start := *offset - 1 // include 'L' - for *offset < len(sig) { - r := sig[*offset] - *offset++ - if r == ';' { - return j.classFromSig(sig[start:*offset]) - } - } - return nil, fmt.Errorf("Fully qualified class missing terminating ';'") - case '[': - start := *offset - 1 // include '[' - el, err := j.parseSignature(sig, offset) - if err != nil { - return nil, err - } - sig := sig[start:*offset] - if array, ok := j.cache.arrays[sig]; ok { - return array, nil - } - class, err := j.classFromSig(sig) - if err != nil { - return nil, err - } - array := &Array{class, el} - j.cache.arrays[sig] = array - return array, nil - default: - return nil, fmt.Errorf("Unknown signature type tag '%v'", r) - } -} diff --git a/core/java/jdbg/type.go b/core/java/jdbg/type.go deleted file mode 100644 index 4ce3da0020..0000000000 --- a/core/java/jdbg/type.go +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "fmt" - - "github.com/google/gapid/core/java/jdwp" -) - -// Type represents a Java type. -type Type interface { - // String returns the string representation of the type. - String() string - // Signature returns the Java signature for the type. - Signature() string - // CastableTo returns true if this type can be cast to ty. - CastableTo(ty Type) bool - // Call invokes the static method with the specified arguments. - Call(method string, args ...interface{}) Value - - call(object Value, method string, args []interface{}) Value - field(object Value, name string) Value - jdbg() *JDbg -} - -// Simple is a primitive type. -type Simple struct { - j *JDbg - ty jdwp.Tag -} - -func (t *Simple) String() string { - switch t.ty { - case jdwp.TagVoid: - return "void" - case jdwp.TagBoolean: - return "boolean" - case jdwp.TagByte: - return "byte" - case jdwp.TagChar: - return "char" - case jdwp.TagShort: - return "short" - case jdwp.TagInt: - return "int" - case jdwp.TagLong: - return "long" - case jdwp.TagFloat: - return "float" - case jdwp.TagDouble: - return "double" - default: - return t.ty.String() - } -} - -// Signature returns the Java signature for the type. -func (t *Simple) Signature() string { - switch t.ty { - case jdwp.TagVoid: - return "V" - case jdwp.TagBoolean: - return "Z" - case jdwp.TagByte: - return "B" - case jdwp.TagChar: - return "C" - case jdwp.TagShort: - return "S" - case jdwp.TagInt: - return "I" - case jdwp.TagLong: - return "J" - case jdwp.TagFloat: - return "F" - case jdwp.TagDouble: - return "D" - default: - return t.ty.String() - } -} - -// CastableTo returns true if this type can be cast to ty. -func (t *Simple) CastableTo(ty Type) bool { - return t == ty || ty == t.j.ObjectType() -} - -// Call invokes the static method with the specified arguments. -func (t *Simple) Call(method string, args ...interface{}) Value { - return t.call(Value{}, method, args) -} - -func (t *Simple) call(object Value, method string, args []interface{}) Value { - t.j.fail("Type '%v' does not support methods", t.ty) - return Value{} -} - -func (t *Simple) field(object Value, name string) Value { - t.j.fail("Type '%v' does not support fields", t.ty) - return Value{} -} - -func (t *Simple) jdbg() *JDbg { return t.j } - -// Array is the type of an array. -type Array struct { - *Class - el Type -} - -func (t *Array) String() string { return fmt.Sprintf("%v[]", t.el) } - -// CastableTo returns true if this type can be cast to ty. -func (t *Array) CastableTo(ty Type) bool { - if t == ty { - return true - } - return t.Class.CastableTo(ty) -} - -// New constructs a new array of the specified size. -func (t *Array) New(size int) Value { - array, err := t.j.conn.NewArray(jdwp.ArrayTypeID(t.class.TypeID), size) - if err != nil { - t.j.fail("Failed to create array: %v", err) - } - if array.Type != jdwp.TagArray { - t.j.fail("NewArray returned %v, not array", array.Type) - } - return newValue(t, jdwp.ArrayID(array.Object)) -} - -type classResolvedInfo struct { - methods methods - fields jdwp.Fields - interfaces []*Class - allMethods methods // Include super's allMethods - error error -} - -// Class is the type of an object. -type Class struct { - j *JDbg - signature string - name string - class jdwp.ClassInfo - implements []*Class - fields jdwp.Fields - super *Class - resolved *classResolvedInfo -} - -func (t *Class) String() string { return t.name } - -// ID returns the JDWP class identifier. -func (t *Class) ID() jdwp.ClassID { return t.class.ClassID() } - -// Signature returns the Java signature for the type. -func (t *Class) Signature() string { return t.signature } - -// New returns a new instance of the class type using the specified parameters. -func (t *Class) New(args ...interface{}) Value { - m := t.j.resolveMethod(false, t, constructor, args) - values := t.j.marshalN(args) - res, err := t.j.conn.NewInstance( - m.class.class.ClassID(), m.id, t.j.thread, jdwp.InvokeSingleThreaded, values...) - if err != nil { - t.j.fail("NewInstance() returned: %v", err) - } - t.j.errFromException(res.Exception, m) - return newValue(t, res.Result) -} - -// CastableTo returns true if this type can be cast to ty. -func (t *Class) CastableTo(ty Type) bool { - if t == ty { - return true - } - for _, i := range t.implements { - if i.CastableTo(ty) { - return true - } - } - if t.super != nil { - return t.super.CastableTo(ty) - } - return false -} - -// Call invokes a static method on the class. -func (t *Class) Call(method string, args ...interface{}) Value { - return t.call(Value{}, method, args) -} - -// Field returns the value of the static field with the given name. -func (t *Class) Field(name string) Value { - field := t.resolve().fields.FindByName(name) - values, err := t.j.conn.GetStaticFieldValues(t.class.TypeID, field.ID) - if err != nil { - t.j.fail("GetValues() returned: %v", err) - } - return t.j.value(values[0]) -} - -// Super returns the super class type. -func (t *Class) Super() *Class { - return t.super -} - -func (t *Class) call(object Value, method string, args []interface{}) Value { - m := t.j.resolveMethod(object != nilValue, t, method, args) - values := t.j.marshalN(args) - - var res jdwp.InvokeResult - var err error - if m.mod&jdwp.ModStatic != 0 { - res, err = t.j.conn.InvokeStaticMethod( - t.class.ClassID(), m.id, t.j.thread, jdwp.InvokeSingleThreaded, values...) - } else { - if object == nilValue { - t.j.fail("Cannot call non-static method '%v' without an object", method) - } - var obj interface{} - obj = object.val - object, ok := obj.(jdwp.Object) - if !ok { - t.j.fail("Cannot call methods on %T types", obj) - } - res, err = t.j.conn.InvokeMethod( - object.ID(), t.class.ClassID(), m.id, t.j.thread, jdwp.InvokeSingleThreaded, values...) - } - if err != nil { - t.j.err(err) - } - - t.j.errFromException(res.Exception, m) - - result, isResultObject := res.Result.(jdwp.Object) - if !isResultObject { - if _, expectedClass := m.sig.Return.(*Class); expectedClass { - panic(fmt.Errorf("Call of %v returned value %T(%v) when %v was expected", - method, res.Result, res.Result, m.sig.Return)) - } - return newValue(m.sig.Return, res.Result) - } - - if result.ID() == 0 { - return Value{m.sig.Return, result.ID()} // null pointer - } - - tyID, err := t.j.conn.GetObjectType(result.ID()) - if err != nil { - t.j.fail("GetObjectType() returned: %v", err) - } - - ty := t.j.typeFromID(tyID.Type) - if !ty.CastableTo(m.sig.Return) { - t.j.fail("Call of %v returned type %v which is not castable to %v", - method, ty, m.sig.Return) - } - - return newValue(ty, res.Result) -} - -func (t *Class) field(object Value, name string) Value { - if object == nilValue { - t.j.fail("Cannot get field '%v' on nill object", name) - } - f := t.fields.FindByName(name) - if f == nil { - t.j.fail("Class '%v' does not contain field '%v'", t.name, name) - } - obj, ok := object.val.(jdwp.Object) - if !ok { - t.j.fail("Class '%v' does not support fields", t.name) - } - vals, err := t.j.conn.GetFieldValues(obj.ID(), f.ID) - if err != nil { - t.j.fail("GetFieldValues() returned: %v", err) - } - if len(vals) != 1 { - t.j.fail("GetFieldValues() returned %n values, expected 1", len(vals)) - } - return t.j.value(vals[0]) -} - -func (t *Class) jdbg() *JDbg { return t.j } - -func (t *Class) resolve() *classResolvedInfo { - if t.resolved != nil { - return t.resolved - } - t.resolved = &classResolvedInfo{} - - f, err := t.j.conn.GetFields(t.class.TypeID) - if err != nil { - t.resolved.error = err - return t.resolved - } - t.resolved.fields = f - - m, err := t.j.conn.GetMethods(t.class.TypeID) - if err != nil { - t.resolved.error = err - return t.resolved - } - t.resolved.methods = make([]method, 0, len(m)) - for _, m := range m { - sig, err := t.j.parseMethodSignature(m.Signature) - if err != nil { - // Probably uses a type that hasn't been loaded. Ignore. - continue - } - t.resolved.methods = append(t.resolved.methods, method{ - id: m.ID, - mod: m.ModBits, - name: m.Name, - sig: sig, - class: t, - }) - } - // build allMethods from methods and super's allMethods - var superMethods methods - if t.super != nil { - if resolved := t.super.resolve(); resolved.error == nil { - superMethods = resolved.allMethods - } - } - all := make(methods, 0, len(t.resolved.methods)+len(superMethods)) - t.resolved.allMethods = append(append(all, t.resolved.methods...), superMethods...) - - return t.resolved -} - -func (j *JDbg) errFromException(exception jdwp.TaggedObjectID, method method) { - if (exception.Type == 0 || exception.Type == jdwp.TagObject) && exception.Object == 0 { - return - } - str := j.object(exception.Object).Call("toString").Get() - j.fail("Exception raised calling: %v\n%v", method, str) -} diff --git a/core/java/jdbg/value.go b/core/java/jdbg/value.go deleted file mode 100644 index c6b66759ec..0000000000 --- a/core/java/jdbg/value.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdbg - -import ( - "fmt" - "reflect" - - "github.com/google/gapid/core/java/jdwp" -) - -var nilValue Value - -// Value holds the value of a call. -type Value struct { - ty Type - val interface{} -} - -func newValue(ty Type, val interface{}) Value { - if obj, ok := val.(jdwp.Object); ok { - // Prevent GC of this object for the duration of the jdbg.Do call. - j, id := ty.jdbg(), obj.ID() - j.conn.DisableGC(id) - j.objects = append(j.objects, id) - } - return Value{ty, val} -} - -// Call invokes the method on the value. -func (v Value) Call(method string, args ...interface{}) Value { - return v.ty.call(v, method, args) -} - -// Field returns the value of the specified field. -func (v Value) Field(name string) Value { - return v.ty.field(v, name) -} - -// Get returns the value, unmarshalled. -func (v Value) Get() interface{} { - return v.ty.jdbg().unmarshal(v.val) -} - -// Type returns the value's type. -func (v Value) Type() Type { - return v.ty -} - -// AsType returns the value as a type. -func (v Value) AsType() Type { - j := v.ty.jdbg() - switch v := v.val.(type) { - case jdwp.ClassObjectID: - id, err := j.conn.ReflectedType(v) - if err != nil { - j.fail("%v", err) - } - return j.typeFromID(id) - } - panic(fmt.Errorf("Unhandled value type: %T %+v", v.val, v.val)) -} - -// SetArrayValues sets the array values to values. This value must be an Array. -func (v Value) SetArrayValues(values interface{}) { - j := v.ty.jdbg() - arrayTy, ok := v.ty.(*Array) - if !ok { - j.fail("SetArrayValues can only be used with Arrays, type is %v", v.ty) - } - r := reflect.ValueOf(values) - if r.Kind() != reflect.Array && r.Kind() != reflect.Slice { - j.fail("values must be an array or slice, got %v", r.Kind()) - } - - if !j.assignableT(v.ty, reflect.TypeOf(values)) { - j.fail("value elements (type %T) does not match array element type %v", values, arrayTy.el) - } - - if arrayTy.el == j.cache.objTy { - values = j.toObjects(values.([]interface{})) - } - - if err := j.conn.SetArrayValues(v.val.(jdwp.ArrayID), 0, values); err != nil { - j.fail("Failed to set array (type %s) values (type %T): %v", arrayTy, values, err) - } -} - -// Variable is a named Value. -type Variable struct { - Value Value - variable jdwp.VariableRequest -} diff --git a/core/java/jdwp/BUILD.bazel b/core/java/jdwp/BUILD.bazel deleted file mode 100644 index 12f80d821d..0000000000 --- a/core/java/jdwp/BUILD.bazel +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "class_status.go", - "cmdset_arrayreference.go", - "cmdset_arraytype.go", - "cmdset_classobjectreference.go", - "cmdset_classtype.go", - "cmdset_eventrequest.go", - "cmdset_method.go", - "cmdset_objectreference.go", - "cmdset_referencetypes.go", - "cmdset_stackframe.go", - "cmdset_stringreference.go", - "cmdset_threadreference.go", - "cmdset_vm.go", - "cmdsets.go", - "coder.go", - "debug.go", - "errors.go", - "event.go", - "event_kind.go", - "field.go", - "helpers.go", - "invoke_options.go", - "jdwp.go", - "method.go", - "modbits.go", - "packet.go", - "recv.go", - "suspend_policy.go", - "tag.go", - "thread_status.go", - "type_tag.go", - "types.go", - "value.go", - ], - importpath = "github.com/google/gapid/core/java/jdwp", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/data/binary:go_default_library", - "//core/data/endian:go_default_library", - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/os/device:go_default_library", - ], -) - -go_test( - name = "go_default_test", - size = "small", - srcs = ["jdwp_test.go"], - embed = [":go_default_library"], - tags = ["integration"], - deps = [ - "//core/assert:go_default_library", - "//core/java/jdwp/test:go_default_library", - "//core/log:go_default_library", - ], -) diff --git a/core/java/jdwp/class_status.go b/core/java/jdwp/class_status.go deleted file mode 100644 index a9c82d5dbc..0000000000 --- a/core/java/jdwp/class_status.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "strings" - -// ClassStatus is an enumerator of class loading state. -// See https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3 -// for detailed descriptions of the loading states. -type ClassStatus int - -const ( - // StatusVerified is used to describe a class in the verified state. - StatusVerified = ClassStatus(1) - // StatusPrepared is used to describe a class in the prepared state. - StatusPrepared = ClassStatus(2) - // StatusInitialized is used to describe a class in the initialized state. - StatusInitialized = ClassStatus(4) - // StatusError is used to describe a class in the error state. - StatusError = ClassStatus(8) -) - -func (c ClassStatus) String() string { - parts := []string{} - if c&StatusVerified != 0 { - parts = append(parts, "Verified") - } - if c&StatusPrepared != 0 { - parts = append(parts, "Prepared") - } - if c&StatusInitialized != 0 { - parts = append(parts, "Initialized") - } - if c&StatusError != 0 { - parts = append(parts, "Error") - } - return strings.Join(parts, ", ") -} diff --git a/core/java/jdwp/cmdset_arrayreference.go b/core/java/jdwp/cmdset_arrayreference.go deleted file mode 100644 index 3f99f4e30f..0000000000 --- a/core/java/jdwp/cmdset_arrayreference.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// GetArrayLength returns the length of the specified array. -func (c *Connection) GetArrayLength(id ArrayID) (int, error) { - var res int - err := c.get(cmdArrayReferenceLength, id, &res) - return res, err -} - -// GetArrayValues the values of the specified array. -func (c *Connection) GetArrayValues(id ArrayID, first, length int) ([]Value, error) { - req := struct { - ID ArrayID - First int - Length int - }{id, first, length} - var res []Value - err := c.get(cmdArrayReferenceGetValues, req, &res) - return res, err -} - -// SetArrayValues the values of the specified array. -func (c *Connection) SetArrayValues(id ArrayID, first int, values interface{}) error { - req := struct { - ID ArrayID - First int - Values interface{} - }{id, first, values} - return c.get(cmdArrayReferenceSetValues, req, nil) -} diff --git a/core/java/jdwp/cmdset_arraytype.go b/core/java/jdwp/cmdset_arraytype.go deleted file mode 100644 index 71eec05535..0000000000 --- a/core/java/jdwp/cmdset_arraytype.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// NewArray constructs a new array of the specified type and length. -func (c *Connection) NewArray(ty ArrayTypeID, length int) (TaggedObjectID, error) { - req := struct { - Ty ArrayTypeID - Length int - }{ty, length} - var res TaggedObjectID - err := c.get(cmdArrayTypeNewInstance, req, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_classobjectreference.go b/core/java/jdwp/cmdset_classobjectreference.go deleted file mode 100644 index 020fd80be8..0000000000 --- a/core/java/jdwp/cmdset_classobjectreference.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// ReflectedType returns the reference type reflected by the class object. -func (c *Connection) ReflectedType(id ClassObjectID) (ReferenceTypeID, error) { - req := struct { - ID ClassObjectID - }{id} - var res struct { - Kind byte - ID ReferenceTypeID - } - err := c.get(cmdClassObjectReferenceReflectedType, req, &res) - return res.ID, err -} diff --git a/core/java/jdwp/cmdset_classtype.go b/core/java/jdwp/cmdset_classtype.go deleted file mode 100644 index 378610e839..0000000000 --- a/core/java/jdwp/cmdset_classtype.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// InvokeResult holds the return values for a method invokation. -type InvokeResult struct { - Result Value - Exception TaggedObjectID -} - -// GetSuperClass returns the immediate super class of the specified class. -func (c *Connection) GetSuperClass(class ClassID) (ClassID, error) { - var res ClassID - err := c.get(cmdClassTypeSuperclass, class, &res) - return res, err -} - -// InvokeStaticMethod invokes the specified static method. -func (c *Connection) InvokeStaticMethod(class ClassID, method MethodID, thread ThreadID, options InvokeOptions, args ...Value) (InvokeResult, error) { - req := struct { - Class ClassID - Thread ThreadID - Method MethodID - Args []Value - Options InvokeOptions - }{class, thread, method, args, options} - var res InvokeResult - err := c.get(cmdClassTypeInvokeMethod, req, &res) - return res, err -} - -// NewInstanceResult holds the return values for a constructor invokation. -type NewInstanceResult struct { - Result TaggedObjectID - Exception TaggedObjectID -} - -// NewInstance invokes the specified constructor. -func (c *Connection) NewInstance(class ClassID, constructor MethodID, thread ThreadID, options InvokeOptions, args ...Value) (NewInstanceResult, error) { - req := struct { - Class ClassID - Thread ThreadID - Constructor MethodID - Args []Value - Options InvokeOptions - }{class, thread, constructor, args, options} - var res NewInstanceResult - err := c.get(cmdClassTypeNewInstance, req, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_eventrequest.go b/core/java/jdwp/cmdset_eventrequest.go deleted file mode 100644 index 88b1a55663..0000000000 --- a/core/java/jdwp/cmdset_eventrequest.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/event/task" -) - -// EventRequestID is an identifier of an event request. -type EventRequestID int - -const cmdCompositeEvent = cmdID(100) - -// WatchEvents sets an event watcher, calling handler for each received event. -// WatchEvents will continue to watch for events until handler returns false or -// the context is cancelled. -func (c *Connection) WatchEvents( - ctx context.Context, - kind EventKind, - suspendPolity SuspendPolicy, - handler func(Event) bool, - modifiers ...EventModifier) error { - - req := struct { - Kind EventKind - SuspendPolicy SuspendPolicy - Modifiers []EventModifier - }{ - Kind: kind, - SuspendPolicy: suspendPolity, - Modifiers: modifiers, - } - - var id EventRequestID - err := c.get(cmdEventRequestSet, req, &id) - if err != nil { - return err - } - - events := make(chan Event, 8) - c.Lock() - c.events[id] = events - c.Unlock() - - defer func() { - c.Lock() - delete(c.events, id) - c.Unlock() - }() - - if err := c.ResumeAll(); err != nil { - return err - } - -run: // Consume events until the handler returns false or the context is cancelled. - for { - select { - case event := <-events: - if !handler(event) { - break run - } - case <-task.ShouldStop(ctx): - break run - } - } - - // Clear the event. - clear := struct { - Kind EventKind - ID EventRequestID - }{ - Kind: kind, - ID: id, - } - - if err := c.get(cmdEventRequestClear, clear, nil); err != nil { - return err - } - -flush: // Consume any remaining events in the pipe. - for { - select { - case event := <-events: - handler(event) - default: - break flush - } - } - - return nil -} - -// EventModifier is the interface implemented by all event modifier types. -// These are filters on the events that are raised. -// See http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Set -// for detailed descriptions and rules for each of the EventModifiers. -type EventModifier interface { - modKind() uint8 -} - -// CountEventModifier is an EventModifier that limits the number of times an -// event is fired. For example, using a CountEventModifier of 2 will only let -// two events fire. -type CountEventModifier int - -// ThreadOnlyEventModifier is an EventModifier that filters the events to those -// that are raised on the specified thread. -type ThreadOnlyEventModifier ThreadID - -// ClassOnlyEventModifier is an EventModifier that filters the events to those -// that are associated with the specified class. -type ClassOnlyEventModifier ClassID - -// ClassMatchEventModifier is an EventModifier that filters the events to those -// that are associated with class names that match the pattern. The pattern can -// be an exact class name match, for use a '*' wildcard at the start or end of -// the string. Examples: -// • "java.lang.String" -// • "*.String" -// • "java.lang.*" -type ClassMatchEventModifier string - -// ClassExcludeEventModifier is an EventModifier that filters the events to -// those that are not associated with class names that match the pattern. -// See ClassMatchEventModifier for the permitted patterns. -type ClassExcludeEventModifier string - -// LocationOnlyEventModifier is an EventModifier that filters the events to -// those that only originate at the specified location. -type LocationOnlyEventModifier Location - -// ExceptionOnlyEventModifier is an EventModifier that filters exception events. -// Can only be used for exception events. -type ExceptionOnlyEventModifier struct { - ExceptionOrNull ReferenceTypeID // If not nil, only permit exceptions of this type. - Caught bool // Report caught exceptions - Uncaught bool // Report uncaught exceptions -} - -// FieldOnlyEventModifier is an EventModifier that filters events to those -// relating to the specified field. -// Can only be used for field access or field modified events. -type FieldOnlyEventModifier struct { - Type ReferenceTypeID - Field FieldID -} - -// StepEventModifier is an EventModifier that filters step events to those which -// satisfy depth and size constraints. -// Can only be used with step events. -type StepEventModifier struct { - Thread ThreadID - Size int - Depth int -} - -// InstanceOnlyEventModifier is an EventModifier that filters events to those -// which have the specified 'this' object. -type InstanceOnlyEventModifier ObjectID - -func (CountEventModifier) modKind() uint8 { return 1 } -func (ThreadOnlyEventModifier) modKind() uint8 { return 3 } -func (ClassOnlyEventModifier) modKind() uint8 { return 4 } -func (ClassMatchEventModifier) modKind() uint8 { return 5 } -func (ClassExcludeEventModifier) modKind() uint8 { return 6 } -func (LocationOnlyEventModifier) modKind() uint8 { return 7 } -func (ExceptionOnlyEventModifier) modKind() uint8 { return 8 } -func (FieldOnlyEventModifier) modKind() uint8 { return 9 } -func (StepEventModifier) modKind() uint8 { return 10 } -func (InstanceOnlyEventModifier) modKind() uint8 { return 11 } - -func (m CountEventModifier) String() string { - return fmt.Sprintf("CountEventModifier<%v>", int(m)) -} -func (m ThreadOnlyEventModifier) String() string { - return fmt.Sprintf("ThreadOnlyEventModifier<%v>", int(m)) -} -func (m ClassOnlyEventModifier) String() string { - return fmt.Sprintf("ClassOnlyEventModifier<%v>", int(m)) -} -func (m ClassMatchEventModifier) String() string { - return fmt.Sprintf("ClassMatchEventModifier<%v>", string(m)) -} -func (m ClassExcludeEventModifier) String() string { - return fmt.Sprintf("ClassExcludeEventModifier<%v>", string(m)) -} -func (m LocationOnlyEventModifier) String() string { - return fmt.Sprintf("LocationOnlyEventModifier<%v>", Location(m)) -} -func (m ExceptionOnlyEventModifier) String() string { - return fmt.Sprintf("ExceptionOnlyEventModifier", - m.ExceptionOrNull, m.Caught, m.Uncaught) -} -func (m FieldOnlyEventModifier) String() string { - return fmt.Sprintf("FieldOnlyEventModifier", m.Type, m.Field) -} -func (m StepEventModifier) String() string { - return fmt.Sprintf("StepEventModifier", - m.Thread, m.Size, m.Depth) -} -func (m InstanceOnlyEventModifier) String() string { - return fmt.Sprintf("InstanceOnlyEventModifier<%v>", ObjectID(m)) -} diff --git a/core/java/jdwp/cmdset_method.go b/core/java/jdwp/cmdset_method.go deleted file mode 100644 index 560cf2bf55..0000000000 --- a/core/java/jdwp/cmdset_method.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// VariableTable returns all of the variables that are present in the given -// Method. -func (c *Connection) VariableTable(classTy ReferenceTypeID, method MethodID) (VariableTable, error) { - req := struct { - Class ReferenceTypeID - Method MethodID - }{classTy, method} - var res VariableTable - err := c.get(cmdMethodTypeVariableTable, req, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_objectreference.go b/core/java/jdwp/cmdset_objectreference.go deleted file mode 100644 index 4478a4c63a..0000000000 --- a/core/java/jdwp/cmdset_objectreference.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// ObjectType describes a Java type. -type ObjectType struct { - Kind TypeTag - Type ReferenceTypeID -} - -// GetObjectType returns the type of the specified object. -func (c *Connection) GetObjectType(object ObjectID) (ObjectType, error) { - var res ObjectType - err := c.get(cmdObjectReferenceReferenceType, object, &res) - return res, err -} - -// GetFieldValues returns the values of all the instance fields. -func (c *Connection) GetFieldValues(obj ObjectID, fields ...FieldID) ([]Value, error) { - var res []Value - err := c.get(cmdObjectReferenceGetValues, struct { - Obj ObjectID - Fields []FieldID - }{obj, fields}, &res) - return res, err -} - -// InvokeMethod invokes the specified static method. -func (c *Connection) InvokeMethod(object ObjectID, class ClassID, method MethodID, thread ThreadID, options InvokeOptions, args ...Value) (InvokeResult, error) { - req := struct { - Object ObjectID - Thread ThreadID - Class ClassID - Method MethodID - Args []Value - Options InvokeOptions - }{object, thread, class, method, args, options} - var res InvokeResult - err := c.get(cmdObjectReferenceInvokeMethod, req, &res) - return res, err -} - -// DisableGC disables garbage collection for the specified object. -func (c *Connection) DisableGC(object ObjectID) error { - return c.get(cmdObjectReferenceDisableCollection, object, nil) -} - -// EnableGC enables garbage collection for the specified object. -func (c *Connection) EnableGC(object ObjectID) error { - return c.get(cmdObjectReferenceEnableCollection, object, nil) -} diff --git a/core/java/jdwp/cmdset_referencetypes.go b/core/java/jdwp/cmdset_referencetypes.go deleted file mode 100644 index 26909bca87..0000000000 --- a/core/java/jdwp/cmdset_referencetypes.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// GetTypeSignature returns the Java type signature for the specified type. -func (c *Connection) GetTypeSignature(ty ReferenceTypeID) (string, error) { - var res string - err := c.get(cmdReferenceTypeSignature, ty, &res) - return res, err -} - -// GetFields returns all the fields for the specified type. -func (c *Connection) GetFields(ty ReferenceTypeID) (Fields, error) { - var res Fields - err := c.get(cmdReferenceTypeFields, ty, &res) - return res, err -} - -// GetMethods returns all the methods for the specified type. -func (c *Connection) GetMethods(ty ReferenceTypeID) (Methods, error) { - var res Methods - err := c.get(cmdReferenceTypeMethods, ty, &res) - return res, err -} - -// GetStaticFieldValues returns the values of all the requests static fields. -func (c *Connection) GetStaticFieldValues(ty ReferenceTypeID, fields ...FieldID) ([]Value, error) { - var res []Value - err := c.get(cmdReferenceTypeGetValues, struct { - Ty ReferenceTypeID - Fields []FieldID - }{ty, fields}, &res) - return res, err -} - -// GetImplemented returns all the direct interfaces implemented by the specified -// type. -func (c *Connection) GetImplemented(ty ReferenceTypeID) ([]InterfaceID, error) { - var res []InterfaceID - err := c.get(cmdReferenceTypeInterfaces, ty, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_stackframe.go b/core/java/jdwp/cmdset_stackframe.go deleted file mode 100644 index 9ea91cdcac..0000000000 --- a/core/java/jdwp/cmdset_stackframe.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// GetThisObject returns the this object for the specified thread and stack -// frame. -func (c *Connection) GetThisObject(thread ThreadID, frame FrameID) (TaggedObjectID, error) { - req := struct { - Thread ThreadID - Frame FrameID - }{thread, frame} - res := TaggedObjectID{} - err := c.get(cmdStackFrameThisObject, req, &res) - return res, err -} - -type VariableRequest struct { - Index int - Tag uint8 -} - -// GetValues returns the set of objects for the specified thread and frame, -// based on their slots. -func (c *Connection) GetValues(thread ThreadID, frame FrameID, slots []VariableRequest) ([]Value, error) { - req := struct { - Thread ThreadID - Frame FrameID - Slots []VariableRequest - }{thread, frame, slots} - res := ValueSlice{} - err := c.get(cmdStackFrameGetValues, req, &res) - return res, err -} - -type VariableAssignmentRequest struct { - Index int - Value Value -} - -// SetValues sets the values for the local variables given thread and frame -func (c *Connection) SetValues(thread ThreadID, frame FrameID, slots []VariableAssignmentRequest) error { - req := struct { - Thread ThreadID - Frame FrameID - Slots []VariableAssignmentRequest - }{thread, frame, slots} - - err := c.get(cmdStackFrameSetValues, req, nil) - return err -} diff --git a/core/java/jdwp/cmdset_stringreference.go b/core/java/jdwp/cmdset_stringreference.go deleted file mode 100644 index 74e1cfa863..0000000000 --- a/core/java/jdwp/cmdset_stringreference.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// GetString returns the string text for the given StringID. -func (c *Connection) GetString(id StringID) (string, error) { - var res string - err := c.get(cmdStringReferenceValue, id, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_threadreference.go b/core/java/jdwp/cmdset_threadreference.go deleted file mode 100644 index dd15a112ba..0000000000 --- a/core/java/jdwp/cmdset_threadreference.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// GetThreadName returns a thread's name. -func (c *Connection) GetThreadName(id ThreadID) (string, error) { - var res string - err := c.get(cmdThreadReferenceName, id, &res) - return res, err -} - -// Suspend suspends the specified thread. -func (c *Connection) Suspend(id ThreadID) error { - var res struct{} - return c.get(cmdThreadReferenceSuspend, id, &res) -} - -// Resume resumes the specified thread. -func (c *Connection) Resume(id ThreadID) error { - var res struct{} - return c.get(cmdThreadReferenceResume, id, &res) -} - -// GetThreadStatus returns the status of the thread. -func (c *Connection) GetThreadStatus(id ThreadID) (ThreadStatus, SuspendStatus, error) { - var res struct { - T ThreadStatus - S SuspendStatus - } - err := c.get(cmdThreadReferenceStatus, id, &res) - if err != nil { - return 0, 0, err - } - return res.T, res.S, nil -} - -// GetSuspendCount returns the number of times the thread has been suspended -// without a corresponding resume. -func (c *Connection) GetSuspendCount(id ThreadID) (int, error) { - var count int - err := c.get(cmdThreadReferenceSuspendCount, id, &count) - if err != nil { - return 0, err - } - return count, nil -} - -// FrameInfo describes a single stack frame. -type FrameInfo struct { - Frame FrameID - Location Location -} - -// GetFrames returns a number of stack frames. -func (c *Connection) GetFrames(thread ThreadID, start, count int) ([]FrameInfo, error) { - req := struct { - Thread ThreadID - Start, Count int - }{thread, start, count} - var res []FrameInfo - err := c.get(cmdThreadReferenceFrames, req, &res) - return res, err -} diff --git a/core/java/jdwp/cmdset_vm.go b/core/java/jdwp/cmdset_vm.go deleted file mode 100644 index 3fc41019ee..0000000000 --- a/core/java/jdwp/cmdset_vm.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// Version describes the JDWP version -type Version struct { - Description string // Text information on the VM version - JDWPMajor int // Major JDWP Version number - JDWPMinor int // Minor JDWP Version number - Version string // Target VM JRE version, as in the java.version property - Name string // Target VM name, as in the java.vm.name property -} - -// GetVersion returns the JDWP version from the server. -func (c *Connection) GetVersion() (Version, error) { - res := Version{} - err := c.get(cmdVirtualMachineVersion, struct{}{}, &res) - return res, err -} - -// ClassInfo describes a loaded classes matching the requested signature. -type ClassInfo struct { - Kind TypeTag // Kind of reference type - TypeID ReferenceTypeID // Matching loaded reference type - Signature string // The class signature - Status ClassStatus // The class status -} - -// ClassID returns the class identifier for the ClassBySignature. -func (c ClassInfo) ClassID() ClassID { - return ClassID(c.TypeID) -} - -// GetClassesBySignature returns all the loaded classes matching the requested -// signature from the server. -func (c *Connection) GetClassesBySignature(signature string) ([]ClassInfo, error) { - res := []struct { - Kind TypeTag - TypeID ReferenceTypeID - Status ClassStatus - }{} - err := c.get(cmdVirtualMachineClassesBySignature, &signature, &res) - out := make([]ClassInfo, len(res)) - for i, c := range res { - out[i] = ClassInfo{c.Kind, c.TypeID, signature, c.Status} - } - return out, err -} - -// GetAllClasses returns all the active threads by ID. -func (c *Connection) GetAllClasses() ([]ClassInfo, error) { - res := []ClassInfo{} - err := c.get(cmdVirtualMachineAllClasses, struct{}{}, &res) - return res, err -} - -// GetAllThreads returns all the active threads by ID. -func (c *Connection) GetAllThreads() ([]ThreadID, error) { - res := []ThreadID{} - err := c.get(cmdVirtualMachineAllThreads, struct{}{}, &res) - return res, err -} - -// IDSizes describes the sizes of all the variably sized data types. -type IDSizes struct { - FieldIDSize int32 // FieldID size in bytes - MethodIDSize int32 // MethodID size in bytes - ObjectIDSize int32 // ObjectID size in bytes - ReferenceTypeIDSize int32 // ReferenceTypeID size in bytes - FrameIDSize int32 // FrameID size in bytes -} - -// GetIDSizes returns the sizes of all the variably sized data types. -func (c *Connection) GetIDSizes() (IDSizes, error) { - res := IDSizes{} - err := c.get(cmdVirtualMachineIDSizes, struct{}{}, &res) - return res, err -} - -// SuspendAll suspends all threads. -func (c *Connection) SuspendAll() error { - return c.get(cmdVirtualMachineSuspend, struct{}{}, nil) -} - -// ResumeAll resumes all threads. -func (c *Connection) ResumeAll() error { - return c.get(cmdVirtualMachineResume, struct{}{}, nil) -} - -// ResumeAllExcept resumes all threads except for the specified thread. -func (c *Connection) ResumeAllExcept(thread ThreadID) error { - if err := c.Suspend(thread); err != nil { - return err - } - return c.ResumeAll() -} - -// CreateString returns the StringID for the given string. -func (c *Connection) CreateString(str string) (StringID, error) { - res := StringID(0) - err := c.get(cmdVirtualMachineCreateString, str, &res) - return res, err -} diff --git a/core/java/jdwp/cmdsets.go b/core/java/jdwp/cmdsets.go deleted file mode 100644 index 0aaac17aa7..0000000000 --- a/core/java/jdwp/cmdsets.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// cmdSet is the namespace for a command identifier. -type cmdSet uint8 - -// cmdID is a command in a command set. -type cmdID uint8 - -type cmd struct { - set cmdSet - id cmdID -} - -func (c cmd) String() string { - return fmt.Sprintf("%v.%v", c.set, cmdNames[c]) -} - -const ( - cmdSetVirtualMachine = cmdSet(1) - cmdSetReferenceType = cmdSet(2) - cmdSetClassType = cmdSet(3) - cmdSetArrayType = cmdSet(4) - cmdSetInterfaceType = cmdSet(5) - cmdSetMethod = cmdSet(6) - cmdSetField = cmdSet(8) - cmdSetObjectReference = cmdSet(9) - cmdSetStringReference = cmdSet(10) - cmdSetThreadReference = cmdSet(11) - cmdSetThreadGroupReference = cmdSet(12) - cmdSetArrayReference = cmdSet(13) - cmdSetClassLoaderReference = cmdSet(14) - cmdSetEventRequest = cmdSet(15) - cmdSetStackFrame = cmdSet(16) - cmdSetClassObjectReference = cmdSet(17) - cmdSetEvent = cmdSet(64) -) - -func (c cmdSet) String() string { - switch c { - case cmdSetVirtualMachine: - return "VirtualMachine" - case cmdSetReferenceType: - return "ReferenceType" - case cmdSetClassType: - return "ClassType" - case cmdSetArrayType: - return "ArrayType" - case cmdSetInterfaceType: - return "InterfaceType" - case cmdSetMethod: - return "Method" - case cmdSetField: - return "Field" - case cmdSetObjectReference: - return "ObjectReference" - case cmdSetStringReference: - return "StringReference" - case cmdSetThreadReference: - return "ThreadReference" - case cmdSetThreadGroupReference: - return "ThreadGroupReference" - case cmdSetArrayReference: - return "ArrayReference" - case cmdSetClassLoaderReference: - return "ClassLoaderReference" - case cmdSetEventRequest: - return "EventRequest" - case cmdSetStackFrame: - return "StackFrame" - case cmdSetClassObjectReference: - return "ClassObjectReference" - case cmdSetEvent: - return "Event" - } - return fmt.Sprint(int(c)) -} - -var ( - cmdVirtualMachineVersion = cmd{cmdSetVirtualMachine, 1} - cmdVirtualMachineClassesBySignature = cmd{cmdSetVirtualMachine, 2} - cmdVirtualMachineAllClasses = cmd{cmdSetVirtualMachine, 3} - cmdVirtualMachineAllThreads = cmd{cmdSetVirtualMachine, 4} - cmdVirtualMachineTopLevelThreadGroups = cmd{cmdSetVirtualMachine, 5} - cmdVirtualMachineDispose = cmd{cmdSetVirtualMachine, 6} - cmdVirtualMachineIDSizes = cmd{cmdSetVirtualMachine, 7} - cmdVirtualMachineSuspend = cmd{cmdSetVirtualMachine, 8} - cmdVirtualMachineResume = cmd{cmdSetVirtualMachine, 9} - cmdVirtualMachineExit = cmd{cmdSetVirtualMachine, 10} - cmdVirtualMachineCreateString = cmd{cmdSetVirtualMachine, 11} - cmdVirtualMachineCapabilities = cmd{cmdSetVirtualMachine, 12} - cmdVirtualMachineClassPaths = cmd{cmdSetVirtualMachine, 13} - cmdVirtualMachineDisposeObjects = cmd{cmdSetVirtualMachine, 14} - cmdVirtualMachineHoldEvents = cmd{cmdSetVirtualMachine, 15} - cmdVirtualMachineReleaseEvents = cmd{cmdSetVirtualMachine, 16} - cmdVirtualMachineCapabilitiesNew = cmd{cmdSetVirtualMachine, 17} - cmdVirtualMachineRedefineClasses = cmd{cmdSetVirtualMachine, 18} - cmdVirtualMachineSetDefaultStratum = cmd{cmdSetVirtualMachine, 19} - cmdVirtualMachineAllClassesWithGeneric = cmd{cmdSetVirtualMachine, 20} - - cmdReferenceTypeSignature = cmd{cmdSetReferenceType, 1} - cmdReferenceTypeClassLoader = cmd{cmdSetReferenceType, 2} - cmdReferenceTypeModifiers = cmd{cmdSetReferenceType, 3} - cmdReferenceTypeFields = cmd{cmdSetReferenceType, 4} - cmdReferenceTypeMethods = cmd{cmdSetReferenceType, 5} - cmdReferenceTypeGetValues = cmd{cmdSetReferenceType, 6} - cmdReferenceTypeSourceFile = cmd{cmdSetReferenceType, 7} - cmdReferenceTypeNestedTypes = cmd{cmdSetReferenceType, 8} - cmdReferenceTypeStatus = cmd{cmdSetReferenceType, 9} - cmdReferenceTypeInterfaces = cmd{cmdSetReferenceType, 10} - cmdReferenceTypeClassObject = cmd{cmdSetReferenceType, 11} - cmdReferenceTypeSourceDebugExtension = cmd{cmdSetReferenceType, 12} - cmdReferenceTypeSignatureWithGeneric = cmd{cmdSetReferenceType, 13} - cmdReferenceTypeFieldsWithGeneric = cmd{cmdSetReferenceType, 14} - cmdReferenceTypeMethodsWithGeneric = cmd{cmdSetReferenceType, 15} - - cmdClassTypeSuperclass = cmd{cmdSetClassType, 1} - cmdClassTypeSetValues = cmd{cmdSetClassType, 2} - cmdClassTypeInvokeMethod = cmd{cmdSetClassType, 3} - cmdClassTypeNewInstance = cmd{cmdSetClassType, 4} - - cmdArrayTypeNewInstance = cmd{cmdSetArrayType, 1} - - cmdMethodTypeLineTable = cmd{cmdSetMethod, 1} - cmdMethodTypeVariableTable = cmd{cmdSetMethod, 2} - cmdMethodTypeBytecodes = cmd{cmdSetMethod, 3} - cmdMethodTypeIsObsolete = cmd{cmdSetMethod, 4} - cmdMethodTypeVariableTableWithGeneric = cmd{cmdSetMethod, 5} - - cmdObjectReferenceReferenceType = cmd{cmdSetObjectReference, 1} - cmdObjectReferenceGetValues = cmd{cmdSetObjectReference, 2} - cmdObjectReferenceSetValues = cmd{cmdSetObjectReference, 3} - cmdObjectReferenceMonitorInfo = cmd{cmdSetObjectReference, 5} - cmdObjectReferenceInvokeMethod = cmd{cmdSetObjectReference, 6} - cmdObjectReferenceDisableCollection = cmd{cmdSetObjectReference, 7} - cmdObjectReferenceEnableCollection = cmd{cmdSetObjectReference, 8} - cmdObjectReferenceIsCollected = cmd{cmdSetObjectReference, 9} - - cmdStringReferenceValue = cmd{cmdSetStringReference, 1} - - cmdThreadReferenceName = cmd{cmdSetThreadReference, 1} - cmdThreadReferenceSuspend = cmd{cmdSetThreadReference, 2} - cmdThreadReferenceResume = cmd{cmdSetThreadReference, 3} - cmdThreadReferenceStatus = cmd{cmdSetThreadReference, 4} - cmdThreadReferenceThreadGroup = cmd{cmdSetThreadReference, 5} - cmdThreadReferenceFrames = cmd{cmdSetThreadReference, 6} - cmdThreadReferenceFrameCount = cmd{cmdSetThreadReference, 7} - cmdThreadReferenceOwnedMonitors = cmd{cmdSetThreadReference, 8} - cmdThreadReferenceCurrentContendedMonitor = cmd{cmdSetThreadReference, 9} - cmdThreadReferenceStop = cmd{cmdSetThreadReference, 10} - cmdThreadReferenceInterrupt = cmd{cmdSetThreadReference, 11} - cmdThreadReferenceSuspendCount = cmd{cmdSetThreadReference, 12} - - cmdThreadGroupReferenceName = cmd{cmdSetThreadGroupReference, 1} - cmdThreadGroupReferenceParent = cmd{cmdSetThreadGroupReference, 2} - cmdThreadGroupReferenceChildren = cmd{cmdSetThreadGroupReference, 3} - - cmdArrayReferenceLength = cmd{cmdSetArrayReference, 1} - cmdArrayReferenceGetValues = cmd{cmdSetArrayReference, 2} - cmdArrayReferenceSetValues = cmd{cmdSetArrayReference, 3} - - cmdClassLoaderReferenceVisibleClasses = cmd{cmdSetClassLoaderReference, 1} - - cmdEventRequestSet = cmd{cmdSetEventRequest, 1} - cmdEventRequestClear = cmd{cmdSetEventRequest, 2} - cmdEventRequestClearAllBreakpoints = cmd{cmdSetEventRequest, 3} - - cmdStackFrameGetValues = cmd{cmdSetStackFrame, 1} - cmdStackFrameSetValues = cmd{cmdSetStackFrame, 2} - cmdStackFrameThisObject = cmd{cmdSetStackFrame, 3} - cmdStackFramePopFrames = cmd{cmdSetStackFrame, 4} - - cmdClassObjectReferenceReflectedType = cmd{cmdSetClassObjectReference, 1} - - cmdEventComposite = cmd{cmdSetEvent, 1} -) - -var cmdNames = map[cmd]string{} - -func init() { - register := func(c cmd, n string) { - if _, e := cmdNames[c]; e { - panic("command already registered") - } - cmdNames[c] = n - } - register(cmdVirtualMachineVersion, "Version") - register(cmdVirtualMachineClassesBySignature, "ClassesBySignature") - register(cmdVirtualMachineAllClasses, "AllClasses") - register(cmdVirtualMachineAllThreads, "AllThreads") - register(cmdVirtualMachineTopLevelThreadGroups, "TopLevelThreadGroups") - register(cmdVirtualMachineDispose, "Dispose") - register(cmdVirtualMachineIDSizes, "IDSizes") - register(cmdVirtualMachineSuspend, "Suspend") - register(cmdVirtualMachineResume, "Resume") - register(cmdVirtualMachineExit, "Exit") - register(cmdVirtualMachineCreateString, "CreateString") - register(cmdVirtualMachineCapabilities, "Capabilities") - register(cmdVirtualMachineClassPaths, "ClassPaths") - register(cmdVirtualMachineDisposeObjects, "DisposeObjects") - register(cmdVirtualMachineHoldEvents, "HoldEvents") - register(cmdVirtualMachineReleaseEvents, "ReleaseEvents") - register(cmdVirtualMachineCapabilitiesNew, "CapabilitiesNew") - register(cmdVirtualMachineRedefineClasses, "RedefineClasses") - register(cmdVirtualMachineSetDefaultStratum, "SetDefaultStratum") - register(cmdVirtualMachineAllClassesWithGeneric, "AllClassesWithGeneric") - - register(cmdReferenceTypeSignature, "Signature") - register(cmdReferenceTypeClassLoader, "ClassLoader") - register(cmdReferenceTypeModifiers, "Modifiers") - register(cmdReferenceTypeFields, "Fields") - register(cmdReferenceTypeMethods, "Methods") - register(cmdReferenceTypeGetValues, "GetValues") - register(cmdReferenceTypeSourceFile, "SourceFile") - register(cmdReferenceTypeNestedTypes, "NestedTypes") - register(cmdReferenceTypeStatus, "Status") - register(cmdReferenceTypeInterfaces, "Interfaces") - register(cmdReferenceTypeClassObject, "ClassObject") - register(cmdReferenceTypeSourceDebugExtension, "SourceDebugExtension") - register(cmdReferenceTypeSignatureWithGeneric, "SignatureWithGeneric") - register(cmdReferenceTypeFieldsWithGeneric, "FieldsWithGeneric") - register(cmdReferenceTypeMethodsWithGeneric, "MethodsWithGeneric") - - register(cmdClassTypeSuperclass, "Superclass") - register(cmdClassTypeSetValues, "SetValues") - register(cmdClassTypeInvokeMethod, "InvokeMethod") - register(cmdClassTypeNewInstance, "NewInstance") - - register(cmdArrayTypeNewInstance, "NewInstance") - - register(cmdMethodTypeLineTable, "LineTable") - register(cmdMethodTypeVariableTable, "VariableTable") - register(cmdMethodTypeBytecodes, "Bytecodes") - register(cmdMethodTypeIsObsolete, "IsObsolete") - register(cmdMethodTypeVariableTableWithGeneric, "VariableTableWithGeneric") - - register(cmdObjectReferenceReferenceType, "ReferenceType") - register(cmdObjectReferenceGetValues, "GetValues") - register(cmdObjectReferenceSetValues, "SetValues") - register(cmdObjectReferenceMonitorInfo, "MonitorInfo") - register(cmdObjectReferenceInvokeMethod, "InvokeMethod") - register(cmdObjectReferenceDisableCollection, "DisableCollection") - register(cmdObjectReferenceEnableCollection, "EnableCollection") - register(cmdObjectReferenceIsCollected, "IsCollected") - - register(cmdStringReferenceValue, "Value") - - register(cmdThreadReferenceName, "Name") - register(cmdThreadReferenceSuspend, "Suspend") - register(cmdThreadReferenceResume, "Resume") - register(cmdThreadReferenceStatus, "Status") - register(cmdThreadReferenceThreadGroup, "ThreadGroup") - register(cmdThreadReferenceFrames, "Frames") - register(cmdThreadReferenceFrameCount, "FrameCount") - register(cmdThreadReferenceOwnedMonitors, "OwnedMonitors") - register(cmdThreadReferenceCurrentContendedMonitor, "CurrentContendedMonitor") - register(cmdThreadReferenceStop, "Stop") - register(cmdThreadReferenceInterrupt, "Interrupt") - register(cmdThreadReferenceSuspendCount, "SuspendCount") - - register(cmdThreadGroupReferenceName, "Name") - register(cmdThreadGroupReferenceParent, "Parent") - register(cmdThreadGroupReferenceChildren, "Children") - - register(cmdArrayReferenceLength, "Length") - register(cmdArrayReferenceGetValues, "GetValues") - register(cmdArrayReferenceSetValues, "SetValues") - - register(cmdClassLoaderReferenceVisibleClasses, "VisibleClasses") - - register(cmdEventRequestSet, "Set") - register(cmdEventRequestClear, "Clear") - register(cmdEventRequestClearAllBreakpoints, "ClearAllBreakpoints") - - register(cmdStackFrameGetValues, "GetValues") - register(cmdStackFrameSetValues, "SetValues") - register(cmdStackFrameThisObject, "ThisObject") - register(cmdStackFramePopFrames, "PopFrames") - - register(cmdClassObjectReferenceReflectedType, "ReflectedType") - - register(cmdEventComposite, "Composite") -} diff --git a/core/java/jdwp/coder.go b/core/java/jdwp/coder.go deleted file mode 100644 index ff570c0282..0000000000 --- a/core/java/jdwp/coder.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "fmt" - "reflect" - - "github.com/google/gapid/core/data/binary" -) - -// debug adds panic handlers to encode() and decode() so that incorrectly -// handled types can be more easily identified. -const debug = false - -func unbox(v reflect.Value) reflect.Value { - if v.Kind() == reflect.Interface { - return v.Elem() - } - return v -} - -// encode writes the value v to w, using the JDWP encoding scheme. -func (c *Connection) encode(w binary.Writer, v reflect.Value) error { - if debug { - defer func() { - if r := recover(); r != nil { - panic(fmt.Errorf("Type %T %v %v", v.Interface(), v.Type().Name(), v.Kind())) - } - }() - } - - t := v.Type() - o := v.Interface() - - switch v.Type() { - case reflect.TypeOf((*EventModifier)(nil)).Elem(): - // EventModifier's are prefixed with their 1-byte modKind. - w.Uint8(o.(EventModifier).modKind()) - - case reflect.TypeOf((*Value)(nil)).Elem(): - // values are prefixed with their 1-tag type. - switch o.(type) { - case ArrayID: - w.Uint8(uint8(TagArray)) - case byte: - w.Uint8(uint8(TagByte)) - case Char: - w.Uint8(uint8(TagChar)) - case ObjectID: - w.Uint8(uint8(TagObject)) - case float32: - w.Uint8(uint8(TagFloat)) - case float64: - w.Uint8(uint8(TagDouble)) - case int, int32: - w.Uint8(uint8(TagInt)) - case int16: - w.Uint8(uint8(TagShort)) - case int64: - w.Uint8(uint8(TagLong)) - case nil: - w.Uint8(uint8(TagVoid)) - case bool: - w.Uint8(uint8(TagBoolean)) - case StringID: - w.Uint8(uint8(TagString)) - case ThreadID: - w.Uint8(uint8(TagThread)) - case ThreadGroupID: - w.Uint8(uint8(TagThreadGroup)) - case ClassLoaderID: - w.Uint8(uint8(TagClassLoader)) - case ClassObjectID: - w.Uint8(uint8(TagClassObject)) - default: - panic(fmt.Errorf("Got Value of type %T", o)) - } - } - - switch o := o.(type) { - case ReferenceTypeID, ClassID, InterfaceID, ArrayTypeID: - binary.WriteUint(w, c.idSizes.ReferenceTypeIDSize*8, unbox(v).Uint()) - - case MethodID: - binary.WriteUint(w, c.idSizes.MethodIDSize*8, unbox(v).Uint()) - - case FieldID: - binary.WriteUint(w, c.idSizes.FieldIDSize*8, unbox(v).Uint()) - - case ObjectID, ThreadID, ThreadGroupID, StringID, ClassLoaderID, ClassObjectID, ArrayID: - binary.WriteUint(w, c.idSizes.ObjectIDSize*8, unbox(v).Uint()) - - case []byte: // Optimisation - w.Uint32(uint32(len(o))) - w.Data(o) - - default: - switch t.Kind() { - case reflect.Ptr, reflect.Interface: - return c.encode(w, v.Elem()) - case reflect.String: - w.Uint32(uint32(v.Len())) - w.Data([]byte(v.String())) - case reflect.Uint8: - w.Uint8(uint8(v.Uint())) - case reflect.Uint64: - w.Uint64(uint64(v.Uint())) - case reflect.Int8: - w.Int8(int8(v.Int())) - case reflect.Int16: - w.Int16(int16(v.Int())) - case reflect.Int32, reflect.Int: - w.Int32(int32(v.Int())) - case reflect.Int64: - w.Int64(v.Int()) - case reflect.Float32: - w.Float32(float32(v.Float())) - case reflect.Float64: - w.Float64(v.Float()) - case reflect.Bool: - w.Bool(v.Bool()) - case reflect.Struct: - for i, count := 0, v.NumField(); i < count; i++ { - c.encode(w, v.Field(i)) - } - case reflect.Slice: - count := v.Len() - w.Uint32(uint32(count)) - for i := 0; i < count; i++ { - c.encode(w, v.Index(i)) - } - default: - panic(fmt.Errorf("Unhandled type %T %v %v", o, t.Name(), t.Kind())) - } - } - return w.Error() -} - -// decode reads the value v from r, using the JDWP encoding scheme. -func (c *Connection) decode(r binary.Reader, v reflect.Value) error { - if debug { - defer func() { - if r := recover(); r != nil { - panic(fmt.Errorf("Type %T %v %v", v.Interface(), v.Type().Name(), v.Kind())) - } - }() - } - - switch v.Type() { - case reflect.TypeOf((*Event)(nil)).Elem(): - var kind EventKind - if err := c.decode(r, reflect.ValueOf(&kind)); err != nil { - return err - } - event := kind.event() - v.Set(reflect.ValueOf(event)) - v = v.Elem() - // Continue to decode event body below. - - case reflect.TypeOf((*Value)(nil)).Elem(): - tag := Tag(r.Uint8()) - var ty reflect.Type - switch tag { - case TagArray: - ty = reflect.TypeOf(ArrayID(0)) - case TagByte: - ty = reflect.TypeOf(byte(0)) - case TagChar: - ty = reflect.TypeOf(Char(0)) - case TagObject: - ty = reflect.TypeOf(ObjectID(0)) - case TagFloat: - ty = reflect.TypeOf(float32(0)) - case TagDouble: - ty = reflect.TypeOf(float64(0)) - case TagInt: - ty = reflect.TypeOf(int(0)) - case TagShort: - ty = reflect.TypeOf(int16(0)) - case TagLong: - ty = reflect.TypeOf(int64(0)) - case TagBoolean: - ty = reflect.TypeOf(false) - case TagString: - ty = reflect.TypeOf(StringID(0)) - case TagThread: - ty = reflect.TypeOf(ThreadID(0)) - case TagThreadGroup: - ty = reflect.TypeOf(ThreadGroupID(0)) - case TagClassLoader: - ty = reflect.TypeOf(ClassLoaderID(0)) - case TagClassObject: - ty = reflect.TypeOf(ClassObjectID(0)) - case TagVoid: - v.Set(reflect.New(v.Type()).Elem()) - return r.Error() - default: - panic(fmt.Errorf("Unhandled value type %v", tag)) - } - data := reflect.New(ty).Elem() - c.decode(r, data) - v.Set(data) - return r.Error() - } - - t := v.Type() - o := v.Interface() - switch o := o.(type) { - case ReferenceTypeID, ClassID, InterfaceID, ArrayTypeID: - v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.ReferenceTypeIDSize*8)).Convert(t)) - - case MethodID: - v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.MethodIDSize*8)).Convert(t)) - - case FieldID: - v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.FieldIDSize*8)).Convert(t)) - - case ObjectID, ThreadID, ThreadGroupID, StringID, ClassLoaderID, ClassObjectID, ArrayID: - v.Set(reflect.ValueOf(binary.ReadUint(r, c.idSizes.ObjectIDSize*8)).Convert(t)) - - case EventModifier: - panic("Cannot decode EventModifiers") - - default: - switch t.Kind() { - case reflect.Ptr, reflect.Interface: - return c.decode(r, v.Elem()) - case reflect.String: - data := make([]byte, r.Uint32()) - r.Data(data) - v.Set(reflect.ValueOf(string(data)).Convert(t)) - case reflect.Bool: - v.Set(reflect.ValueOf(r.Bool()).Convert(t)) - case reflect.Uint8: - v.Set(reflect.ValueOf(r.Uint8()).Convert(t)) - case reflect.Uint64: - v.Set(reflect.ValueOf(r.Uint64()).Convert(t)) - case reflect.Int8: - v.Set(reflect.ValueOf(r.Int8()).Convert(t)) - case reflect.Int16: - v.Set(reflect.ValueOf(r.Int16()).Convert(t)) - case reflect.Int32, reflect.Int: - v.Set(reflect.ValueOf(r.Int32()).Convert(t)) - case reflect.Int64: - v.Set(reflect.ValueOf(r.Int64()).Convert(t)) - case reflect.Struct: - for i, count := 0, v.NumField(); i < count; i++ { - c.decode(r, v.Field(i)) - } - case reflect.Slice: - count := int(r.Uint32()) - slice := reflect.MakeSlice(t, count, count) - for i := 0; i < count; i++ { - c.decode(r, slice.Index(i)) - } - v.Set(slice) - default: - panic(fmt.Errorf("Unhandled type %T %v %v", o, t.Name(), t.Kind())) - } - } - return r.Error() -} diff --git a/core/java/jdwp/debug.go b/core/java/jdwp/debug.go deleted file mode 100644 index 67d3ee502f..0000000000 --- a/core/java/jdwp/debug.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -func dbg(msg string, args ...interface{}) { - const enabled = false - if enabled { - fmt.Println(fmt.Sprintf(msg, args...)) - } -} diff --git a/core/java/jdwp/errors.go b/core/java/jdwp/errors.go deleted file mode 100644 index eee273c6e4..0000000000 --- a/core/java/jdwp/errors.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// Error is an enumerator of error codes returned by JDWP. -type Error uint16 - -const ( - ErrNone = Error(0) - ErrInvalidThread = Error(10) - ErrInvalidThreadGroup = Error(11) - ErrInvalidPriority = Error(12) - ErrThreadNotSuspended = Error(13) - ErrThreadSuspended = Error(14) - ErrInvalidObject = Error(20) - ErrInvalidClass = Error(21) - ErrClassNotPrepared = Error(22) - ErrInvalidMethodID = Error(23) - ErrInvalidLocation = Error(24) - ErrInvalidFieldID = Error(25) - ErrInvalidFrameID = Error(30) - ErrNoMoreFrames = Error(31) - ErrOpaqueFrame = Error(32) - ErrNotCurrentFrame = Error(33) - ErrTypeMismatch = Error(34) - ErrInvalidSlot = Error(35) - ErrDuplicate = Error(40) - ErrNotFound = Error(41) - ErrInvalidMonitor = Error(50) - ErrNotMonitorOwner = Error(51) - ErrInterrupt = Error(52) - ErrInvalidClassFormat = Error(60) - ErrCircularClassDefinition = Error(61) - ErrFailsVerification = Error(62) - ErrAddMethodNotImplemented = Error(63) - ErrSchemaChangeNotImplemented = Error(64) - ErrInvalidTypestate = Error(65) - ErrHierarchyChangeNotImplemented = Error(66) - ErrDeleteMethodNotImplemented = Error(67) - ErrUnsupportedVersion = Error(68) - ErrNamesDontMatch = Error(69) - ErrClassModifiersChangeNotImplemented = Error(70) - ErrMethodModifiersChangeNotImplemented = Error(71) - ErrNotImplemented = Error(99) - ErrNullPointer = Error(100) - ErrAbsentInformation = Error(101) - ErrInvalidEventType = Error(102) - ErrIllegalArgument = Error(103) - ErrOutOfMemory = Error(110) - ErrAccessDenied = Error(111) - ErrVMDead = Error(112) - ErrInternal = Error(113) - ErrUnattachedThread = Error(115) - ErrInvalidTag = Error(500) - ErrAlreadyInvoking = Error(502) - ErrInvalidIndex = Error(503) - ErrInvalidLength = Error(504) - ErrInvalidString = Error(506) - ErrInvalidClassLoader = Error(507) - ErrInvalidArray = Error(508) - ErrTransportLoad = Error(509) - ErrTransportInit = Error(510) - ErrNativeMethod = Error(511) - ErrInvalidCount = Error(512) -) - -func (e Error) Error() string { - switch e { - case ErrNone: - return "No error has occurred." - case ErrInvalidThread: - return "Passed thread is null, is not a valid thread or has exited." - case ErrInvalidThreadGroup: - return "Thread group invalid." - case ErrInvalidPriority: - return "Invalid priority." - case ErrThreadNotSuspended: - return "The specified thread has not been suspended by an event." - case ErrThreadSuspended: - return "Thread already suspended." - case ErrInvalidObject: - return "This reference type has been unloaded and garbage collected." - case ErrInvalidClass: - return "Invalid class." - case ErrClassNotPrepared: - return "Class has been loaded but not yet prepared." - case ErrInvalidMethodID: - return "Invalid method." - case ErrInvalidLocation: - return "Invalid location." - case ErrInvalidFieldID: - return "Invalid field." - case ErrInvalidFrameID: - return "Invalid jframeID." - case ErrNoMoreFrames: - return "There are no more Java or JNI frames on the call stack." - case ErrOpaqueFrame: - return "Information about the frame is not available." - case ErrNotCurrentFrame: - return "Operation can only be performed on current frame." - case ErrTypeMismatch: - return "The variable is not an appropriate type for the function used." - case ErrInvalidSlot: - return "Invalid slot." - case ErrDuplicate: - return "Item already set." - case ErrNotFound: - return "Desired element not found." - case ErrInvalidMonitor: - return "Invalid monitor." - case ErrNotMonitorOwner: - return "This thread doesn't own the monitor." - case ErrInterrupt: - return "The call has been interrupted before completion." - case ErrInvalidClassFormat: - return "The virtual machine attempted to read a class file and determined that the file is malformed or otherwise cannot be interpreted as a class file." - case ErrCircularClassDefinition: - return "A circularity has been detected while initializing a class." - case ErrFailsVerification: - return "The verifier detected that a class file, though well formed, contained some sort of internal inconsistency or security problem." - case ErrAddMethodNotImplemented: - return "Adding methods has not been implemented." - case ErrSchemaChangeNotImplemented: - return "Schema change has not been implemented." - case ErrInvalidTypestate: - return "The state of the thread has been modified, and is now inconsistent." - case ErrHierarchyChangeNotImplemented: - return "A direct superclass is different for the new class version, or the set of directly implemented interfaces is different and canUnrestrictedlyRedefineClasses is false." - case ErrDeleteMethodNotImplemented: - return "The new class version does not declare a method declared in the old class version and canUnrestrictedlyRedefineClasses is false." - case ErrUnsupportedVersion: - return "A class file has a version number not supported by this VM." - case ErrNamesDontMatch: - return "The class name defined in the new class file is different from the name in the old class object." - case ErrClassModifiersChangeNotImplemented: - return "The new class version has different modifiers and and canUnrestrictedlyRedefineClasses is false." - case ErrMethodModifiersChangeNotImplemented: - return "A method in the new class version has different modifiers than its counterpart in the old class version and and canUnrestrictedlyRedefineClasses is false." - case ErrNotImplemented: - return "The functionality is not implemented in this virtual machine." - case ErrNullPointer: - return "Invalid pointer." - case ErrAbsentInformation: - return "Desired information is not available." - case ErrInvalidEventType: - return "The specified event type id is not recognized." - case ErrIllegalArgument: - return "Illegal argument." - case ErrOutOfMemory: - return "The function needed to allocate memory and no more memory was available for allocation." - case ErrAccessDenied: - return "Debugging has not been enabled in this virtual machine. JVMDI cannot be used." - case ErrVMDead: - return "The virtual machine is not running." - case ErrInternal: - return "An unexpected internal error has occurred." - case ErrUnattachedThread: - return "The thread being used to call this function is not attached to the virtual machine. Calls must be made from attached threads." - case ErrInvalidTag: - return "object type id or class tag." - case ErrAlreadyInvoking: - return "Previous invoke not complete." - case ErrInvalidIndex: - return "Index is invalid." - case ErrInvalidLength: - return "The length is invalid." - case ErrInvalidString: - return "The string is invalid." - case ErrInvalidClassLoader: - return "The class loader is invalid." - case ErrInvalidArray: - return "The array is invalid." - case ErrTransportLoad: - return "Unable to load the transport." - case ErrTransportInit: - return "Unable to initialize the transport." - case ErrNativeMethod: - return "Error native method." - case ErrInvalidCount: - return "The count is invalid." - } - return fmt.Sprintf("Error<%v>", int(e)) -} diff --git a/core/java/jdwp/event.go b/core/java/jdwp/event.go deleted file mode 100644 index 92d64e6042..0000000000 --- a/core/java/jdwp/event.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// events is a collection of events. -type events struct { - Policy SuspendPolicy - Events []Event -} - -// Event is the interface implemented by all events raised by the VM. -type Event interface { - request() EventRequestID - Kind() EventKind -} - -// EventVMStart represents an event raised when the virtual machine is started. -type EventVMStart struct { - Request EventRequestID - Thread ThreadID -} - -// EventVMDeath represents an event raised when the virtual machine is stopped. -type EventVMDeath struct { - Request EventRequestID -} - -// EventSingleStep represents an event raised when a single-step has been completed. -type EventSingleStep struct { - Request EventRequestID - Thread ThreadID - Location Location -} - -// EventBreakpoint represents an event raised when a breakpoint has been hit. -type EventBreakpoint struct { - Request EventRequestID - Thread ThreadID - Location Location -} - -// EventMethodEntry represents an event raised when a method has been entered. -type EventMethodEntry struct { - Request EventRequestID - Thread ThreadID - Location Location -} - -// EventMethodExit represents an event raised when a method has been exited. -type EventMethodExit struct { - Request EventRequestID - Thread ThreadID - Location Location -} - -// EventException represents an event raised when an exception is thrown. -type EventException struct { - Request EventRequestID - Thread ThreadID - Location Location - Exception TaggedObjectID - CatchLocation Location -} - -// EventThreadStart represents an event raised when a new thread is started. -type EventThreadStart struct { - Request EventRequestID - Thread ThreadID -} - -// EventThreadDeath represents an event raised when a thread is stopped. -type EventThreadDeath struct { - Request EventRequestID - Thread ThreadID -} - -// EventClassPrepare represents an event raised when a class enters the prepared state. -type EventClassPrepare struct { - Request EventRequestID - Thread ThreadID - ClassKind TypeTag - ClassType ReferenceTypeID - Signature string - Status ClassStatus -} - -// EventClassUnload represents an event raised when a class is unloaded. -type EventClassUnload struct { - Request EventRequestID - Signature string -} - -// EventFieldAccess represents an event raised when a field is accessed. -type EventFieldAccess struct { - Request EventRequestID - Thread ThreadID - Location Location - FieldKind TypeTag - FieldType ReferenceTypeID - Field FieldID - Object TaggedObjectID -} - -// EventFieldModification represents an event raised when a field is modified. -type EventFieldModification struct { - Request EventRequestID - Thread ThreadID - Location Location - FieldKind TypeTag - FieldType ReferenceTypeID - Field FieldID - Object TaggedObjectID - NewValue Value -} - -func (e EventVMStart) request() EventRequestID { return e.Request } -func (e EventVMDeath) request() EventRequestID { return e.Request } -func (e EventSingleStep) request() EventRequestID { return e.Request } -func (e EventBreakpoint) request() EventRequestID { return e.Request } -func (e EventMethodEntry) request() EventRequestID { return e.Request } -func (e EventMethodExit) request() EventRequestID { return e.Request } -func (e EventException) request() EventRequestID { return e.Request } -func (e EventThreadStart) request() EventRequestID { return e.Request } -func (e EventThreadDeath) request() EventRequestID { return e.Request } -func (e EventClassPrepare) request() EventRequestID { return e.Request } -func (e EventClassUnload) request() EventRequestID { return e.Request } -func (e EventFieldAccess) request() EventRequestID { return e.Request } -func (e EventFieldModification) request() EventRequestID { return e.Request } - -// Kind returns VMStart -func (EventVMStart) Kind() EventKind { return VMStart } - -// Kind returns VMDeath -func (EventVMDeath) Kind() EventKind { return VMDeath } - -// Kind returns SingleStep -func (EventSingleStep) Kind() EventKind { return SingleStep } - -// Kind returns Breakpoint -func (EventBreakpoint) Kind() EventKind { return Breakpoint } - -// Kind returns MethodEntry -func (EventMethodEntry) Kind() EventKind { return MethodEntry } - -// Kind returns MethodExit -func (EventMethodExit) Kind() EventKind { return MethodExit } - -// Kind returns Exception -func (EventException) Kind() EventKind { return Exception } - -// Kind returns ThreadStart -func (EventThreadStart) Kind() EventKind { return ThreadStart } - -// Kind returns ThreadDeath -func (EventThreadDeath) Kind() EventKind { return ThreadDeath } - -// Kind returns ClassPrepare -func (EventClassPrepare) Kind() EventKind { return ClassPrepare } - -// Kind returns ClassUnload -func (EventClassUnload) Kind() EventKind { return ClassUnload } - -// Kind returns FieldAccess -func (EventFieldAccess) Kind() EventKind { return FieldAccess } - -// Kind returns FieldModification -func (EventFieldModification) Kind() EventKind { return FieldModification } diff --git a/core/java/jdwp/event_kind.go b/core/java/jdwp/event_kind.go deleted file mode 100644 index c116325cb5..0000000000 --- a/core/java/jdwp/event_kind.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// EventKind represents the type of event to set, or being raised. -type EventKind uint8 - -const ( - // SingleStep is the kind of event raised when a single-step has been completed. - SingleStep = EventKind(1) - // Breakpoint is the kind of event raised when a breakpoint has been hit. - Breakpoint = EventKind(2) - // FramePop is the kind of event raised when a stack-frame is popped. - FramePop = EventKind(3) - // Exception is the kind of event raised when an exception is thrown. - Exception = EventKind(4) - // UserDefined is the kind of event raised when a user-defind event is fired. - UserDefined = EventKind(5) - // ThreadStart is the kind of event raised when a new thread is started. - ThreadStart = EventKind(6) - // ThreadDeath is the kind of event raised when a thread is stopped. - ThreadDeath = EventKind(7) - // ClassPrepare is the kind of event raised when a class enters the prepared state. - ClassPrepare = EventKind(8) - // ClassUnload is the kind of event raised when a class is unloaded. - ClassUnload = EventKind(9) - // ClassLoad is the kind of event raised when a class enters the loaded state. - ClassLoad = EventKind(10) - // FieldAccess is the kind of event raised when a field is accessed. - FieldAccess = EventKind(20) - // FieldModification is the kind of event raised when a field is modified. - FieldModification = EventKind(21) - // ExceptionCatch is the kind of event raised when an exception is caught. - ExceptionCatch = EventKind(30) - // MethodEntry is the kind of event raised when a method has been entered. - MethodEntry = EventKind(40) - // MethodExit is the kind of event raised when a method has been exited. - MethodExit = EventKind(41) - // VMStart is the kind of event raised when the virtual machine is initialized. - VMStart = EventKind(90) - // VMDeath is the kind of event raised when the virtual machine is shutdown. - VMDeath = EventKind(99) -) - -func (k EventKind) String() string { - switch k { - case SingleStep: - return "SingleStep" - case Breakpoint: - return "Breakpoint" - case FramePop: - return "FramePop" - case Exception: - return "Exception" - case UserDefined: - return "UserDefined" - case ThreadStart: - return "ThreadStart" - case ThreadDeath: - return "ThreadDeath" - case ClassPrepare: - return "ClassPrepare" - case ClassUnload: - return "ClassUnload" - case ClassLoad: - return "ClassLoad" - case FieldAccess: - return "FieldAccess" - case FieldModification: - return "FieldModification" - case ExceptionCatch: - return "ExceptionCatch" - case MethodEntry: - return "MethodEntry" - case MethodExit: - return "MethodExit" - case VMStart: - return "VMStart" - case VMDeath: - return "VMDeath" - default: - return fmt.Sprintf("EventKind<%d>", int(k)) - } -} - -// event returns a default-initialzed Event of the specified kind. -func (k EventKind) event() Event { - switch k { - case SingleStep: - return &EventSingleStep{} - case Breakpoint: - return &EventBreakpoint{} - case Exception: - return &EventException{} - case ThreadStart: - return &EventThreadStart{} - case ThreadDeath: - return &EventThreadDeath{} - case ClassPrepare: - return &EventClassPrepare{} - case ClassUnload: - return &EventClassUnload{} - case FieldAccess: - return &EventFieldAccess{} - case FieldModification: - return &EventFieldModification{} - case ExceptionCatch: - return &EventException{} - case MethodEntry: - return &EventMethodEntry{} - case MethodExit: - return &EventMethodExit{} - case VMStart: - return &EventVMStart{} - case VMDeath: - return &EventVMDeath{} - default: - return nil - } -} diff --git a/core/java/jdwp/field.go b/core/java/jdwp/field.go deleted file mode 100644 index ebac0440fb..0000000000 --- a/core/java/jdwp/field.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "fmt" - "strings" -) - -// Field describes a single field -type Field struct { - ID FieldID - Name string - Signature string - ModBits ModBits -} - -// Fields is a collection of fields -type Fields []Field - -func (l Fields) String() string { - parts := make([]string, len(l)) - for i, m := range l { - parts[i] = fmt.Sprintf("%+v", m) - } - return strings.Join(parts, "\n") -} - -// FindByName returns the field with the matching name, or nil if no field with -// a matching name is found in l. -func (l Fields) FindByName(name string) *Field { - for _, f := range l { - if f.Name == name { - return &f - } - } - return nil -} - -// FindBySignature returns the field with the matching signature in l, or nil -// if no field with a matching signature is found in l. -func (l Fields) FindBySignature(name, sig string) *Field { - for _, f := range l { - if f.Name == name && f.Signature == sig { - return &f - } - } - return nil -} - -// FindByID returns the field with the matching identifier in l, or nil if no -// field with a matching identifier is found in l. -func (l Fields) FindByID(id FieldID) *Field { - for _, f := range l { - if f.ID == id { - return &f - } - } - return nil -} diff --git a/core/java/jdwp/helpers.go b/core/java/jdwp/helpers.go deleted file mode 100644 index 75b86a2bea..0000000000 --- a/core/java/jdwp/helpers.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "context" - "fmt" -) - -// GetClassBySignature returns the single loaded class matching the requested -// signature from the server. If there are no, or more than one class found, -// then an error is returned. -func (c *Connection) GetClassBySignature(signature string) (ClassInfo, error) { - classes, err := c.GetClassesBySignature(signature) - if err != nil { - return ClassInfo{}, err - } - if len(classes) != 1 { - err := fmt.Errorf("%d classes found with the signature '%v'", len(classes), signature) - return ClassInfo{}, err - } - return classes[0], nil -} - -// GetLocationMethodName returns the name of the method from the location. -func (c *Connection) GetLocationMethodName(l Location) (string, error) { - methods, err := c.GetMethods(ReferenceTypeID(l.Class)) - if err != nil { - return "", err - } - method := methods.FindByID(l.Method) - if method == nil { - return "", fmt.Errorf("Method not found with ID %v", l.Method) - } - return method.Name, nil -} - -// GetClassMethod looks up the method with the specified signature on class. -func (c *Connection) GetClassMethod(class ClassID, name, signature string) (Method, error) { - methods, err := c.GetMethods(ReferenceTypeID(class)) - if err != nil { - return Method{}, err - } - method := methods.FindBySignature(name, signature) - if method == nil { - return Method{}, fmt.Errorf("Method '%s%s' not found", name, signature) - } - return *method, nil -} - -// WaitForClassPrepare blocks until a class with a name that matches the pattern -// is prepared, and then returns the thread that prepared the class. -// All threads are suspended when the method returns. -func (c *Connection) WaitForClassPrepare(ctx context.Context, pattern string) (ThreadID, error) { - var out ThreadID - - onEvent := func(event Event) bool { - out = event.(*EventClassPrepare).Thread - return false - } - - err := c.WatchEvents(ctx, ClassPrepare, SuspendAll, onEvent, ClassMatchEventModifier(pattern)) - if err != nil { - return 0, err - } - - return out, nil -} - -// WaitForMethodEntry blocks until the method on class is entered, and then -// returns the method entry event. -// All threads are suspended when the method returns. -func (c *Connection) WaitForMethodEntry(ctx context.Context, class ClassID, method MethodID) (*EventMethodEntry, error) { - var out *EventMethodEntry - - onEvent := func(event Event) bool { - e := event.(*EventMethodEntry) - if e.Location.Method == method { - out = e - return false - } - c.ResumeAll() - return true - } - - err := c.WatchEvents(ctx, MethodEntry, SuspendAll, onEvent, ClassOnlyEventModifier(class)) - if err != nil { - return nil, err - } - - return out, nil -} diff --git a/core/java/jdwp/invoke_options.go b/core/java/jdwp/invoke_options.go deleted file mode 100644 index 153a97420b..0000000000 --- a/core/java/jdwp/invoke_options.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "strings" - -// InvokeOptions is a collection of bit flags controlling an invoke. -type InvokeOptions int - -const ( - // InvokeSingleThreaded prevents the resume of all other threads when - // performing the invoke. Once the invoke has finished, the single thread will - // suspended again. - InvokeSingleThreaded = InvokeOptions(1) - - // InvokeNonvirtual invokes the method without using regular, virtual - // invocation. - InvokeNonvirtual = InvokeOptions(2) -) - -func (i InvokeOptions) String() string { - parts := []string{} - if i&InvokeSingleThreaded != 0 { - parts = append(parts, "InvokeSingleThreaded") - } - if i&InvokeNonvirtual != 0 { - parts = append(parts, "InvokeNonvirtual") - } - return strings.Join(parts, ", ") -} diff --git a/core/java/jdwp/jdwp.go b/core/java/jdwp/jdwp.go deleted file mode 100644 index 37c0c960e6..0000000000 --- a/core/java/jdwp/jdwp.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package jdwp implements types to communicate using the the Java Debug Wire Protocol. -package jdwp - -import ( - "bufio" - "bytes" - "context" - "fmt" - "io" - "reflect" - "sync" - "time" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/data/binary" - "github.com/google/gapid/core/data/endian" - "github.com/google/gapid/core/os/device" -) - -var ( - handshake = []byte("JDWP-Handshake") - - defaultIDSizes = IDSizes{ - FieldIDSize: 8, - MethodIDSize: 8, - ObjectIDSize: 8, - ReferenceTypeIDSize: 8, - FrameIDSize: 8, - } -) - -// Connection represents a JDWP connection. -type Connection struct { - in io.Reader - r binary.Reader - w binary.Writer - flush func() error - idSizes IDSizes - nextPacketID packetID - events map[EventRequestID]chan<- Event - replies map[packetID]chan<- replyPacket - sync.Mutex -} - -// Open creates a Connection using conn for I/O. -func Open(ctx context.Context, conn io.ReadWriteCloser) (*Connection, error) { - if err := exchangeHandshakes(conn); err != nil { - return nil, err - } - - buf := bufio.NewWriterSize(conn, 1024) - r := endian.Reader(conn, device.BigEndian) - w := endian.Writer(buf, device.BigEndian) - c := &Connection{ - in: conn, - r: r, - w: w, - flush: buf.Flush, - idSizes: defaultIDSizes, - events: map[EventRequestID]chan<- Event{}, - replies: map[packetID]chan<- replyPacket{}, - } - - crash.Go(func() { c.recv(ctx) }) - var err error - c.idSizes, err = c.GetIDSizes() - if err != nil { - return nil, err - } - return c, nil -} - -func exchangeHandshakes(conn io.ReadWriter) error { - if _, err := conn.Write(handshake); err != nil { - return err - } - ok, err := expect(conn, handshake) - if err != nil { - return err - } - if !ok { - return fmt.Errorf("Bad handshake") - } - return nil -} - -// expect reads c.in, expecting the specfified sequence of bytes. If the read -// data doesn't match, then the function returns immediately with false. -func expect(conn io.Reader, expected []byte) (bool, error) { - got := make([]byte, len(expected)) - for len(expected) > 0 { - n, err := conn.Read(got) - if err != nil { - return false, err - } - for i := 0; i < n; i++ { - if got[i] != expected[i] { - return false, nil - } - } - got, expected = got[n:], expected[n:] - } - return true, nil -} - -// get sends the specified command and waits for a reply. -func (c *Connection) get(cmd cmd, req interface{}, out interface{}) error { - p, err := c.req(cmd, req) - if err != nil { - return err - } - return p.wait(out) -} - -// req sends the specified command and returns a pending. -func (c *Connection) req(cmd cmd, req interface{}) (*pending, error) { - data := bytes.Buffer{} - if req != nil { - e := endian.Writer(&data, device.BigEndian) - if err := c.encode(e, reflect.ValueOf(req)); err != nil { - return nil, err - } - } - - id, replyChan := c.newReplyHandler() - - p := cmdPacket{id: id, cmdSet: cmd.set, cmdID: cmd.id, data: data.Bytes()} - - c.Lock() - defer c.Unlock() - - if err := p.write(c.w); err != nil { - return nil, err - } - if err := c.flush(); err != nil { - return nil, err - } - - dbg("<%v> send: %v, %+v", id, cmd, req) - - return &pending{c, replyChan, id}, nil -} - -type pending struct { - c *Connection - p <-chan replyPacket - id packetID -} - -// wait blocks until the penging response is received, filling out with the -// response data. -func (p *pending) wait(out interface{}) error { - select { - case reply := <-p.p: - if reply.err != ErrNone { - dbg("<%v> recv err: %+v", p.id, reply.err) - return reply.err - } - if out == nil { - return nil - } - r := bytes.NewReader(reply.data) - d := endian.Reader(r, device.BigEndian) - if err := p.c.decode(d, reflect.ValueOf(out)); err != nil { - return err - } - dbg("<%v> recv: %+v", p.id, out) - if offset, _ := r.Seek(0, 1); offset != int64(len(reply.data)) { - panic(fmt.Errorf("Only %d/%d bytes read from reply packet", offset, len(reply.data))) - } - return nil - case <-time.After(time.Second * 120): - return fmt.Errorf("timeout") - } -} - -func (c *Connection) newReplyHandler() (packetID, <-chan replyPacket) { - reply := make(chan replyPacket, 1) - c.Lock() - id := c.nextPacketID - c.nextPacketID++ - c.replies[id] = reply - c.Unlock() - return id, reply -} diff --git a/core/java/jdwp/jdwp_test.go b/core/java/jdwp/jdwp_test.go deleted file mode 100644 index 363bd96165..0000000000 --- a/core/java/jdwp/jdwp_test.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp_test - -import ( - "context" - "os" - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/java/jdwp" - "github.com/google/gapid/core/java/jdwp/test" - "github.com/google/gapid/core/log" -) - -var source = map[string]string{ - "main.java": ` -public class main { - static { - Calculator.register(); - } - public static void main(String[] args) throws Exception { - System.out.print("Doing stuff\n"); - Thread.sleep(1000); - } -}`, - "Calculator.java": ` -public class Calculator { - public static void register() {} - - private int value = 0; - - public static int Add(int a, int b) { return a + b; } - public void Add(int a) { value += a; } - - public int Result() { return value; } -} -`, -} - -func TestMain(m *testing.M) { - ctx := context.Background() - ctx = log.PutHandler(ctx, log.Normal.Handler(log.Std())) - os.Exit(test.BuildRunAndConnect(ctx, source, func(ctx context.Context, c *jdwp.Connection) int { - // Wait for java to load the prepare class - t, err := c.WaitForClassPrepare(ctx, "Calculator") - if err != nil { - log.F(ctx, true, "Failed to wait for Calculator prepare. Error: %v", err) - return -1 - } - - connection, thread = c, t - return m.Run() - })) -} - -var connection *jdwp.Connection -var thread jdwp.ThreadID - -func TestGetClassBySignature(t *testing.T) { - ctx := log.Testing(t) - - calculator, err := connection.GetClassBySignature("LCalculator;") - if err != nil { - log.F(ctx, true, "GetClassesBySignature returned error: %v", err) - } - - assert.For(ctx, "Calculator kind").That(calculator.Kind).Equals(jdwp.Class) - assert.For(ctx, "Calculator kind").That(calculator.Signature).Equals("LCalculator;") -} - -func TestInvokeStaticMethod(t *testing.T) { - ctx := log.Testing(t) - - class, err := connection.GetClassBySignature("LCalculator;") - if err != nil { - log.F(ctx, true, "GetClassesBySignature returned error: %v", err) - return - } - - methods, err := connection.GetMethods(class.TypeID) - if err != nil { - log.F(ctx, true, "GetMethods returned error: %v", err) - return - } - - add := methods.FindBySignature("Add", "(II)I") - if add == nil { - log.F(ctx, true, "Couldn't find method Add: %v", err) - return - } - - result, err := connection.InvokeStaticMethod(class.ClassID(), add.ID, thread, jdwp.InvokeSingleThreaded, 3, 7) - if err != nil { - log.F(ctx, true, "InvokeStaticMethod returned error: %v", err) - return - } - assert.For(ctx, "Add(3, 7)").That(result.Result).Equals(10) -} - -func TestInvokeMethod(t *testing.T) { - ctx := log.Testing(t) - - class, err := connection.GetClassBySignature("LCalculator;") - if err != nil { - log.F(ctx, true, "GetClassesBySignature returned error: %v", err) - return - } - - methods, err := connection.GetMethods(class.TypeID) - if err != nil { - log.F(ctx, true, "GetMethods returned error: %v", err) - return - } - - constructor := methods.FindBySignature("", "()V") - if constructor == nil { - log.F(ctx, true, "Couldn't find constructor: %v", err) - log.I(ctx, "Available methods:\n%v", methods) - return - } - - instance, err := connection.NewInstance(class.ClassID(), constructor.ID, thread, jdwp.InvokeSingleThreaded) - if err != nil { - log.F(ctx, true, "NewInstance returned error: %v", err) - return - } - - add := methods.FindBySignature("Add", "(I)V") - if add == nil { - log.F(ctx, true, "Couldn't find method Add: %v", err) - log.I(ctx, "Available methods:\n%v", methods) - return - } - - for _, i := range []int{3, 6, 8} { - _, err = connection.InvokeMethod( - instance.Result.Object, - class.ClassID(), - add.ID, - thread, - jdwp.InvokeSingleThreaded, - i) - if err != nil { - log.F(ctx, true, "InvokeMethod returned error: %v", err) - return - } - } - - resultf := methods.FindBySignature("Result", "()I") - if resultf == nil { - log.F(ctx, true, "Couldn't find method Result: %v", err) - log.I(ctx, "Available methods:\n%v", methods) - return - } - - result, err := connection.InvokeMethod( - instance.Result.Object, - class.ClassID(), - resultf.ID, - thread, - jdwp.InvokeSingleThreaded) - if err != nil { - log.F(ctx, true, "InvokeMethod returned error: %v", err) - return - } - assert.For(ctx, "Result").That(result.Result).Equals(3 + 6 + 8) -} diff --git a/core/java/jdwp/method.go b/core/java/jdwp/method.go deleted file mode 100644 index 40b0788e6d..0000000000 --- a/core/java/jdwp/method.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "fmt" - "strings" -) - -// Method describes a single method -type Method struct { - ID MethodID - Name string - Signature string - ModBits ModBits -} - -// Methods is a collection of methods -type Methods []Method - -func (l Methods) String() string { - parts := make([]string, len(l)) - for i, m := range l { - parts[i] = fmt.Sprintf("%+v", m) - } - return strings.Join(parts, "\n") -} - -// FindBySignature returns the method with the matching signature in l, or nil -// if no method with a matching signature is found in l. -func (l Methods) FindBySignature(name, sig string) *Method { - for _, m := range l { - if m.Name == name && m.Signature == sig { - return &m - } - } - return nil -} - -// FindByID returns the method with the matching identifier in l, or nil if no -// method with a matching identifier is found in l. -func (l Methods) FindByID(id MethodID) *Method { - for _, m := range l { - if m.ID == id { - return &m - } - } - return nil -} diff --git a/core/java/jdwp/modbits.go b/core/java/jdwp/modbits.go deleted file mode 100644 index b6b07f2002..0000000000 --- a/core/java/jdwp/modbits.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "strings" - -// ModBits represents the modifier bitflags for a class, method or field. -type ModBits int - -const ( - ModPublic = ModBits(1) - ModPrivate = ModBits(2) - ModProtected = ModBits(4) - ModStatic = ModBits(8) - ModFinal = ModBits(16) - ModSynchronized = ModBits(32) - ModVolatile = ModBits(64) - ModTransient = ModBits(128) - ModInterface = ModBits(512) - ModNative = ModBits(256) - ModAbstract = ModBits(1024) - ModStrict = ModBits(2048) -) - -func (m ModBits) String() string { - parts := []string{} - if m&ModPublic != 0 { - parts = append(parts, "public") - } - if m&ModPrivate != 0 { - parts = append(parts, "private") - } - if m&ModProtected != 0 { - parts = append(parts, "protected") - } - if m&ModStatic != 0 { - parts = append(parts, "static") - } - if m&ModFinal != 0 { - parts = append(parts, "final") - } - if m&ModSynchronized != 0 { - parts = append(parts, "synchronized") - } - if m&ModVolatile != 0 { - parts = append(parts, "volatile") - } - if m&ModTransient != 0 { - parts = append(parts, "transient") - } - if m&ModInterface != 0 { - parts = append(parts, "interface") - } - if m&ModNative != 0 { - parts = append(parts, "native") - } - if m&ModAbstract != 0 { - parts = append(parts, "abstract") - } - if m&ModStrict != 0 { - parts = append(parts, "strict") - } - - return strings.Join(parts, " ") -} - -func (m ModBits) Public() bool { return m&ModPublic != 0 } -func (m ModBits) Private() bool { return m&ModPrivate != 0 } -func (m ModBits) Protected() bool { return m&ModProtected != 0 } -func (m ModBits) Static() bool { return m&ModStatic != 0 } -func (m ModBits) Final() bool { return m&ModFinal != 0 } -func (m ModBits) Synchronized() bool { return m&ModSynchronized != 0 } -func (m ModBits) Volatile() bool { return m&ModVolatile != 0 } -func (m ModBits) Transient() bool { return m&ModTransient != 0 } -func (m ModBits) Interface() bool { return m&ModInterface != 0 } -func (m ModBits) Native() bool { return m&ModNative != 0 } -func (m ModBits) Abstract() bool { return m&ModAbstract != 0 } -func (m ModBits) Strict() bool { return m&ModStrict != 0 } diff --git a/core/java/jdwp/packet.go b/core/java/jdwp/packet.go deleted file mode 100644 index c3e85a7046..0000000000 --- a/core/java/jdwp/packet.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "fmt" - - "github.com/google/gapid/core/data/binary" -) - -type packetID uint32 - -type packetFlags uint8 - -const packetIsReply = packetFlags(0x80) - -type cmdPacket struct { - id packetID - flags packetFlags - cmdSet cmdSet - cmdID cmdID - data []byte -} - -// JDWP uses the following structs for all communication: -// -// struct cmdPacket { -// length uint32 4 bytes -// id packetID 4 bytes -// flags packetFlags 1 bytes -// cmdSet cmdSet 1 bytes -// cmd uint8 1 bytes -// data []byte N bytes -// } -// -// struct reply { -// length uint32 4 bytes -// id packetID 4 bytes -// flags packetFlags 1 bytes -// err errorCode 2 bytes -// data []byte N bytes -// } - -func (p cmdPacket) write(w binary.Writer) error { - w.Uint32(11 + uint32(len(p.data))) - w.Uint32(uint32(p.id)) - w.Uint8(uint8(p.flags)) - w.Uint8(uint8(p.cmdSet)) - w.Uint8(uint8(p.cmdID)) - w.Data(p.data) - return w.Error() -} - -type replyPacket struct { - id packetID - err Error - data []byte -} - -func (c *Connection) readPacket() (interface{}, error) { - len := c.r.Uint32() - if err := c.r.Error(); err != nil { - return nil, err - } - if len < 11 { - return replyPacket{}, fmt.Errorf("Packet length too short (%d)", len) - } - id := packetID(c.r.Uint32()) - flags := packetFlags(c.r.Uint8()) - if flags&packetIsReply != 0 { - // Reply packet - out := replyPacket{ - id: id, - err: Error(c.r.Uint16()), - } - out.data = make([]byte, len-11) - c.r.Data(out.data) - return out, c.r.Error() - } - // Command packet - out := cmdPacket{ - cmdSet: cmdSet(c.r.Uint8()), - cmdID: cmdID(c.r.Uint8()), - } - out.data = make([]byte, len-11) - c.r.Data(out.data) - return out, c.r.Error() -} diff --git a/core/java/jdwp/recv.go b/core/java/jdwp/recv.go deleted file mode 100644 index c3101dfbb2..0000000000 --- a/core/java/jdwp/recv.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "bytes" - "context" - "io" - "reflect" - - "github.com/google/gapid/core/data/endian" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" -) - -// recv decodes all the incoming reply or command packets, forwarding them on -// to the corresponding chans. recv is blocking and should be run on a new -// go routine. -// recv returns when ctx is stopped or there's an IO error. -func (c *Connection) recv(ctx context.Context) { - for !task.Stopped(ctx) { - packet, err := c.readPacket() - switch err { - case nil: - case io.EOF: - return - default: - if !task.Stopped(ctx) { - log.W(ctx, "Failed to read packet. Error: %v", err) - } - return - } - - switch packet := packet.(type) { - case replyPacket: - c.Lock() - out, ok := c.replies[packet.id] - delete(c.replies, packet.id) - c.Unlock() - if !ok { - log.W(ctx, "Unexpected reply for packet %d", packet.id) - continue - } - out <- packet - - case cmdPacket: - switch { - case packet.cmdSet == cmdSetEvent && packet.cmdID == cmdCompositeEvent: - d := endian.Reader(bytes.NewReader(packet.data), device.BigEndian) - l := events{} - if err := c.decode(d, reflect.ValueOf(&l)); err != nil { - log.F(ctx, true, "Couldn't decode composite event data. Error: %v", err) - continue - } - - for _, ev := range l.Events { - dbg("<%v> event: %T %+v", ev.request(), ev, ev) - - c.Lock() - handler, ok := c.events[ev.request()] - c.Unlock() - - if ok { - handler <- ev - } else { - dbg("No event handler registered for %+v", ev) - } - } - - default: - dbg("received unknown packet %+v", packet) - // Unknown packet. Ignore. - } - } - } -} diff --git a/core/java/jdwp/suspend_policy.go b/core/java/jdwp/suspend_policy.go deleted file mode 100644 index a0de4aa3c0..0000000000 --- a/core/java/jdwp/suspend_policy.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// SuspendPolicy describes what threads should be suspended on an event being -// raised. -type SuspendPolicy byte - -const ( - // SuspendNone suspends no threads when a event is raised. - SuspendNone = SuspendPolicy(0) - // SuspendEventThread suspends only the event's thread when a event is raised. - SuspendEventThread = SuspendPolicy(1) - // SuspendAll suspends all threads when a event is raised. - SuspendAll = SuspendPolicy(2) -) - -func (s SuspendPolicy) String() string { - switch s { - case SuspendNone: - return "SuspendNone" - case SuspendEventThread: - return "SuspendEventThread" - case SuspendAll: - return "SuspendAll" - } - return fmt.Sprint(int(s)) -} diff --git a/core/java/jdwp/tag.go b/core/java/jdwp/tag.go deleted file mode 100644 index f3da19eff1..0000000000 --- a/core/java/jdwp/tag.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// Tag is a type kind enumerator. -type Tag uint8 - -const ( - TagArray = Tag(91) // '[' - an array object (objectID size). - TagByte = Tag(66) // 'B' - a byte value (1 byte). - TagChar = Tag(67) // 'C' - a character value (2 bytes). - TagObject = Tag(76) // 'L' - an object (objectID size). - TagFloat = Tag(70) // 'F' - a float value (4 bytes). - TagDouble = Tag(68) // 'D' - a double value (8 bytes). - TagInt = Tag(73) // 'I' - an int value (4 bytes). - TagLong = Tag(74) // 'J' - a long value (8 bytes). - TagShort = Tag(83) // 'S' - a short value (2 bytes). - TagVoid = Tag(86) // 'V' - a void value (no bytes). - TagBoolean = Tag(90) // 'Z' - a boolean value (1 byte). - TagString = Tag(115) // 's' - a String object (objectID size). - TagThread = Tag(116) // 't' - a Thread object (objectID size). - TagThreadGroup = Tag(103) // 'g' - a ThreadGroup object (objectID size). - TagClassLoader = Tag(108) // 'l' - a ClassLoader object (objectID size). - TagClassObject = Tag(99) // 'c' - a class object object (objectID size). -) - -func (t Tag) String() string { - switch t { - case TagArray: - return "Array" - case TagByte: - return "Byte" - case TagChar: - return "Char" - case TagObject: - return "Object" - case TagFloat: - return "Float" - case TagDouble: - return "Double" - case TagInt: - return "Int" - case TagLong: - return "Long" - case TagShort: - return "Short" - case TagVoid: - return "Void" - case TagBoolean: - return "Boolean" - case TagString: - return "String" - case TagThread: - return "Thread" - case TagThreadGroup: - return "ThreadGroup" - case TagClassLoader: - return "ClassLoader" - case TagClassObject: - return "ClassObject" - default: - return fmt.Sprintf("Tag<%v>", int(t)) - } -} diff --git a/core/java/jdwp/test/BUILD.bazel b/core/java/jdwp/test/BUILD.bazel deleted file mode 100644 index 7ab542dcae..0000000000 --- a/core/java/jdwp/test/BUILD.bazel +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = ["test.go"], - importpath = "github.com/google/gapid/core/java/jdwp/test", - tags = ["integration"], - visibility = ["//visibility:public"], - deps = [ - "//core/event/task:go_default_library", - "//core/java/jdwp:go_default_library", - "//core/log:go_default_library", - "//core/os/shell:go_default_library", - ], -) diff --git a/core/java/jdwp/test/test.go b/core/java/jdwp/test/test.go deleted file mode 100644 index 4250590d33..0000000000 --- a/core/java/jdwp/test/test.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package test - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "path/filepath" - "time" - - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/java/jdwp" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/shell" -) - -// findFreePort returns a currently free TCP port on the localhost. -// There are two potential issues with this function: -// * There is the potential for the port to be taken between the function -// returning and the port actually being used. -// * The system _may_ hold on to the socket after it has been told to close. -// Because of these issues, there is a potential for flakiness. -func findFreePort() (int, error) { - dummy, err := net.Listen("tcp", ":0") - if err != nil { - return 0, err - } - defer dummy.Close() - return dummy.Addr().(*net.TCPAddr).Port, nil -} - -// JavaSource is a map of file name 'foo.java' to the source code. -type JavaSource map[string]string - -func runJavaServer(ctx context.Context, sources JavaSource, port int) task.Signal { - signal, done := task.NewSignal() - go func() { - defer done(ctx) - tmp, err := ioutil.TempDir("", "jdwp") - if err != nil { - log.E(ctx, "Couldn't get temporary directory. Error: %v", err) - return - } - defer os.RemoveAll(tmp) - sourceNames := make([]string, 0, len(sources)) - for name, source := range sources { - if err := ioutil.WriteFile(filepath.Join(tmp, name), []byte(source), 0777); err != nil { - log.E(ctx, "Couldn't write to temporary source file. Error: %v", err) - return - } - sourceNames = append(sourceNames, name) - } - l := log.From(ctx) - if err := shell. - Command("javac", sourceNames...). - In(tmp). - Capture(nil, l.Writer(log.Error)). - Run(ctx); err != nil { - - log.E(ctx, "Couldn't compile java source. Error: %v", err) - return - } - agentlib := fmt.Sprintf("-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address=%v", port) - if err := shell. - Command("java", agentlib, "main"). - In(tmp). - Capture(l.Writer(log.Info), l.Writer(log.Error)). - Run(ctx); err != nil { - - if !task.Stopped(ctx) { - log.E(ctx, "Couldn't start java server. Error: %v", err) - } - return - } - }() - return signal -} - -// BuildRunAndConnect builds all the source files with javac, executes them with -// java, attaches to it via JDWP, then calls onConnect with the connection. -func BuildRunAndConnect(ctx context.Context, source JavaSource, onConnect func(ctx context.Context, conn *jdwp.Connection) int) int { - ctx, stop := task.WithTimeout(ctx, time.Second*30) - - port, err := findFreePort() - if err != nil { - log.E(ctx, "Failed to find a free port. Error: %v", err) - return -1 - } - - done := runJavaServer(ctx, source, port) - defer func() { - stop() - <-done - }() - - var socket io.ReadWriteCloser - for i := 0; i < 5; i++ { - var err error - if socket, err = net.Dial("tcp", fmt.Sprintf("localhost:%v", port)); err == nil { - break - } - time.Sleep(time.Second) - } - - if socket == nil { - log.E(ctx, "Failed to connect to the socket. Error: %v", err) - return -1 - } - - conn, err := jdwp.Open(ctx, socket) - if err != nil { - log.E(ctx, "Failed to open the JDWP connection. Error: %v", err) - return -1 - } - - return onConnect(ctx, conn) -} diff --git a/core/java/jdwp/thread_status.go b/core/java/jdwp/thread_status.go deleted file mode 100644 index d69b209a9b..0000000000 --- a/core/java/jdwp/thread_status.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// ThreadStatus is an enumerator of thread state. -type ThreadStatus int - -const ( - ThreadZombie = ThreadStatus(0) - ThreadRunning = ThreadStatus(1) - ThreadSleeping = ThreadStatus(2) - ThreadMonitor = ThreadStatus(3) - ThreadWait = ThreadStatus(4) -) - -// SuspendStatus is an enumerator of thread suspend state. -type SuspendStatus int - -const ( - NotSuspended = SuspendStatus(0) - Suspended = SuspendStatus(1) -) - -func (s ThreadStatus) String() string { - switch s { - case ThreadZombie: - return "Zombie" - case ThreadRunning: - return "Running" - case ThreadSleeping: - return "Sleeping" - case ThreadMonitor: - return "Monitor" - case ThreadWait: - return "Wait" - } - return fmt.Sprint(int(s)) -} - -func (s SuspendStatus) String() string { - switch s { - case NotSuspended: - return "NotSuspended" - case Suspended: - return "Suspended" - } - return fmt.Sprint(int(s)) -} diff --git a/core/java/jdwp/type_tag.go b/core/java/jdwp/type_tag.go deleted file mode 100644 index 281e650f9b..0000000000 --- a/core/java/jdwp/type_tag.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import "fmt" - -// TypeTag is an enumerator of class, interface or array. -type TypeTag uint8 - -const ( - Class = TypeTag(1) // Type is a class. - Interface = TypeTag(2) // Type is an interface. - Array = TypeTag(3) // Type is an array. -) - -func (t TypeTag) String() string { - switch t { - case Class: - return "Class" - case Interface: - return "Interface" - case Array: - return "Array" - default: - return fmt.Sprintf("TypeTag<%v>", int(t)) - } -} diff --git a/core/java/jdwp/types.go b/core/java/jdwp/types.go deleted file mode 100644 index a34691904f..0000000000 --- a/core/java/jdwp/types.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -import ( - "fmt" - "sort" -) - -// TaggedObjectID is a type and object identifier pair. -type TaggedObjectID struct { - Type Tag - Object ObjectID -} - -// Location describes a code location. -type Location struct { - Type TypeTag - Class ClassID - Method MethodID - Location uint64 -} - -// Char is a 16-bit character type. -type Char int16 - -// ObjectID is an object instance identifier. -// If the specific object type is known, then ObjectID can be cast to -// ThreadID, ThreadGroupID, StringID, ClassLoaderID, ClassObjectID or ArrayID. -type ObjectID uint64 - -// ThreadID is an thread instance identifier. -// ThreadID can always be safely cast to the less specific ObjectID. -type ThreadID uint64 - -// ThreadGroupID is an thread group identifier. -// ThreadGroupID can always be safely cast to the less specific ObjectID. -type ThreadGroupID uint64 - -// StringID is a string instance identifier. -// StringID can always be safely cast to the less specific ObjectID. -type StringID uint64 - -// ClassLoaderID is class loader identifier. -// ClassLoaderID can always be safely cast to the less specific ObjectID. -type ClassLoaderID uint64 - -// ClassObjectID is a class object instance identifier. -// ClassObjectID can always be safely cast to the less specific ObjectID. -type ClassObjectID uint64 - -// ArrayID is an array instance identifier. -// ArrayID can always be safely cast to the less specific ObjectID. -type ArrayID uint64 - -// Object is the interface implemented by all types that are a variant of ObjectID. -type Object interface { - ID() ObjectID -} - -// ID returns the ObjectID -func (i ObjectID) ID() ObjectID { return i } - -// ID returns the ThreadID as an ObjectID -func (i ThreadID) ID() ObjectID { return ObjectID(i) } - -// ID returns the ThreadGroupID as an ObjectID -func (i ThreadGroupID) ID() ObjectID { return ObjectID(i) } - -// ID returns the StringID as an ObjectID -func (i StringID) ID() ObjectID { return ObjectID(i) } - -// ID returns the ClassLoaderID as an ObjectID -func (i ClassLoaderID) ID() ObjectID { return ObjectID(i) } - -// ID returns the ClassObjectID as an ObjectID -func (i ClassObjectID) ID() ObjectID { return ObjectID(i) } - -// ID returns the ArrayID as an ObjectID -func (i ArrayID) ID() ObjectID { return ObjectID(i) } - -// ID returns the ObjectID of the TaggedObjectID -func (i TaggedObjectID) ID() ObjectID { return i.Object } - -// ReferenceTypeID is a reference type identifier. -// If the specific reference type is known, then ReferenceTypeID can be cast to -// ClassID, InterfaceID or ArrayTypeID. -type ReferenceTypeID uint64 - -// ClassID is a class reference type identifier. -// ClassID can always be safely cast to the less specific ReferenceTypeID. -type ClassID uint64 - -// InterfaceID is an interface reference type identifier. -// InterfaceID can always be safely cast to the less specific ReferenceTypeID. -type InterfaceID uint64 - -// ArrayTypeID is an array reference type identifier. -// ArrayTypeID can always be safely cast to the less specific ReferenceTypeID. -type ArrayTypeID uint64 - -// MethodID is the identifier for a single method for a class or interface. -type MethodID uint64 - -// FieldID is the identifier for a single method for a class or interface. -type FieldID uint64 - -// FrameID is the identifier for a stack frame. -type FrameID uint64 - -// FrameVariable contains all of the information a single variable. -type FrameVariable struct { - CodeIndex uint64 - Name string - Signature string - Length int - Slot int -} - -// VariableTable contains all of the variables for a stack frame. -type VariableTable struct { - ArgCount int - Slots []FrameVariable -} - -func (i ObjectID) String() string { return fmt.Sprintf("ObjectID<%d>", uint64(i)) } -func (i ThreadID) String() string { return fmt.Sprintf("ThreadID<%d>", uint64(i)) } -func (i ThreadGroupID) String() string { return fmt.Sprintf("ThreadGroupID<%d>", uint64(i)) } -func (i StringID) String() string { return fmt.Sprintf("StringID<%d>", uint64(i)) } -func (i ClassLoaderID) String() string { return fmt.Sprintf("ClassLoaderID<%d>", uint64(i)) } -func (i ClassObjectID) String() string { return fmt.Sprintf("ClassObjectID<%d>", uint64(i)) } -func (i ArrayID) String() string { return fmt.Sprintf("ArrayID<%d>", uint64(i)) } -func (i ReferenceTypeID) String() string { return fmt.Sprintf("ReferenceTypeID<%d>", uint64(i)) } -func (i ClassID) String() string { return fmt.Sprintf("ClassID<%d>", uint64(i)) } -func (i InterfaceID) String() string { return fmt.Sprintf("InterfaceID<%d>", uint64(i)) } -func (i ArrayTypeID) String() string { return fmt.Sprintf("ArrayTypeID<%d>", uint64(i)) } -func (i MethodID) String() string { return fmt.Sprintf("MethodID<%d>", uint64(i)) } -func (i FieldID) String() string { return fmt.Sprintf("FieldID<%d>", uint64(i)) } -func (i FrameID) String() string { return fmt.Sprintf("FrameID<%d>", uint64(i)) } - -// ArgumentSlots returns the slots that could possibly be method arguments. -// Slots that could be method arguments are slots that are acessible at -// location 0 and have a length > 0. Returns the result sorted by slot index. -func (v *VariableTable) ArgumentSlots() []FrameVariable { - r := []FrameVariable{} - for _, slot := range v.Slots { - if slot.CodeIndex == 0 && slot.Length > 0 { - r = append(r, slot) - } - } - sort.Slice(r, func(i, j int) bool { - return r[i].Slot < r[j].Slot - }) - return r -} diff --git a/core/java/jdwp/value.go b/core/java/jdwp/value.go deleted file mode 100644 index 76f4e87aec..0000000000 --- a/core/java/jdwp/value.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jdwp - -// Value is a generic value that can be one of the following types: -// • bool • Char • int • int8 -// • int16 • int32 • int64 • float32 -// • float64 • ArrayID • ClassLoaderID • ClassObjectID -// • ObjectID • StringID • ThreadGroupID • ThreadID -// • nil -type Value interface{} - -// ValueSlice contains a set of values -type ValueSlice []Value - -// untaggedValue can hold the same types as Value, but when encoded / decoded it -// is not prefixed with a type tag. -type untaggedValue interface{} diff --git a/core/os/android/adb/forward.go b/core/os/android/adb/forward.go index 76b46b6ff8..28423ab873 100644 --- a/core/os/android/adb/forward.go +++ b/core/os/android/adb/forward.go @@ -73,14 +73,6 @@ func (p NamedFileSystemSocket) adbForwardString() string { return fmt.Sprintf("localfilesystem:%s", p) } -// Jdwp represents a Jdwp process on an Android device. The value is the same as -// the PID of the process. Jdwp implements the Port interface. -type Jdwp int - -func (p Jdwp) adbForwardString() string { - return fmt.Sprintf("jdwp:%d", p) -} - // Forward will forward the specified device Port to the specified local Port. func (b *binding) Forward(ctx context.Context, local, device Port) error { return b.Command("forward", local.adbForwardString(), device.adbForwardString()).Run(ctx) diff --git a/gapii/client/BUILD.bazel b/gapii/client/BUILD.bazel index 2acec84439..3e4f7ae701 100644 --- a/gapii/client/BUILD.bazel +++ b/gapii/client/BUILD.bazel @@ -21,7 +21,6 @@ go_library( "capture.go", "doc.go", "header.go", - "jdwp_loader.go", "protocol.go", ], importpath = "github.com/google/gapid/gapii/client", @@ -29,13 +28,10 @@ go_library( deps = [ "//core/app:go_default_library", "//core/app/analytics:go_default_library", - "//core/app/crash:go_default_library", "//core/app/status:go_default_library", "//core/context/keys:go_default_library", "//core/data/endian:go_default_library", "//core/event/task:go_default_library", - "//core/java/jdbg:go_default_library", - "//core/java/jdwp:go_default_library", "//core/log:go_default_library", "//core/os/android:go_default_library", "//core/os/android/adb:go_default_library", diff --git a/gapii/client/adb.go b/gapii/client/adb.go index a4385a27ba..0e8d56df37 100644 --- a/gapii/client/adb.go +++ b/gapii/client/adb.go @@ -108,7 +108,7 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity } log.I(ctx, "Checking gapid.apk is installed") - apk, err := gapidapk.EnsureInstalled(ctx, d, abi) + _, err = gapidapk.EnsureInstalled(ctx, d, abi) if err != nil { return nil, nil, log.Err(ctx, err, "Installing gapid.apk") } @@ -127,30 +127,16 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity d.RemoveForward(ctx, port) }) - isVulkan := o.APIs&VulkanAPI != uint32(0) - var useLayers bool - if isVulkan { - useLayers = android.SupportsVulkanLayersViaSystemSettings(d) - } else { - useLayers = android.SupportsGLESLayersViaSystemSettings(d) + if !android.SupportsVulkanLayersViaSystemSettings(d) { + return nil, cleanup.Invoke(ctx), log.Err(ctx, nil, "Cannot trace without layers support") } - if useLayers { - log.I(ctx, "Setting up Layer") - cu, err := android.SetupLayers(ctx, d, p.Name, []string{gapidapk.PackageName(abi)}, []string{gapidapk.LayerName(isVulkan)}, isVulkan) - if err != nil { - return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Setting up the layer") - } - cleanup = cleanup.Then(cu) - } else if isVulkan { - m, err := reserveVulkanDevice(ctx, d) - if err != nil { - return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Setting up for tracing Vulkan") - } - cleanup = cleanup.Then(func(ctx context.Context) { - releaseVulkanDevice(ctx, d, m) - }) + log.I(ctx, "Setting up Layer") + cu, err := android.SetupLayers(ctx, d, p.Name, []string{gapidapk.PackageName(abi)}, []string{gapidapk.LayerName(true)}, true) + if err != nil { + return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Setting up the layer") } + cleanup = cleanup.Then(cu) var additionalArgs []android.ActionExtra if o.AdditionalFlags != "" { @@ -158,16 +144,9 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity } if a != nil { - if useLayers { - log.I(ctx, "Starting activity") - if err := d.StartActivity(ctx, *a, additionalArgs...); err != nil { - return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Starting activity") - } - } else { - log.I(ctx, "Starting activity in debug mode") - if err := d.StartActivityForDebug(ctx, *a, additionalArgs...); err != nil { - return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Starting activity in debug mode") - } + log.I(ctx, "Starting activity") + if err := d.StartActivity(ctx, *a, additionalArgs...); err != nil { + return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Starting activity") } } else { log.I(ctx, "No start activity selected - trying to attach...") @@ -189,11 +168,6 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity Device: d, Options: o, } - if !useLayers { - if err := process.loadAndConnectViaJDWP(ctx, apk, pid, d); err != nil { - return nil, cleanup.Invoke(ctx), err - } - } return process, cleanup, nil } diff --git a/gapii/client/jdwp_loader.go b/gapii/client/jdwp_loader.go deleted file mode 100644 index b1410039af..0000000000 --- a/gapii/client/jdwp_loader.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package client - -import ( - "context" - "fmt" - "io" - "net" - "reflect" - "time" - - "github.com/google/gapid/core/app/analytics" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/context/keys" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/java/jdbg" - "github.com/google/gapid/core/java/jdwp" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/android/adb" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/gapidapk" -) - -var ( - getClassLoaderSignatures = []struct { - signature string - argIndex int - }{ - {"(Ljava/lang/String;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)Ljava/lang/ClassLoader;", 3}, - {"(Ljava/lang/String;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/ClassLoader;", 3}, - {"(Ljava/lang/String;IZLjava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/ClassLoader;", 3}, - } -) - -func expect(r io.Reader, expected []byte) error { - got := make([]byte, len(expected)) - if _, err := io.ReadFull(r, got); err != nil { - return err - } - if !reflect.DeepEqual(expected, got) { - return fmt.Errorf("Expected %v, got %v", expected, got) - } - return nil -} - -// waitForOnCreate waits for android.app.Application.onCreate to be called, and -// then suspends all threads. -func waitForOnCreate(ctx context.Context, conn *jdwp.Connection) (*jdwp.EventMethodEntry, error) { - app, err := conn.GetClassBySignature("Landroid/app/Application;") - if err != nil { - return nil, err - } - - constructor, err := conn.GetClassMethod(app.ClassID(), "", "()V") - if err != nil { - return nil, err - } - - log.I(ctx, " Waiting for Application.()") - initEntry, err := conn.WaitForMethodEntry(ctx, app.ClassID(), constructor.ID) - if err != nil { - return nil, err - } - - var entry *jdwp.EventMethodEntry - err = jdbg.Do(conn, initEntry.Thread, func(j *jdbg.JDbg) error { - class := j.This().Call("getClass").AsType().(*jdbg.Class) - var onCreate jdwp.Method - for class != nil { - var err error - onCreate, err = conn.GetClassMethod(class.ID(), "onCreate", "()V") - if err == nil { - break - } - class = class.Super() - } - if class == nil { - return fmt.Errorf("Couldn't find Application.onCreate") - } - log.I(ctx, " Waiting for %v.onCreate()", class.String()) - out, err := conn.WaitForMethodEntry(ctx, class.ID(), onCreate.ID) - if err != nil { - return err - } - entry = out - return nil - }) - if err != nil { - return nil, err - } - - return entry, nil -} - -// waitForVulkanLoad for android.app.ApplicationLoaders.getClassLoader to be called, -// and then suspends the thread. -// This function is what is used to tell the vulkan loader where to search for -// layers. -func waitForVulkanLoad(ctx context.Context, conn *jdwp.Connection) (*jdwp.EventMethodEntry, int, error) { - loaders, err := conn.GetClassBySignature("Landroid/app/ApplicationLoaders;") - if err != nil { - return nil, 0, err - } - - for _, sig := range getClassLoaderSignatures { - if getClassLoader, err := conn.GetClassMethod(loaders.ClassID(), "getClassLoader", sig.signature); err == nil { - entry, err := conn.WaitForMethodEntry(ctx, loaders.ClassID(), getClassLoader.ID) - return entry, sig.argIndex, err - } - } - return nil, 0, fmt.Errorf("no known ApplicationLoaders.getClassLoader method found") -} - -// loadAndConnectViaJDWP connects to the application waiting for a JDWP -// connection with the specified process id, sends a number of JDWP commands to -// load the list of libraries. -func (p *Process) loadAndConnectViaJDWP( - ctx context.Context, - gapidAPK *gapidapk.APK, - pid int, - d adb.Device) error { - - const ( - reconnectAttempts = 10 - reconnectDelay = time.Second - ) - - jdwpPort, err := adb.LocalFreeTCPPort() - if err != nil { - return log.Err(ctx, err, "Finding free port") - } - ctx = log.V{"jdwpPort": jdwpPort}.Bind(ctx) - - log.I(ctx, "Forwarding TCP port %v -> JDWP pid %v", jdwpPort, pid) - if err := d.Forward(ctx, adb.TCPPort(jdwpPort), adb.Jdwp(pid)); err != nil { - return log.Err(ctx, err, "Setting up JDWP port forwarding") - } - defer func() { - // Clone context to ignore cancellation. - ctx := keys.Clone(context.Background(), ctx) - d.RemoveForward(ctx, adb.TCPPort(jdwpPort)) - }() - - ctx, stop := task.WithCancel(ctx) - defer stop() - - log.I(ctx, "Connecting to JDWP") - - // Create a JDWP connection with the application. - var sock net.Conn - var conn *jdwp.Connection - err = task.Retry(ctx, reconnectAttempts, reconnectDelay, func(ctx context.Context) (bool, error) { - if sock, err = net.Dial("tcp", fmt.Sprintf("localhost:%v", jdwpPort)); err != nil { - return false, err - } - if conn, err = jdwp.Open(ctx, sock); err != nil { - sock.Close() - log.I(ctx, "Failed to connect to the application: %v. Retrying...", err) - return false, err - } - return true, nil - }) - if err != nil { - if err == io.EOF { - analytics.SendBug(911, analytics.TargetDevice(d.Instance().GetConfiguration())) - return fmt.Errorf("Unable to connect to the application.\n\n" + - "This can happen when another debugger or IDE is running " + - "in the background, such as Android Studio.\n" + - "Please close any running Android debuggers and try again.\n\n" + - "See https://github.com/google/gapid/issues/911 for more " + - "information") - } - return log.Err(ctx, err, "Connecting to JDWP") - } - defer sock.Close() - - // Start by suspending all the threads. - conn.SuspendAll() - - processABI := func(j *jdbg.JDbg) (*device.ABI, error) { - abiName := j.Class("android.os.Build").Field("CPU_ABI").Get().(string) - abi := device.ABIByName(abiName) - if abi == nil { - return nil, fmt.Errorf("Unknown ABI %v", abiName) - } - - // For NativeBridge emulated devices opt for the native ABI of the - // emulator. - abi = d.NativeBridgeABI(ctx, abi) - - return abi, nil - } - - log.I(ctx, "Waiting for ApplicationLoaders.getClassLoader()") - getClassLoader, argIdx, err := waitForVulkanLoad(ctx, conn) - if err == nil { - // If err != nil that means we could not find or break in getClassLoader - // so we have no vulkan support. - err = jdbg.Do(conn, getClassLoader.Thread, func(j *jdbg.JDbg) error { - abi, err := processABI(j) - if err != nil { - return err - } - libsPath := gapidAPK.LibsPath(abi) - newLibraryPath := j.String(":" + libsPath) - arg := j.GetArgument("librarySearchPath", argIdx) - j.SetVariable(arg, arg.Value.Call("concat", newLibraryPath)) - return nil - }) - if err != nil { - return log.Err(ctx, err, "JDWP failure") - } - } else { - log.W(ctx, "Couldn't break in ApplicationLoaders.getClassLoader. Vulkan will not be supported.") - } - - // Wait for Application.onCreate to be called. - log.I(ctx, "Waiting for Application Creation") - onCreate, err := waitForOnCreate(ctx, conn) - if err != nil { - return log.Err(ctx, err, "Waiting for Application Creation") - } - - // We can now let the non-main threads resume. - if err := conn.ResumeAllExcept(onCreate.Thread); err != nil { - return log.Err(ctx, err, "Resuming non-main threads") - } - - // Attempt to get the GVR library handle. - // Will throw an exception for non-GVR apps. - var gvrHandle uint64 - log.I(ctx, "Installing interceptor libraries") - loadNativeGvrLibrary, vrCoreLibraryLoader := "loadNativeGvrLibrary", "com/google/vr/cardboard/VrCoreLibraryLoader" - gvrMajor, gvrMinor, gvrPoint := 1, 8, 1 - - getGVRHandle := func(j *jdbg.JDbg, libLoader jdbg.Type) error { - // loadNativeGvrLibrary has a couple of different signatures depending - // on GVR release. - for _, f := range []func() error{ - // loadNativeGvrLibrary(Context, int major, int minor, int point) - func() error { - gvrHandle = (uint64)(libLoader.Call(loadNativeGvrLibrary, j.This(), gvrMajor, gvrMinor, gvrPoint).Get().(int64)) - return nil - }, - // loadNativeGvrLibrary(Context) - func() error { - gvrHandle = (uint64)(libLoader.Call(loadNativeGvrLibrary, j.This()).Get().(int64)) - return nil - }, - } { - if jdbg.Try(f) == nil { - return nil - } - } - return fmt.Errorf("Couldn't call loadNativeGvrLibrary") - } - for _, f := range []func(j *jdbg.JDbg) error{ - func(j *jdbg.JDbg) error { - libLoader := j.Class(vrCoreLibraryLoader) - getGVRHandle(j, libLoader) - return nil - }, - func(j *jdbg.JDbg) error { - classLoader := j.This().Call("getClassLoader") - libLoader := classLoader.Call("findClass", vrCoreLibraryLoader).AsType() - getGVRHandle(j, libLoader) - return nil - }, - } { - if err := jdbg.Do(conn, onCreate.Thread, f); err == nil { - break - } - } - if gvrHandle == 0 { - log.I(ctx, "GVR library not found") - } else { - log.I(ctx, "GVR library found") - } - - // Connect to GAPII. - // This has to be done on a separate go-routine as the call to load gapii - // will block until a connection is made. - connErr := make(chan error) - - // Load GAPII library. - err = jdbg.Do(conn, onCreate.Thread, func(j *jdbg.JDbg) error { - abi, err := processABI(j) - if err != nil { - return err - } - - interceptorPath := gapidAPK.LibInterceptorPath(abi) - crash.Go(func() { connErr <- p.connect(ctx, gvrHandle, interceptorPath) }) - - gapiiPath := gapidAPK.LibGAPIIPath(abi) - ctx = log.V{"gapii.so": gapiiPath, "process abi": abi.Name}.Bind(ctx) - - if p.Options.PipeName != "" { - // Set the GAPID_PIPE_NAME environment variable. - j.Class("libcore.io.Libcore").Field("os").Call("setenv", "GAPII_PIPE_NAME", p.Options.PipeName, true) - } - - // Load the library. - log.D(ctx, "Loading GAPII library...") - j.Class("java.lang.System").Call("load", gapiiPath) - log.D(ctx, "Library loaded") - return nil - }) - if err != nil { - return log.Err(ctx, err, "loadGAPII") - } - - return <-connErr -} diff --git a/gapii/vulkan/vk_graphics_spy/cc/layer.cpp b/gapii/vulkan/vk_graphics_spy/cc/layer.cpp index 737040f60b..9452d3930c 100644 --- a/gapii/vulkan/vk_graphics_spy/cc/layer.cpp +++ b/gapii/vulkan/vk_graphics_spy/cc/layer.cpp @@ -25,7 +25,6 @@ extern "C" { #define VK_LAYER_EXPORT __attribute__((visibility("default"))) -typedef void* (*eglGetProcAddress)(const char* procname); #define LOG_DEBUG(fmt, ...) \ __android_log_print(ANDROID_LOG_DEBUG, "GAPID", fmt, ##__VA_ARGS__) @@ -36,21 +35,9 @@ typedef void* (*eglGetProcAddress)(const char* procname); static void* getLibGapii(); -// Up to and including Android P, libgapii, which contains the actual layer -// functions, is loaded via JDWP. Thus, use libEGL's eglGetProcAddress to find -// the functions. Starting with Q, libgapii will not be loaded via JDWP -// anymore, so we load it here if eglGetProcAddress can't find the symbol. static void* getProcAddress(const char* name) { - static void* libegl = dlopen("libEGL.so", RTLD_NOW); - static eglGetProcAddress pa = - (eglGetProcAddress)dlsym(libegl, "eglGetProcAddress"); - LOG_DEBUG("Looking for function %s", name); - void* result = pa(name); - if (result == nullptr) { - result = dlsym(getLibGapii(), name); - } - return result; + return dlsym(getLibGapii(), name); } VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL From fa468d50537eb98afaf9c324d5473b2a2ef8bfe9 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 18 Mar 2020 00:33:40 -0700 Subject: [PATCH 0169/1218] Make sure ready signal is fired. (#150) Make sure ready signal is fired when trace session is ready to start. Bug: b/147490759 --- gapis/perfetto/android/trace.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gapis/perfetto/android/trace.go b/gapis/perfetto/android/trace.go index 8cd0f5802a..1ad8625b13 100644 --- a/gapis/perfetto/android/trace.go +++ b/gapis/perfetto/android/trace.go @@ -285,6 +285,7 @@ func (p *Process) captureWithClientApi(ctx context.Context, start task.Signal, s ts.Stop(ctx) return 0, log.Err(ctx, nil, "Cancelled") } + ready(ctx) ts.Start(ctx) wait := make(chan error, 1) crash.Go(func() { From e5310ddaf16feef09692e4394b98989c4e8200ec Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Wed, 18 Mar 2020 20:22:48 +0000 Subject: [PATCH 0170/1218] Remove preMutate(), obsolete for Vulkan (#152) Bug: b/148010811 --- gapis/api/templates/mutate.go.tmpl | 6 +----- gapis/api/test/test.go | 4 ---- gapis/api/vulkan/vulkan.go | 4 ---- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/gapis/api/templates/mutate.go.tmpl b/gapis/api/templates/mutate.go.tmpl index b741399d35..54a0a3460a 100644 --- a/gapis/api/templates/mutate.go.tmpl +++ b/gapis/api/templates/mutate.go.tmpl @@ -162,11 +162,7 @@ ϟs, ϟt := GetState(ϟg), ϟc.Thread() ϟl, ϟa := ϟg.MemoryLayout, ϟg.Arena; _, _ = ϟl, ϟa ϟo := ϟc.Extras().Observations() - _, _ = ϟl, ϟt - - if err := ϟs.preMutate(ϟctx, ϟg, ϟc); err != nil { - return err - } + _, _, _ = ϟs, ϟl, ϟt {{Global "CurrentFunction" $}} diff --git a/gapis/api/test/test.go b/gapis/api/test/test.go index e9f37f8737..e1da1e1338 100644 --- a/gapis/api/test/test.go +++ b/gapis/api/test/test.go @@ -54,10 +54,6 @@ func (s *State) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) // or it can apply backward-compatibility fixes for older traces. func (*State) SetupInitialState(ctx context.Context) {} -func (c *State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error { - return nil -} - func (i Remapped) remap(cmd api.Cmd, s *api.GlobalState) (interface{}, bool) { return i, true } diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index 2861267233..fae71dd15d 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -92,10 +92,6 @@ func (s *State) SetupInitialState(ctx context.Context) { s.customState.init(s) } -func (State) preMutate(ctx context.Context, s *api.GlobalState, cmd api.Cmd) error { - return nil -} - func (API) GetFramebufferAttachmentInfo( ctx context.Context, after []uint64, From 17ae5a8e48a88534648cad8631d9595eb7b11786 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Wed, 18 Mar 2020 20:24:12 +0000 Subject: [PATCH 0171/1218] Place the gfxtrace artifact in KOKORO_ARTIFACTS_DIR (#155) --- kokoro/linux/build.sh | 4 ++-- kokoro/linux/common.cfg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 7f82f14616..b441580d76 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -123,6 +123,6 @@ test "${APP_EXIT_STATUS}" -eq 130 # TODO(https://github.com/google/gapid/issues/3163): The coherent memory # tracker must be disabled with SwiftShader for now. -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out out/dist/vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 out/dist/vulkan_sample.gfxtrace +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index 6fe4469f5b..8d5b475456 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -19,7 +19,7 @@ action { regex: "out/dist/agi*.zip" regex: "out/dist/*gapir*.sym" # b/151297033: save trace of sample on swiftshader, for debug purposes - regex: "out/dist/*.gfxtrace" + regex: "*.gfxtrace" strip_prefix: "out/dist" } } From 85bfa461bd64291e1daa6048a2454ee7407e1384 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 17 Mar 2020 16:05:33 -0700 Subject: [PATCH 0172/1218] Remove api.Context machinery Now that GLES is gone, this does nothing useful. --- cmd/gapit/benchmark.go | 28 --- cmd/gapit/commands.go | 7 +- cmd/gapit/common.go | 31 ---- cmd/gapit/flags.go | 30 ++-- cmd/gapit/report.go | 4 +- cmd/smoketests/main.go | 1 - .../src/main/com/google/gapid/util/Paths.java | 78 -------- gapis/api/BUILD.bazel | 1 - gapis/api/api.go | 3 - gapis/api/context.go | 46 ----- gapis/api/test/test.go | 2 - gapis/api/vulkan/vulkan.go | 22 --- gapis/extensions/extensions.go | 3 - gapis/resolve/BUILD.bazel | 1 - gapis/resolve/command_tree.go | 21 --- gapis/resolve/contexts.go | 169 ------------------ gapis/resolve/filter.go | 14 -- gapis/resolve/requests_test.go | 1 - gapis/resolve/resolvables.proto | 5 - gapis/resolve/resolve.go | 4 - gapis/resolve/resources.go | 4 - gapis/resolve/service.go | 15 -- gapis/service/path/path.go | 24 +-- gapis/service/path/path.proto | 21 --- gapis/service/path/validate.go | 13 -- gapis/service/service.go | 4 - gapis/service/service.proto | 17 -- test/integration/service/service_test.go | 1 - 28 files changed, 16 insertions(+), 554 deletions(-) delete mode 100644 gapis/api/context.go delete mode 100644 gapis/resolve/contexts.go diff --git a/cmd/gapit/benchmark.go b/cmd/gapit/benchmark.go index 58980995e2..a94d6dad0f 100644 --- a/cmd/gapit/benchmark.go +++ b/cmd/gapit/benchmark.go @@ -185,7 +185,6 @@ func (verb *benchmarkVerb) Run(ctx context.Context, flags flag.FlagSet) error { device := devices[0] wg := sync.WaitGroup{} - gotContext := sync.WaitGroup{} var resources *service.Resources wg.Add(1) @@ -201,34 +200,11 @@ func (verb *benchmarkVerb) Run(ctx context.Context, flags flag.FlagSet) error { wg.Done() }() - var context *service.Context - var ctxId *path.ID - - wg.Add(1) - gotContext.Add(1) - go func() { - ctx := status.Start(oldCtx, "Resolving Contexts") - defer status.Finish(ctx) - contextsInterface, err := client.Get(ctx, c.Contexts().Path(), resolveConfig) - if err != nil { - panic(err) - } - contexts := contextsInterface.(*service.Contexts) - ctxId = contexts.GetList()[0].ID - contextInterface, err := client.Get(ctx, contexts.GetList()[0].Path(), resolveConfig) - context = contextInterface.(*service.Context) - - gotContext.Done() - wg.Done() - }() - wg.Add(1) go func() { ctx := status.Start(oldCtx, "Getting Report") defer status.Finish(ctx) - gotContext.Wait() filter := &path.CommandFilter{} - filter.Context = ctxId _, err := client.Get(ctx, c.Commands().Path(), resolveConfig) if err != nil { @@ -302,18 +278,14 @@ func (verb *benchmarkVerb) Run(ctx context.Context, flags flag.FlagSet) error { go func() { ctx := status.Start(oldCtx, "Resolving Command Tree") - gotContext.Wait() filter := &path.CommandFilter{} - filter.Context = ctxId treePath := c.CommandTree(filter) treePath.GroupByApi = true - treePath.GroupByContext = true treePath.GroupByDrawCall = true treePath.GroupByFrame = true treePath.GroupByUserMarkers = true treePath.GroupBySubmission = true - treePath.IncludeNoContextGroups = true treePath.AllowIncompleteFrame = true treePath.MaxChildren = int32(2000) diff --git a/cmd/gapit/commands.go b/cmd/gapit/commands.go index 872540dca4..7d1aa80188 100644 --- a/cmd/gapit/commands.go +++ b/cmd/gapit/commands.go @@ -33,12 +33,9 @@ type commandsVerb struct{ CommandsFlags } func init() { verb := &commandsVerb{ CommandsFlags: CommandsFlags{ - CommandFilterFlags: CommandFilterFlags{ - Context: -1, - }, + CommandFilterFlags: CommandFilterFlags{}, }, } - verb.Context = -1 app.AddVerb(&app.Verb{ Name: "commands", ShortHelp: "Prints the command tree for a .gfxtrace file", @@ -65,13 +62,11 @@ func (verb *commandsVerb) Run(ctx context.Context, flags flag.FlagSet) error { treePath := capture.CommandTree(filter) treePath.GroupByApi = verb.GroupByAPI - treePath.GroupByContext = verb.GroupByContext treePath.GroupByThread = verb.GroupByThread treePath.GroupByDrawCall = verb.GroupByDrawCall treePath.GroupByFrame = verb.GroupByFrame treePath.GroupByUserMarkers = verb.GroupByUserMarkers treePath.GroupBySubmission = verb.GroupBySubmission - treePath.IncludeNoContextGroups = verb.IncludeNoContextGroups treePath.AllowIncompleteFrame = verb.AllowIncompleteFrame treePath.MaxChildren = int32(verb.MaxChildren) diff --git a/cmd/gapit/common.go b/cmd/gapit/common.go index 484abf66a1..55ddce35b0 100644 --- a/cmd/gapit/common.go +++ b/cmd/gapit/common.go @@ -47,37 +47,6 @@ import ( func (f CommandFilterFlags) commandFilter(ctx context.Context, client service.Service, p *path.Capture) (*path.CommandFilter, error) { filter := &path.CommandFilter{} - if f.ContextName != "" { - boxedContexts, err := client.Get(ctx, p.Contexts().Path(), nil) - if err != nil { - return nil, log.Err(ctx, err, "Failed to load the contexts") - } - contextList := boxedContexts.(*service.Contexts).List - - for i, c := range contextList { - boxedContext, err := client.Get(ctx, p.Context(c.ID.ID()).Path(), nil) - if err != nil { - return nil, log.Errf(ctx, err, "Failed to load context at index %d", i) - } - context := boxedContext.(*service.Context) - if f.ContextName == context.Name { - filter.Context = c.ID - return filter, nil - } - } - - return nil, log.Errf(ctx, err, "Could not find context named %s", f.ContextName) - } else if f.Context >= 0 { - boxedContexts, err := client.Get(ctx, p.Contexts().Path(), nil) - if err != nil { - return nil, log.Err(ctx, err, "Failed to load the contexts") - } - contexts := boxedContexts.(*service.Contexts) - if n := len(contexts.List); f.Context >= n { - return nil, log.Errf(ctx, err, "Context %d is out of range [0..%d]", f.Context, n-1) - } - filter.Context = contexts.List[f.Context].ID - } return filter, nil } diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index 151b7890a2..c81963b19a 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -141,8 +141,6 @@ type ( CaptureID bool `help:"if true then interpret the capture file argument as a capture ID that is already loaded in gapis"` } CommandFilterFlags struct { - Context int `help:"Filter to the i'th context. Does nothing with -contextname."` - ContextName string `help:"Filter by context name."` } ObservationFlags struct { Ranges bool `help:"if true then display the read and write ranges made by each command."` @@ -245,21 +243,19 @@ type ( CaptureFileFlags } CommandsFlags struct { - Gapis GapisFlags - Gapir GapirFlags - Raw bool `help:"if true then the value of constants, instead of their names, will be dumped."` - Name string `help:"Filter to commands and groups with the specified name."` - MaxChildren int `help:"_Maximum children per tree node."` - GroupByAPI bool `help:"Group commands by api"` - GroupByContext bool `help:"Group commands by context"` - GroupByThread bool `help:"Group commands by thread"` - GroupByDrawCall bool `help:"Group commands by draw call"` - GroupByFrame bool `help:"Group commands by frame"` - GroupByUserMarkers bool `help:"Group commands by user markers"` - GroupBySubmission bool `help:"Group commands by submissions"` - IncludeNoContextGroups bool `help:"_Include no context groups"` - AllowIncompleteFrame bool `help:"_Make a group for incomplete frames"` - Observations ObservationFlags + Gapis GapisFlags + Gapir GapirFlags + Raw bool `help:"if true then the value of constants, instead of their names, will be dumped."` + Name string `help:"Filter to commands and groups with the specified name."` + MaxChildren int `help:"_Maximum children per tree node."` + GroupByAPI bool `help:"Group commands by api"` + GroupByThread bool `help:"Group commands by thread"` + GroupByDrawCall bool `help:"Group commands by draw call"` + GroupByFrame bool `help:"Group commands by frame"` + GroupByUserMarkers bool `help:"Group commands by user markers"` + GroupBySubmission bool `help:"Group commands by submissions"` + AllowIncompleteFrame bool `help:"_Make a group for incomplete frames"` + Observations ObservationFlags CommandFilterFlags CaptureFileFlags } diff --git a/cmd/gapit/report.go b/cmd/gapit/report.go index a82e7bb92b..4bdb901ce1 100644 --- a/cmd/gapit/report.go +++ b/cmd/gapit/report.go @@ -34,9 +34,7 @@ type reportVerb struct{ ReportFlags } func init() { verb := &reportVerb{ ReportFlags: ReportFlags{ - CommandFilterFlags: CommandFilterFlags{ - Context: -1, - }, + CommandFilterFlags: CommandFilterFlags{}, }, } app.AddVerb(&app.Verb{ diff --git a/cmd/smoketests/main.go b/cmd/smoketests/main.go index a90bccbb33..f541a0d47a 100644 --- a/cmd/smoketests/main.go +++ b/cmd/smoketests/main.go @@ -156,7 +156,6 @@ func testTrace(ctx context.Context, nbErr *int, gapitPath string, tracepath stri {"commands", tracepath}, {"commands", "-context", "0", tracepath}, {"commands", "-groupbyapi", tracepath}, - {"commands", "-groupbycontext", tracepath}, {"commands", "-groupbydrawcall", tracepath}, {"commands", "-groupbyframe", tracepath}, {"commands", "-groupbythread", tracepath}, diff --git a/gapic/src/main/com/google/gapid/util/Paths.java b/gapic/src/main/com/google/gapid/util/Paths.java index 245f60ebf4..3127c7ec5c 100644 --- a/gapic/src/main/com/google/gapid/util/Paths.java +++ b/gapic/src/main/com/google/gapid/util/Paths.java @@ -76,12 +76,6 @@ public static Path.Any capture(Path.ID id, boolean excludeObservations) { .build(); } - public static Path.Any context(Path.Context ctx) { - return Path.Any.newBuilder() - .setContext(ctx) - .build(); - } - public static Path.Any command(Path.Command command) { return Path.Any.newBuilder() .setCommand(command) @@ -517,8 +511,6 @@ private interface Visitor { R visit(Path.CommandTree path, A arg); R visit(Path.CommandTreeNode path, A arg); R visit(Path.CommandTreeNodeForCommand path, A arg); - R visit(Path.Context path, A arg); - R visit(Path.Contexts path, A arg); R visit(Path.Device path, A arg); R visit(Path.DeviceTraceConfiguration path, A arg); R visit(Path.Events path, A arg); @@ -571,10 +563,6 @@ private static T dispatchAny(Path.Any path, Visitor visitor, A arg) return visitor.visit(path.getCommandTreeNode(), arg); case COMMAND_TREE_NODE_FOR_COMMAND: return visitor.visit(path.getCommandTreeNodeForCommand(), arg); - case CONTEXT: - return visitor.visit(path.getContext(), arg); - case CONTEXTS: - return visitor.visit(path.getContexts(), arg); case DEVICE: return visitor.visit(path.getDevice(), arg); case TRACECONFIG: @@ -653,10 +641,6 @@ protected static T dispatch(Object path, Visitor visitor, A arg) { return visitor.visit((Path.CommandTreeNode)path, arg); } else if (path instanceof Path.CommandTreeNodeForCommand) { return visitor.visit((Path.CommandTreeNodeForCommand)path, arg); - } else if (path instanceof Path.Context) { - return visitor.visit((Path.Context)path, arg); - } else if (path instanceof Path.Contexts) { - return visitor.visit((Path.Contexts)path, arg); } else if (path instanceof Path.Device) { return visitor.visit((Path.Device)path, arg); } else if (path instanceof Path.DeviceTraceConfiguration) { @@ -724,8 +708,6 @@ protected static T dispatch(Object path, Visitor visitor, A arg) { @Override public Object visit(Path.CommandTree path, Void ignored) { return path; } @Override public Object visit(Path.CommandTreeNode path, Void ignored) { return path; } @Override public Object visit(Path.CommandTreeNodeForCommand path, Void ignored) { return path; } - @Override public Object visit(Path.Context path, Void ignored) { return path; } - @Override public Object visit(Path.Contexts path, Void ignored) { return path; } @Override public Object visit(Path.Device path, Void ignored) { return path; } @Override public Object visit(Path.DeviceTraceConfiguration path, Void ignored) { return path; } @Override public Object visit(Path.Events path, Void ignored) { return path; } @@ -815,16 +797,6 @@ public Path.Any visit(Path.CommandTreeNodeForCommand path, Void ignored) { return Path.Any.newBuilder().setCommandTreeNodeForCommand(path).build(); } - @Override - public Path.Any visit(Path.Context path, Void ignored) { - return Path.Any.newBuilder().setContext(path).build(); - } - - @Override - public Path.Any visit(Path.Contexts path, Void ignored) { - return Path.Any.newBuilder().setContexts(path).build(); - } - @Override public Path.Any visit(Path.Device path, Void ignored) { return Path.Any.newBuilder().setDevice(path).build(); @@ -1029,16 +1001,6 @@ public Object visit(Path.CommandTreeNodeForCommand path, Void ignored) { return path.getCommand(); } - @Override - public Object visit(Path.Context path, Void ignored) { - return path.getCapture(); - } - - @Override - public Object visit(Path.Contexts path, Void ignored) { - return path.getCapture(); - } - @Override public Object visit(Path.Device path, Void ignored) { return null; @@ -1325,24 +1287,6 @@ public Object visit(Path.CommandTreeNodeForCommand path, Object parent) { } } - @Override - public Object visit(Path.Context path, Object parent) { - if (parent instanceof Path.Capture) { - return path.toBuilder().setCapture((Path.Capture) parent).build(); - } else { - throw new RuntimeException("Path.Context cannot set parent to " + parent.getClass().getName()); - } - } - - @Override - public Object visit(Path.Contexts path, Object parent) { - if (parent instanceof Path.Capture) { - return path.toBuilder().setCapture((Path.Capture) parent).build(); - } else { - throw new RuntimeException("Path.Contexts cannot set parent to " + parent.getClass().getName()); - } - } - @Override public Object visit(Path.Device path, Object parent) { throw new RuntimeException("Path.Device has no parent to set"); @@ -1637,8 +1581,6 @@ public StringBuilder visit(Path.CommandTree path, StringBuilder sb) { append(sb, path.getFilter()).append('['); if (path.getGroupByApi()) sb.append('A'); if (path.getGroupByThread()) sb.append('T'); - if (path.getGroupByContext()) sb.append('C'); - if (path.getIncludeNoContextGroups()) sb.append('n'); if (path.getGroupByFrame()) sb.append('F'); if (path.getAllowIncompleteFrame()) sb.append('i'); if (path.getGroupByDrawCall()) sb.append('D'); @@ -1671,20 +1613,6 @@ public StringBuilder visit(Path.CommandTreeNodeForCommand path, StringBuilder sb return sb; } - @Override - public StringBuilder visit(Path.Context path, StringBuilder sb) { - visit(path.getCapture(), sb); - sb.append(".context["); - visit(path.getID(), sb); - sb.append("]"); - return sb; - } - - @Override - public StringBuilder visit(Path.Contexts path, StringBuilder sb) { - return visit(path.getCapture(), sb).append(".contexts"); - } - @Override public StringBuilder visit(Path.Device path, StringBuilder sb) { sb.append("device{"); @@ -1875,12 +1803,6 @@ public StringBuilder visit(Path.Thumbnail path, StringBuilder sb) { private StringBuilder append(StringBuilder sb, Path.CommandFilter filter) { String sep = "(", end = ""; - if (filter.hasContext()) { - sb.append(sep).append("context="); - visit(filter.getContext(), sb); - sep = ","; - end = ")"; - } if (filter.getThreadsCount() > 0) { sb.append(sep).append("threads=").append(filter.getThreadsList()); sep = ","; diff --git a/gapis/api/BUILD.bazel b/gapis/api/BUILD.bazel index e855b0fa05..833b0739b7 100644 --- a/gapis/api/BUILD.bazel +++ b/gapis/api/BUILD.bazel @@ -31,7 +31,6 @@ go_library( "cmd_id_set.go", "cmd_observations.go", "cmd_service.go", - "context.go", "data_group.go", "doc.go", "graph_visualization.go", diff --git a/gapis/api/api.go b/gapis/api/api.go index 94316e0049..2b149dc8a7 100644 --- a/gapis/api/api.go +++ b/gapis/api/api.go @@ -52,9 +52,6 @@ type API interface { thread uint64, attachment FramebufferAttachment) (info FramebufferAttachmentInfo, err error) - // Context returns the active context for the given state. - Context(ctx context.Context, state *GlobalState, thread uint64) Context - // CreateCmd constructs and returns a new command with the specified name. CreateCmd(a arena.Arena, name string) Cmd diff --git a/gapis/api/context.go b/gapis/api/context.go deleted file mode 100644 index fa59e921d8..0000000000 --- a/gapis/api/context.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package api - -import ( - "reflect" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/gapis/service/path" -) - -// ContextID is the unique identifier for a context. -type ContextID id.ID - -// Context represents a graphics API's unique context of execution. -type Context interface { - APIObject - - // ID returns the context's unique identifier - ID() ContextID -} - -// ContextInfo is describes a Context. -// Unlike Context, ContextInfo describes the context at no particular point in -// the trace. -type ContextInfo struct { - Path *path.Context - ID ContextID - API ID - NumCommandsByType map[reflect.Type]int - Name string - Priority int - UserData map[interface{}]interface{} -} diff --git a/gapis/api/test/test.go b/gapis/api/test/test.go index e1da1e1338..246186e850 100644 --- a/gapis/api/test/test.go +++ b/gapis/api/test/test.go @@ -40,8 +40,6 @@ func (API) GetFramebufferAttachmentInfo( return api.FramebufferAttachmentInfo{}, nil } -func (API) Context(context.Context, *api.GlobalState, uint64) api.Context { return nil } - // Root returns the path to the root of the state to display. It can vary based // on filtering mode. Returning nil, nil indicates there is no state to show at // this point in the capture. diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index fae71dd15d..5abc3f0da4 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -57,28 +57,6 @@ func getStateObject(s *api.GlobalState) *State { return GetState(s) } -type VulkanContext struct{} - -// Name returns the display-name of the context. -func (VulkanContext) Name() string { - return "Vulkan Context" -} - -// ID returns the context's unique identifier. -func (VulkanContext) ID() api.ContextID { - // ID returns the context's unique identifier - return api.ContextID{1} -} - -// API returns the vulkan API. -func (VulkanContext) API() api.API { - return API{} -} - -func (API) Context(ctx context.Context, s *api.GlobalState, thread uint64) api.Context { - return VulkanContext{} -} - // Root returns the path to the root of the state to display. It can vary based // on filtering mode. Returning nil, nil indicates there is no state to show at // this point in the capture. diff --git a/gapis/extensions/extensions.go b/gapis/extensions/extensions.go index 8d1dfd8db6..149120d271 100644 --- a/gapis/extensions/extensions.go +++ b/gapis/extensions/extensions.go @@ -47,9 +47,6 @@ type EventFilter func(api.CmdID, api.Cmd, *api.GlobalState) bool type Extension struct { // Name of the extension. Name string - // AdjustContexts lets the extension rename or reprioritize the list of - // contexts. - AdjustContexts func(context.Context, []*api.ContextInfo) // Custom command groupers. CmdGroupers func(ctx context.Context, p *path.CommandTree, r *path.ResolveConfig) []cmdgrouper.Grouper // Custom events provider. diff --git a/gapis/resolve/BUILD.bazel b/gapis/resolve/BUILD.bazel index 1d34b14471..0f8c0659bf 100644 --- a/gapis/resolve/BUILD.bazel +++ b/gapis/resolve/BUILD.bazel @@ -22,7 +22,6 @@ go_library( "command_tree.go", "commands.go", "constant_set.go", - "contexts.go", "delete.go", "doc.go", "errors.go", diff --git a/gapis/resolve/command_tree.go b/gapis/resolve/command_tree.go index f7f85863e4..201e0a7886 100644 --- a/gapis/resolve/command_tree.go +++ b/gapis/resolve/command_tree.go @@ -215,27 +215,6 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error })) } - if p.GroupByContext { - var noContextID interface{} - if p.IncludeNoContextGroups { - noContextID = api.ContextID{} - } - ctxs, err := ContextsByID(ctx, p.Capture.Contexts(), r.Config) - if err != nil { - return nil, err - } - groupers = append(groupers, cmdgrouper.Run( - func(cmd api.Cmd, s *api.GlobalState) (interface{}, string) { - if api := cmd.API(); api != nil { - if context := api.Context(ctx, s, cmd.Thread()); context != nil { - id := context.ID() - return id, ctxs[id].Name - } - } - return noContextID, "No context" - })) - } - if p.GroupByThread { groupers = append(groupers, cmdgrouper.Run( func(cmd api.Cmd, s *api.GlobalState) (interface{}, string) { diff --git a/gapis/resolve/contexts.go b/gapis/resolve/contexts.go deleted file mode 100644 index 5b69e43820..0000000000 --- a/gapis/resolve/contexts.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package resolve - -import ( - "context" - "fmt" - "reflect" - "sort" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/extensions" - "github.com/google/gapid/gapis/messages" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" -) - -// Contexts resolves the list of contexts belonging to a capture. -func Contexts(ctx context.Context, p *path.Contexts, r *path.ResolveConfig) ([]*api.ContextInfo, error) { - obj, err := database.Build(ctx, &ContextListResolvable{Capture: p.Capture, Config: r}) - if err != nil { - return nil, err - } - return obj.([]*api.ContextInfo), nil -} - -// ContextsByID resolves the list of contexts belonging to a capture. -func ContextsByID(ctx context.Context, p *path.Contexts, r *path.ResolveConfig) (map[api.ContextID]*api.ContextInfo, error) { - ctxs, err := Contexts(ctx, p, r) - if err != nil { - return nil, err - } - out := map[api.ContextID]*api.ContextInfo{} - for _, c := range ctxs { - out[c.ID] = c - } - return out, nil -} - -// Context resolves the single context. -func Context(ctx context.Context, p *path.Context, r *path.ResolveConfig) (*api.ContextInfo, error) { - contexts, err := Contexts(ctx, p.Capture.Contexts(), r) - if err != nil { - return nil, err - } - id := api.ContextID(p.ID.ID()) - for _, c := range contexts { - if c.ID == id { - return c, nil - } - } - return nil, &service.ErrInvalidPath{ - Reason: messages.ErrContextDoesNotExist(p.ID), - Path: p.Path(), - } -} - -// Importance is the interface implemeneted by commands that provide an -// "importance score". This value is used to prioritize contexts. -type Importance interface { - Importance() int -} - -// Named is the interface implemented by context that have a name. -type Named interface { - Name() string -} - -// Resolve implements the database.Resolver interface. -func (r *ContextListResolvable) Resolve(ctx context.Context) (interface{}, error) { - ctx = SetupContext(ctx, r.Capture, r.Config) - - c, err := capture.ResolveGraphics(ctx) - if err != nil { - return nil, err - } - - type ctxInfo struct { - ctx api.Context - cnts map[reflect.Type]int - pri int - } - - seen := map[api.ContextID]int{} - contexts := []*ctxInfo{} - - s := c.NewState(ctx) - err = api.ForeachCmd(ctx, c.Commands, true, func(ctx context.Context, i api.CmdID, cmd api.Cmd) error { - if err := cmd.Mutate(ctx, i, s, nil, nil); err != nil { - return fmt.Errorf("Fail to mutate command %v: %v", cmd, err) - } - - api := cmd.API() - if api == nil { - return nil - } - - context := api.Context(ctx, s, cmd.Thread()) - if context == nil { - return nil - } - - id := context.ID() - idx, ok := seen[id] - if !ok { - idx = len(contexts) - seen[id] = idx - contexts = append(contexts, &ctxInfo{ - ctx: context, - cnts: map[reflect.Type]int{}, - }) - } - - c := contexts[idx] - cmdTy := reflect.TypeOf(cmd) - c.cnts[cmdTy] = c.cnts[cmdTy] + 1 - if i, ok := cmd.(Importance); ok { - c.pri += i.Importance() - } - return nil - }) - if err != nil { - return nil, err - } - - sort.Slice(contexts, func(i, j int) bool { - return contexts[i].pri > contexts[j].pri - }) - - out := make([]*api.ContextInfo, len(contexts)) - for i, c := range contexts { - name := fmt.Sprintf("Context %v", i) - if n, ok := c.ctx.(Named); ok { - name = n.Name() - } - out[i] = &api.ContextInfo{ - Path: r.Capture.Context(id.ID(c.ctx.ID())), - ID: c.ctx.ID(), - API: c.ctx.API().ID(), - NumCommandsByType: c.cnts, - Name: name, - Priority: len(contexts) - i, - UserData: map[interface{}]interface{}{}, - } - } - - for _, e := range extensions.Get() { - if e.AdjustContexts != nil { - e.AdjustContexts(ctx, out) - } - } - - return out, nil -} diff --git a/gapis/resolve/filter.go b/gapis/resolve/filter.go index 862450cad5..261e19d1c3 100644 --- a/gapis/resolve/filter.go +++ b/gapis/resolve/filter.go @@ -52,20 +52,6 @@ func buildFilter( return !sd.Hidden.Contains(id) }, } - if f := f.GetContext(); f.IsValid() { - c, err := Context(ctx, p.Context(f.ID()), r) - if err != nil { - return nil, err - } - filters = append(filters, func(id api.CmdID, cmd api.Cmd, s *api.GlobalState) bool { - if api := cmd.API(); api != nil { - if ctx := api.Context(ctx, s, cmd.Thread()); ctx != nil { - return ctx.ID() == c.ID - } - } - return false - }) - } if len(f.GetThreads()) > 0 { filters = append(filters, func(id api.CmdID, cmd api.Cmd, s *api.GlobalState) bool { thread := cmd.Thread() diff --git a/gapis/resolve/requests_test.go b/gapis/resolve/requests_test.go index 8cdbfef615..d609d7e69b 100644 --- a/gapis/resolve/requests_test.go +++ b/gapis/resolve/requests_test.go @@ -19,7 +19,6 @@ import "github.com/google/gapid/gapis/database" // Interface compliance tests var _ = []database.Resolvable{ (*CommandTreeResolvable)(nil), - (*ContextListResolvable)(nil), (*FollowResolvable)(nil), (*FramebufferAttachmentBytesResolvable)(nil), (*FramebufferAttachmentResolvable)(nil), diff --git a/gapis/resolve/resolvables.proto b/gapis/resolve/resolvables.proto index 085d8a70e4..6eb6cb250a 100644 --- a/gapis/resolve/resolvables.proto +++ b/gapis/resolve/resolvables.proto @@ -22,11 +22,6 @@ import "gapis/api/service.proto"; import "gapis/service/path/path.proto"; import "gapis/service/service.proto"; -message ContextListResolvable { - path.Capture capture = 1; - path.ResolveConfig config = 2; -} - message CommandTreeResolvable { path.CommandTree path = 1; path.ResolveConfig config = 2; diff --git a/gapis/resolve/resolve.go b/gapis/resolve/resolve.go index ce7e00638f..b93fd5e872 100644 --- a/gapis/resolve/resolve.go +++ b/gapis/resolve/resolve.go @@ -311,10 +311,6 @@ func ResolveInternal(ctx context.Context, p path.Node, r *path.ResolveConfig) (i return CommandTreeNodeForCommand(ctx, p, r) case *path.ConstantSet: return ConstantSet(ctx, p, r) - case *path.Context: - return Context(ctx, p, r) - case *path.Contexts: - return Contexts(ctx, p, r) case *path.Device: return Device(ctx, p, r) case *path.DeviceTraceConfiguration: diff --git a/gapis/resolve/resources.go b/gapis/resolve/resources.go index 32a499e238..c6edecd0e7 100644 --- a/gapis/resolve/resources.go +++ b/gapis/resolve/resources.go @@ -62,11 +62,9 @@ func (r *ResourcesResolvable) Resolve(ctx context.Context) (interface{}, error) state := capture.NewUninitializedState(ctx).ReserveMemory(ranges) state.OnResourceCreated = func(res api.Resource) { currentCmdResourceCount++ - context := currentAPI.Context(ctx, state, currentThread) tr := trackedResource{ resource: res, id: genResourceID(currentCmdIndex, currentCmdResourceCount), - context: r.Capture.Context(id.ID(context.ID())), accesses: []uint64{currentCmdIndex}, created: currentCmdIndex, } @@ -148,7 +146,6 @@ func (r *ResourcesResolvable) Resolve(ctx context.Context) (interface{}, error) type trackedResource struct { resource api.Resource id id.ID - context *path.Context name string accesses []uint64 deleted uint64 @@ -158,7 +155,6 @@ type trackedResource struct { func (r trackedResource) asService(p *path.Capture) *service.Resource { out := &service.Resource{ ID: path.NewID(r.id), - Context: r.context, Handle: r.resource.ResourceHandle(), Label: r.resource.ResourceLabel(), Order: r.resource.Order(), diff --git a/gapis/resolve/service.go b/gapis/resolve/service.go index badc864dcb..aef12bb680 100644 --- a/gapis/resolve/service.go +++ b/gapis/resolve/service.go @@ -15,30 +15,15 @@ package resolve import ( - "github.com/google/gapid/core/data/id" "github.com/google/gapid/core/memory/arena" "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/box" - "github.com/google/gapid/gapis/service/path" ) func internalToService(v interface{}) (interface{}, error) { switch v := v.(type) { case api.Cmd: return api.CmdToService(v) - case []*api.ContextInfo: - out := &service.Contexts{List: make([]*path.Context, len(v))} - for i, c := range v { - out.List[i] = c.Path - } - return out, nil - case *api.ContextInfo: - return &service.Context{ - Name: v.Name, - API: path.NewAPI(id.ID(v.API)), - Priority: uint32(v.Priority), - }, nil default: return v, nil } diff --git a/gapis/service/path/path.go b/gapis/service/path/path.go index d80718ef8f..f3549c1bc4 100644 --- a/gapis/service/path/path.go +++ b/gapis/service/path/path.go @@ -68,8 +68,6 @@ func (n *Commands) Path() *Any { return &Any{Path: &Any_Command func (n *CommandTree) Path() *Any { return &Any{Path: &Any_CommandTree{n}} } func (n *CommandTreeNode) Path() *Any { return &Any{Path: &Any_CommandTreeNode{n}} } func (n *CommandTreeNodeForCommand) Path() *Any { return &Any{Path: &Any_CommandTreeNodeForCommand{n}} } -func (n *Context) Path() *Any { return &Any{Path: &Any_Context{n}} } -func (n *Contexts) Path() *Any { return &Any{Path: &Any_Contexts{n}} } func (n *Device) Path() *Any { return &Any{Path: &Any_Device{n}} } func (n *DeviceTraceConfiguration) Path() *Any { return &Any{Path: &Any_TraceConfig{n}} } func (n *Events) Path() *Any { return &Any{Path: &Any_Events{n}} } @@ -110,8 +108,6 @@ func (n Commands) Parent() Node { return n.Capture } func (n CommandTree) Parent() Node { return n.Capture } func (n CommandTreeNode) Parent() Node { return nil } func (n CommandTreeNodeForCommand) Parent() Node { return n.Command } -func (n Context) Parent() Node { return n.Capture } -func (n Contexts) Parent() Node { return n.Capture } func (n Device) Parent() Node { return nil } func (n DeviceTraceConfiguration) Parent() Node { return n.Device } func (n Events) Parent() Node { return n.Capture } @@ -150,8 +146,6 @@ func (n *Commands) SetParent(p Node) { n.Capture, _ = p.(*Captu func (n *CommandTree) SetParent(p Node) { n.Capture, _ = p.(*Capture) } func (n *CommandTreeNode) SetParent(p Node) {} func (n *CommandTreeNodeForCommand) SetParent(p Node) { n.Command, _ = p.(*Command) } -func (n *Context) SetParent(p Node) { n.Capture, _ = p.(*Capture) } -func (n *Contexts) SetParent(p Node) { n.Capture, _ = p.(*Capture) } func (n *Device) SetParent(p Node) {} func (n *DeviceTraceConfiguration) SetParent(p Node) { n.Device, _ = p.(*Device) } func (n *Events) SetParent(p Node) { n.Capture, _ = p.(*Capture) } @@ -223,12 +217,6 @@ func (n CommandTreeNodeForCommand) Format(f fmt.State, c rune) { fmt.Fprintf(f, "%v.command-tree-node<%v>", n.Command, n.Tree) } -// Format implements fmt.Formatter to print the path. -func (n Context) Format(f fmt.State, c rune) { fmt.Fprintf(f, "%v.[%x]", n.Parent(), n.ID) } - -// Format implements fmt.Formatter to print the path. -func (n Contexts) Format(f fmt.State, c rune) { fmt.Fprintf(f, "%v.contexts", n.Parent()) } - // Format implements fmt.Formatter to print the path. func (n Device) Format(f fmt.State, c rune) { fmt.Fprintf(f, "device<%x>", n.ID) } @@ -293,7 +281,7 @@ func (n Slice) Format(f fmt.State, c rune) { // Format implements fmt.Formatter to print the path. func (n State) Format(f fmt.State, c rune) { - fmt.Fprintf(f, "%v.state", n.Parent(), n.Context) + fmt.Fprintf(f, "%v.state", n.Parent()) } // Format implements fmt.Formatter to print the path. @@ -562,11 +550,6 @@ func (n *Capture) Report(d *Device, f *CommandFilter, display bool) *Report { return &Report{Capture: n, Device: d, Filter: f, DisplayToSurface: display} } -// Contexts returns the path node to the capture's contexts. -func (n *Capture) Contexts() *Contexts { - return &Contexts{Capture: n} -} - // Messages returns the path node to the capture's messages. func (n *Capture) Messages() *Messages { return &Messages{Capture: n} @@ -619,11 +602,6 @@ func (n *Capture) Command(i uint64, subidx ...uint64) *Command { return &Command{Capture: n, Indices: indices} } -// Context returns the path node to the a context with the given ID. -func (n *Capture) Context(id id.ID) *Context { - return &Context{Capture: n, ID: NewID(id)} -} - // Thread returns the path node to the thread with the given ID. func (n *Capture) Thread(id uint64) *Thread { return &Thread{Capture: n, ID: id} diff --git a/gapis/service/path/path.proto b/gapis/service/path/path.proto index 2127c8ea86..e41dc8c1d9 100644 --- a/gapis/service/path/path.proto +++ b/gapis/service/path/path.proto @@ -37,8 +37,6 @@ message Any { CommandTreeNode command_tree_node = 9; CommandTreeNodeForCommand command_tree_node_for_command = 10; ConstantSet constant_set = 11; - Context context = 12; - Contexts contexts = 13; Device device = 14; DeviceTraceConfiguration traceConfig = 15; Events events = 16; @@ -204,17 +202,6 @@ message Messages { Capture capture = 1; } -// Contexts is path to a list of contexts in a capture. -message Contexts { - Capture capture = 1; -} - -// Context is a path to a single context in a capture. -message Context { - Capture capture = 1; - ID ID = 2; -} - // Device is a path to a device used for replay. message Device { ID ID = 1; @@ -247,8 +234,6 @@ message Field { // CommandFilter are the optional filters applied to CommandTrees and Events. message CommandFilter { - // context filters the commands to the specified context. - ID context = 1; // thread filters the commands to those with the specified threads. repeated uint64 threads = 2; } @@ -262,8 +247,6 @@ message CommandTree { CommandFilter filter = 2; // If true then commands will be grouped by API. bool group_by_api = 3; - // If true then commands will be grouped by context. - bool group_by_context = 4; // If true then commands will be grouped by thread. bool group_by_thread = 5; // If true then commands will be grouped by draw calls. @@ -276,8 +259,6 @@ message CommandTree { bool group_by_user_markers = 9; // If true then commands will be grouped by submission. bool group_by_submission = 10; - // If true and grouping by context, 'no context' groups will be created. - bool include_no_context_groups = 11; // If true and grouping by frames, commands after the last frame will be // grouped into an 'incomplete frame' group. Only if there is at least one // complete frame. @@ -454,8 +435,6 @@ message Slice { // State is a path to a subset of the GlobalState at a point in a capture. message State { Command after = 1; - // If non-nil, then the state is filtered to the specified context. - ID context = 2; } // GlobalState is an path node to the absolute global state after a specfied diff --git a/gapis/service/path/validate.go b/gapis/service/path/validate.go index 2520f81e4d..33d5fba3af 100644 --- a/gapis/service/path/validate.go +++ b/gapis/service/path/validate.go @@ -159,19 +159,6 @@ func (n *ConstantSet) Validate() error { ) } -// Validate checks the path is valid. -func (n *Context) Validate() error { - return anyErr( - checkNotNilAndValidate(n, n.Capture, "capture"), - checkIsValid(n, n.ID, "id"), - ) -} - -// Validate checks the path is valid. -func (n *Contexts) Validate() error { - return checkNotNilAndValidate(n, n.Capture, "capture") -} - // Validate checks the path is valid. func (n *Device) Validate() error { return checkIsValid(n, n.ID, "id") diff --git a/gapis/service/service.go b/gapis/service/service.go index b5673c02b2..759b53bd1c 100644 --- a/gapis/service/service.go +++ b/gapis/service/service.go @@ -251,10 +251,6 @@ func NewValue(v interface{}) *Value { return &Value{} case *Capture: return &Value{Val: &Value_Capture{v}} - case *Context: - return &Value{Val: &Value_Context{v}} - case *Contexts: - return &Value{Val: &Value_Contexts{v}} case *Commands: return &Value{Val: &Value_Commands{v}} case *CommandTree: diff --git a/gapis/service/service.proto b/gapis/service/service.proto index 7602e8a0fa..f168fb1ada 100644 --- a/gapis/service/service.proto +++ b/gapis/service/service.proto @@ -63,9 +63,6 @@ message ServerInfo { message Commands { repeated path.Command list = 1; } -message Contexts { - repeated path.Context list = 1; -} message Devices { repeated path.Device list = 1; } @@ -85,8 +82,6 @@ message Value { CommandTree command_tree = 2; CommandTreeNode command_tree_node = 3; Commands commands = 4; - Context context = 5; - Contexts contexts = 6; ConstantSet constant_set = 7; Event event = 8; Events events = 9; @@ -1001,8 +996,6 @@ message ResourcesByType { message Resource { // The resource's unique identifier. path.ID ID = 1; - // The context that created this resource. - path.Context context = 8; // The resource identifier used for display. string handle = 2; // The resource label. @@ -1017,16 +1010,6 @@ message Resource { path.Command created = 7; } -// Context represents a single rendering context in the capture. -message Context { - // The context name. - string name = 1; - // The API that this context belongs to. - path.API API = 2; - // The estimated importance for the context. 0 = lowest priority. - uint32 priority = 3; -} - // CommandTree represents a command tree hierarchy. message CommandTree { path.CommandTreeNode root = 1; diff --git a/test/integration/service/service_test.go b/test/integration/service/service_test.go index 608681a857..79dfb069df 100644 --- a/test/integration/service/service_test.go +++ b/test/integration/service/service_test.go @@ -192,7 +192,6 @@ func TestGet(t *testing.T) { ty reflect.Type }{ {capture, T((*service.Capture)(nil))}, - {capture.Contexts(), T((*service.Contexts)(nil))}, {capture.Commands(), T((*service.Commands)(nil))}, {capture.Command(swapCmdIndex), T((*api.Command)(nil))}, // TODO: box.go doesn't currently support serializing structs this big. From 63a10e1edcda12d172f6c72de9b5f232251d4783 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 18 Mar 2020 11:00:29 -0700 Subject: [PATCH 0173/1218] Remove command filter from report --- cmd/gapit/benchmark.go | 3 +- cmd/gapit/flags.go | 1 - cmd/gapit/report.go | 13 ++------ cmd/smoketests/main.go | 1 - .../src/main/com/google/gapid/util/Paths.java | 2 +- gapis/resolve/get_set_test.go | 2 +- gapis/resolve/report.go | 32 ++++++------------- gapis/service/path/path.go | 4 +-- gapis/service/path/path.proto | 2 -- test/integration/service/service_test.go | 2 +- 10 files changed, 18 insertions(+), 44 deletions(-) diff --git a/cmd/gapit/benchmark.go b/cmd/gapit/benchmark.go index a94d6dad0f..9464e9425b 100644 --- a/cmd/gapit/benchmark.go +++ b/cmd/gapit/benchmark.go @@ -204,14 +204,13 @@ func (verb *benchmarkVerb) Run(ctx context.Context, flags flag.FlagSet) error { go func() { ctx := status.Start(oldCtx, "Getting Report") defer status.Finish(ctx) - filter := &path.CommandFilter{} _, err := client.Get(ctx, c.Commands().Path(), resolveConfig) if err != nil { panic(err) } - _, err = client.Get(ctx, c.Report(device, filter, false).Path(), resolveConfig) + _, err = client.Get(ctx, c.Report(device, false).Path(), resolveConfig) wg.Done() }() diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index c81963b19a..e9b3c46228 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -184,7 +184,6 @@ type ( Gapir GapirFlags Out string `help:"output report path"` DisplayToSurface bool `help:"display the frames rendered in the replay back to the surface"` - CommandFilterFlags CaptureFileFlags } ExportReplayFlags struct { diff --git a/cmd/gapit/report.go b/cmd/gapit/report.go index 4bdb901ce1..7d89f5695c 100644 --- a/cmd/gapit/report.go +++ b/cmd/gapit/report.go @@ -32,11 +32,7 @@ import ( type reportVerb struct{ ReportFlags } func init() { - verb := &reportVerb{ - ReportFlags: ReportFlags{ - CommandFilterFlags: CommandFilterFlags{}, - }, - } + verb := &reportVerb{} app.AddVerb(&app.Verb{ Name: "report", ShortHelp: "Check a capture replays without issues", @@ -85,18 +81,13 @@ func (verb *reportVerb) Run(ctx context.Context, flags flag.FlagSet) error { return err } - filter, err := verb.commandFilter(ctx, client, capturePath) - if err != nil { - return log.Err(ctx, err, "Failed to build the CommandFilter") - } - boxedCommands, err := client.Get(ctx, capturePath.Commands().Path(), nil) if err != nil { return log.Err(ctx, err, "Failed to acquire the capture's commands") } commands := boxedCommands.(*service.Commands).List - boxedReport, err := client.Get(ctx, capturePath.Report(device, filter, verb.DisplayToSurface).Path(), nil) + boxedReport, err := client.Get(ctx, capturePath.Report(device, verb.DisplayToSurface).Path(), nil) if err != nil { return log.Err(ctx, err, "Failed to acquire the capture's report") } diff --git a/cmd/smoketests/main.go b/cmd/smoketests/main.go index f541a0d47a..5afe4f5960 100644 --- a/cmd/smoketests/main.go +++ b/cmd/smoketests/main.go @@ -154,7 +154,6 @@ func testTrace(ctx context.Context, nbErr *int, gapitPath string, tracepath stri tests := [][]string{ {"commands", tracepath}, - {"commands", "-context", "0", tracepath}, {"commands", "-groupbyapi", tracepath}, {"commands", "-groupbydrawcall", tracepath}, {"commands", "-groupbyframe", tracepath}, diff --git a/gapic/src/main/com/google/gapid/util/Paths.java b/gapic/src/main/com/google/gapid/util/Paths.java index 3127c7ec5c..d8d49bc436 100644 --- a/gapic/src/main/com/google/gapid/util/Paths.java +++ b/gapic/src/main/com/google/gapid/util/Paths.java @@ -1716,7 +1716,7 @@ public StringBuilder visit(Path.Report path, StringBuilder sb) { visit(path.getDevice(), sb); sb.append(']'); } - return append(sb, path.getFilter()); + return sb; } @Override diff --git a/gapis/resolve/get_set_test.go b/gapis/resolve/get_set_test.go index 62416332eb..5be090d5b1 100644 --- a/gapis/resolve/get_set_test.go +++ b/gapis/resolve/get_set_test.go @@ -267,7 +267,7 @@ func TestSet(t *testing.T) { // Test invalid sets {sB.Field("Map").MapIndex("bird"), 10.0, fmt.Errorf( - "Map at capture<%v>.commands[2].state>.Map has value of type test.Complexʳ, got type float64", p.ID.ID())}, + "Map at capture<%v>.commands[2].state.Map has value of type test.Complexʳ, got type float64", p.ID.ID())}, } { ctx := log.V{"path": test.path, "value": test.val}.Bind(ctx) diff --git a/gapis/resolve/report.go b/gapis/resolve/report.go index 70c96081df..091eae977b 100644 --- a/gapis/resolve/report.go +++ b/gapis/resolve/report.go @@ -60,16 +60,6 @@ func (r *ReportResolvable) Resolve(ctx context.Context) (interface{}, error) { defer analytics.SendTiming("resolve", "report")(analytics.Size(len(c.Commands))) - sd, err := SyncData(ctx, r.Path.Capture) - if err != nil { - return nil, err - } - - filter, err := buildFilter(ctx, r.Path.Capture, r.Path.Filter, sd, r.Config) - if err != nil { - return nil, err - } - builder := service.NewReportBuilder() var currentCmd uint64 @@ -134,19 +124,17 @@ func (r *ReportResolvable) Resolve(ctx context.Context) (interface{}, error) { } } - if filter(id, cmd, state) { - for _, item := range items { - item.Tags = append(item.Tags, getCommandNameTag(cmd)) - builder.Add(ctx, item) - } - for _, issue := range issues[id] { - item := r.newReportItem(log.Severity(issue.Severity), uint64(issue.Command), - messages.ErrReplayDriver(issue.Error.Error())) - if int(issue.Command) < len(c.Commands) { - item.Tags = append(item.Tags, getCommandNameTag(c.Commands[issue.Command])) - } - builder.Add(ctx, item) + for _, item := range items { + item.Tags = append(item.Tags, getCommandNameTag(cmd)) + builder.Add(ctx, item) + } + for _, issue := range issues[id] { + item := r.newReportItem(log.Severity(issue.Severity), uint64(issue.Command), + messages.ErrReplayDriver(issue.Error.Error())) + if int(issue.Command) < len(c.Commands) { + item.Tags = append(item.Tags, getCommandNameTag(c.Commands[issue.Command])) } + builder.Add(ctx, item) } return nil }) diff --git a/gapis/service/path/path.go b/gapis/service/path/path.go index f3549c1bc4..6047ec7b38 100644 --- a/gapis/service/path/path.go +++ b/gapis/service/path/path.go @@ -546,8 +546,8 @@ func (n *Capture) Resources() *Resources { } // Report returns the path node to the capture's report. -func (n *Capture) Report(d *Device, f *CommandFilter, display bool) *Report { - return &Report{Capture: n, Device: d, Filter: f, DisplayToSurface: display} +func (n *Capture) Report(d *Device, display bool) *Report { + return &Report{Capture: n, Device: d, DisplayToSurface: display} } // Messages returns the path node to the capture's messages. diff --git a/gapis/service/path/path.proto b/gapis/service/path/path.proto index e41dc8c1d9..456b601148 100644 --- a/gapis/service/path/path.proto +++ b/gapis/service/path/path.proto @@ -394,8 +394,6 @@ message Report { Capture capture = 1; // The optional path to the device used to generate replay information. Device device = 2; - // The optional filter to apply to the report items. - CommandFilter filter = 3; // Whether to display the replay to the original surface while in progress. bool display_to_surface = 4; } diff --git a/test/integration/service/service_test.go b/test/integration/service/service_test.go index 79dfb069df..2630c7c65e 100644 --- a/test/integration/service/service_test.go +++ b/test/integration/service/service_test.go @@ -201,7 +201,7 @@ func TestGet(t *testing.T) { {capture.Command(swapCmdIndex).MemoryAfter(0, 0x1000, 0x1000), T((*service.Memory)(nil))}, {capture.Command(drawCmdIndex).Mesh(nil), T((*api.Mesh)(nil))}, {capture.CommandTree(nil), T((*service.CommandTree)(nil))}, - {capture.Report(nil, nil, false), T((*service.Report)(nil))}, + {capture.Report(nil, false), T((*service.Report)(nil))}, {capture.Resources(), T((*service.Resources)(nil))}, } { ctx = log.V{"path": test.path}.Bind(ctx) From 57f0ff9d44748b3f9db9f44e78a5f7ada16ef8bf Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 18 Mar 2020 21:46:33 -0700 Subject: [PATCH 0174/1218] Use device capabilities to decide whether to add profiling layer Previously we had hardcoded this in a weird way based on the device name. We already know from the perfetto capabilities whether the device needs a layer to be loaded -- use that. --- gapis/api/vulkan/replay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/vulkan/replay.go b/gapis/api/vulkan/replay.go index 19bb91df21..4ca06b6855 100644 --- a/gapis/api/vulkan/replay.go +++ b/gapis/api/vulkan/replay.go @@ -1050,7 +1050,7 @@ func (a API) Replay( makeReadable.imagesOnly = true optimize = false transforms.Add(NewWaitForPerfetto(req.traceOptions, req.handler, req.buffer)) - if strings.Contains(device.GetConfiguration().GetHardware().GetGPU().GetName(), "Adreno") { + if device.GetConfiguration().GetPerfettoCapability().GetGpuProfiling().GetHasRenderStageProducerLayer() { transforms.Add(&profilingLayers{}) } transforms.Add(replay.NewMappingExporter(ctx, req.handleMappings)) From 7f34a1847011e3d7143e21e279f908b9ac9bc6cb Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 18 Mar 2020 13:56:21 -0700 Subject: [PATCH 0175/1218] Remove old dependency graph system This is not used by Vulkan. --- BUILD.bazel | 2 - gapis/resolve/dependencygraph/BUILD.bazel | 67 ----- .../dependencygraph/dead_code_elimination.go | 271 ------------------ .../dead_code_elimination_test.go | 93 ------ .../dependencygraph/dependency_graph.go | 218 -------------- gapis/resolve/dependencygraph/doc.go | 15 - .../resolve/dependencygraph/resolvables.proto | 25 -- 7 files changed, 691 deletions(-) delete mode 100644 gapis/resolve/dependencygraph/BUILD.bazel delete mode 100644 gapis/resolve/dependencygraph/dead_code_elimination.go delete mode 100644 gapis/resolve/dependencygraph/dead_code_elimination_test.go delete mode 100644 gapis/resolve/dependencygraph/dependency_graph.go delete mode 100644 gapis/resolve/dependencygraph/doc.go delete mode 100644 gapis/resolve/dependencygraph/resolvables.proto diff --git a/BUILD.bazel b/BUILD.bazel index 51e9e4ba32..2a58c3c57f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -323,7 +323,6 @@ test_suite( "//gapis/replay/builder:go_default_test", "//gapis/replay/scheduler:go_default_test", "//gapis/resolve:go_default_test", - "//gapis/resolve/dependencygraph:go_default_test", "//gapis/resolve/dependencygraph2:go_default_test", "//gapis/resolve/dependencygraph2/graph_visualization:go_default_test", ], @@ -441,7 +440,6 @@ test_suite( "//gapis/replay/builder:go_default_test", "//gapis/replay/scheduler:go_default_test", "//gapis/resolve:go_default_test", - "//gapis/resolve/dependencygraph:go_default_test", "//gapis/resolve/dependencygraph2:go_default_test", "//gapis/resolve/dependencygraph2/graph_visualization:go_default_test", "//gapis/service/box:go_default_test", diff --git a/gapis/resolve/dependencygraph/BUILD.bazel b/gapis/resolve/dependencygraph/BUILD.bazel deleted file mode 100644 index 7d9dc8c38c..0000000000 --- a/gapis/resolve/dependencygraph/BUILD.bazel +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "dead_code_elimination.go", - "dependency_graph.go", - "doc.go", - ], - embed = [":dependencygraph_go_proto"], - importpath = "github.com/google/gapid/gapis/resolve/dependencygraph", - visibility = ["//visibility:public"], - deps = [ - "//core/app/benchmark:go_default_library", - "//core/app/status:go_default_library", - "//core/log:go_default_library", - "//gapis/api:go_default_library", - "//gapis/api/transform:go_default_library", - "//gapis/capture:go_default_library", - "//gapis/config:go_default_library", - "//gapis/database:go_default_library", - "//gapis/resolve:go_default_library", - "//gapis/resolve/initialcmds:go_default_library", - "//gapis/service/path:go_default_library", - ], -) - -proto_library( - name = "dependencygraph_proto", - srcs = ["resolvables.proto"], - visibility = ["//visibility:public"], - deps = ["//gapis/service/path:path_proto"], -) - -go_proto_library( - name = "dependencygraph_go_proto", - importpath = "github.com/google/gapid/gapis/resolve/dependencygraph", - proto = ":dependencygraph_proto", - visibility = ["//visibility:public"], - deps = ["//gapis/service/path:go_default_library"], -) - -go_test( - name = "go_default_test", - srcs = ["dead_code_elimination_test.go"], - embed = [":go_default_library"], - deps = [ - "//core/assert:go_default_library", - "//core/log:go_default_library", - "//gapis/database:go_default_library", - ], -) diff --git a/gapis/resolve/dependencygraph/dead_code_elimination.go b/gapis/resolve/dependencygraph/dead_code_elimination.go deleted file mode 100644 index 9c908aff4f..0000000000 --- a/gapis/resolve/dependencygraph/dead_code_elimination.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dependencygraph - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/app/benchmark" - "github.com/google/gapid/core/app/status" - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/api/transform" - "github.com/google/gapid/gapis/config" -) - -const ( - // Logs all the commands that were dropped. - // Recommended to be used with a carefully considered `gapit screenshot`. - debugDCE = false -) - -var ( - deadCodeEliminationCounter = benchmark.Duration("deadCodeElimination") - deadCodeEliminationCmdDeadCounter = benchmark.Integer("deadCodeElimination.cmd.dead") - deadCodeEliminationCmdLiveCounter = benchmark.Integer("deadCodeElimination.cmd.live") - deadCodeEliminationDataDeadCounter = benchmark.Integer("deadCodeElimination.data.dead") - deadCodeEliminationDataLiveCounter = benchmark.Integer("deadCodeElimination.data.live") -) - -// DeadCodeElimination is an implementation of Transformer that outputs live -// commands. That is, all commands which do not affect the requested output are -// omitted. It is named after the standard compiler optimization. -// (state is like memory and commands are instructions which read/write it). -// Construct with NewDeadCodeElimination, do not build directly. -type DeadCodeElimination struct { - KeepAllAlive bool - depGraph *DependencyGraph - requests api.CmdIDSet - lastRequest api.CmdID -} - -// NewDeadCodeElimination constructs and returns a new DeadCodeElimination -// transform. -// -// The transform generates commands from the given depGraph, it does not take -// inputs. -func NewDeadCodeElimination(ctx context.Context, depGraph *DependencyGraph) *DeadCodeElimination { - return &DeadCodeElimination{ - depGraph: depGraph, - requests: make(api.CmdIDSet), - } -} - -// Request ensures that we keep alive all commands needed to render framebuffer -// at the given point. -func (t *DeadCodeElimination) Request(id api.CmdID) { - if id.IsReal() { - t.requests.Add(id) - if id > t.lastRequest { - t.lastRequest = id - } - } -} - -func (t *DeadCodeElimination) Transform(ctx context.Context, id api.CmdID, c api.Cmd, out transform.Writer) error { - panic(fmt.Errorf("This transform does not accept input commands")) -} - -func (t *DeadCodeElimination) PreLoop(ctx context.Context, out transform.Writer) {} -func (t *DeadCodeElimination) PostLoop(ctx context.Context, out transform.Writer) {} -func (t *DeadCodeElimination) BuffersCommands() bool { return false } - -func (t *DeadCodeElimination) Flush(ctx context.Context, out transform.Writer) error { - ctx = status.Start(ctx, "DCE Flush") - defer status.Finish(ctx) - - if t.KeepAllAlive { - err := api.ForeachCmd(ctx, t.depGraph.Commands, true, func(ctx context.Context, index api.CmdID, cmd api.Cmd) error { - return out.MutateAndWrite(ctx, t.depGraph.GetCmdID(int(index)), cmd) - }) - return err - } - t0 := deadCodeEliminationCounter.Start() - isLive := t.propagateLiveness(ctx) - deadCodeEliminationCounter.Stop(t0) - return api.ForeachCmd(ctx, t.depGraph.Commands[:len(isLive)], true, func(ctx context.Context, index api.CmdID, cmd api.Cmd) error { - id := t.depGraph.GetCmdID(int(index)) - if isLive[index] { - return out.MutateAndWrite(ctx, id, cmd) - } else if debugDCE { - log.I(ctx, "Dropped %v %v", id, cmd) - } - return nil - }) -} - -// See https://en.wikipedia.org/wiki/Live_variable_analysis -func (t *DeadCodeElimination) propagateLiveness(ctx context.Context) []bool { - isLive := make([]bool, t.depGraph.NumInitialCommands+int(t.lastRequest)+1) - state := NewLivenessTree(t.depGraph.GetHierarchyStateMap()) - for i := len(isLive) - 1; i >= 0; i-- { - b := t.depGraph.Behaviours[i] - isLive[i] = b.KeepAlive - // Always ignore commands that abort. - if b.Aborted { - continue - } - // If this is requested ID, mark all root state as live. - id := t.depGraph.GetCmdID(i) - if t.requests.Contains(id) { - isLive[i] = true - for root := range t.depGraph.Roots { - state.MarkLive(root) - } - } - // If any output state is live then this command is live as well. - for _, write := range b.Writes { - if state.IsLive(write) { - isLive[i] = true - // We just completely wrote the state, so we do not care about - // the earlier value of the state - it is dead. - state.MarkDead(write) // KILL - } - } - // Modification is just combined read and write - for _, modify := range b.Modifies { - if state.IsLive(modify) { - isLive[i] = true - // We will mark it as live since it is also a read, but we have - // to do it at the end so that all inputs are marked as live. - } - } - // Mark input state as live so that we get all dependencies. - if isLive[i] { - for _, modify := range b.Modifies { - state.MarkLive(modify) // GEN - } - for _, read := range b.Reads { - state.MarkLive(read) // GEN - } - } - // Debug output - if config.DebugDeadCodeElimination && t.requests.Contains(id) { - log.I(ctx, "DCE: Requested cmd %v: %v", id, t.depGraph.Commands[i]) - t.depGraph.Print(ctx, &b) - } - } - - { - // Collect and report statistics - num, numDead, numLive := len(isLive), 0, 0 - deadMem, liveMem := uint64(0), uint64(0) - for i := 0; i < num; i++ { - cmd := t.depGraph.Commands[i] - mem := uint64(0) - if e := cmd.Extras(); e != nil && e.Observations() != nil { - for _, r := range e.Observations().Reads { - mem += r.Range.Size - } - } - if !isLive[i] { - numDead++ - deadMem += mem - } else { - numLive++ - liveMem += mem - } - } - deadCodeEliminationCmdDeadCounter.Add(int64(numDead)) - deadCodeEliminationCmdLiveCounter.Add(int64(numLive)) - deadCodeEliminationDataDeadCounter.Add(int64(deadMem)) - deadCodeEliminationDataLiveCounter.Add(int64(liveMem)) - log.D(ctx, "DCE: dead: %v%% %v cmds %v MB, live: %v%% %v cmds %v MB", - 100*numDead/num, numDead, deadMem/1024/1024, - 100*numLive/num, numLive, liveMem/1024/1024) - } - return isLive -} - -// LivenessTree assigns boolean value to each state (live or dead). -// Think of each node as memory range, with children being sub-ranges. -type LivenessTree struct { - nodes []livenessNode // indexed by StateAddress - time int // current time used for time-stamps -} - -type livenessNode struct { - // Liveness value for this node. - live bool - // Optimization 1 - union of liveness of this node and all its descendants. - anyLive bool - // Optimization 2 - time of the last write to the 'live' field. - // This allows efficient update of all descendants. - // Children with lower time-stamp are effectively deleted. - timestamp int - // Link to the parent node, or nil if there is none. - parent *livenessNode -} - -// NewLivenessTree creates a new tree. -// The parent map defines parent for each node, -// and it must be continuous with no gaps. -func NewLivenessTree(parents map[StateAddress]StateAddress) LivenessTree { - nodes := make([]livenessNode, len(parents)) - for address, parent := range parents { - if parent != NullStateAddress { - nodes[address].parent = &nodes[parent] - } - } - return LivenessTree{nodes: nodes, time: 1} -} - -// IsLive returns true if the state, or any of its descendants, are live. -func (l *LivenessTree) IsLive(address StateAddress) bool { - node := &l.nodes[address] - live := node.anyLive // Check descendants as well. - for p := node.parent; p != nil; p = p.parent { - if p.timestamp > node.timestamp { - node = p - live = p.live // Ignore other descendants. - } - } - return live -} - -// MarkDead makes the given state, and all of its descendants, dead. -func (l *LivenessTree) MarkDead(address StateAddress) { - node := &l.nodes[address] - node.live = false - node.anyLive = false - node.timestamp = l.time - l.time++ -} - -// MarkLive makes the given state, and all of its descendants, live. -func (l *LivenessTree) MarkLive(address StateAddress) { - node := &l.nodes[address] - node.live = true - node.anyLive = true - node.timestamp = l.time - l.time++ - if p := node.parent; p != nil { - p.setAnyLive() - } -} - -// setAnyLive is helper to recursively set 'anyLive' flag on ancestors. -func (node *livenessNode) setAnyLive() { - if p := node.parent; p != nil { - p.setAnyLive() - if node.timestamp < p.timestamp { - // This node is effectively deleted so we need to create it. - node.live = p.live - node.timestamp = p.timestamp - } - } - node.anyLive = true -} diff --git a/gapis/resolve/dependencygraph/dead_code_elimination_test.go b/gapis/resolve/dependencygraph/dead_code_elimination_test.go deleted file mode 100644 index b33115a7ea..0000000000 --- a/gapis/resolve/dependencygraph/dead_code_elimination_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dependencygraph_test - -import ( - "testing" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/resolve/dependencygraph" -) - -func TestLivenessTree(t *testing.T) { - ctx := log.Testing(t) - ctx = database.Put(ctx, database.NewInMemory(ctx)) - - // - // root - // / \ - // child1 child2 - // / \ - // childA childB - // - root := dependencygraph.StateAddress(1) - child1 := dependencygraph.StateAddress(2) - child2 := dependencygraph.StateAddress(3) - childA := dependencygraph.StateAddress(4) - childB := dependencygraph.StateAddress(5) - tree := dependencygraph.NewLivenessTree(map[dependencygraph.StateAddress]dependencygraph.StateAddress{ - dependencygraph.NullStateAddress: dependencygraph.NullStateAddress, - root: dependencygraph.NullStateAddress, - child1: root, - child2: root, - childA: child1, - childB: child1, - }) - - tree.MarkLive(child1) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(true) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(true) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(false) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(true) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(true) - - tree.MarkDead(root) - tree.MarkLive(child1) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(true) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(true) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(false) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(true) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(true) - - tree.MarkLive(root) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(true) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(true) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(true) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(true) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(true) - - tree.MarkDead(child1) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(true) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(false) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(true) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(false) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(false) - - tree.MarkDead(root) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(false) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(false) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(false) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(false) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(false) - - tree.MarkLive(childA) - assert.For(ctx, "IsLive(root)").That(tree.IsLive(root)).Equals(true) - assert.For(ctx, "IsLive(child1)").That(tree.IsLive(child1)).Equals(true) - assert.For(ctx, "IsLive(child2)").That(tree.IsLive(child2)).Equals(false) - assert.For(ctx, "IsLive(childA)").That(tree.IsLive(childA)).Equals(true) - assert.For(ctx, "IsLive(childB)").That(tree.IsLive(childB)).Equals(false) -} diff --git a/gapis/resolve/dependencygraph/dependency_graph.go b/gapis/resolve/dependencygraph/dependency_graph.go deleted file mode 100644 index e7f7cd2307..0000000000 --- a/gapis/resolve/dependencygraph/dependency_graph.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dependencygraph - -import ( - "context" - "fmt" - - "github.com/google/gapid/core/app/benchmark" - "github.com/google/gapid/core/log" - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/resolve" - "github.com/google/gapid/gapis/resolve/initialcmds" - "github.com/google/gapid/gapis/service/path" - - // The following are the imports that generated source files pull in when present - // Having these here helps out tools that can't cope with missing dependancies - - _ "github.com/google/gapid/gapis/service/path" -) - -var dependencyGraphBuildCounter = benchmark.Duration("dependencyGraph.build") - -type DependencyGraph struct { - // Number of generated commands in 'Commands' which build the initial state. - NumInitialCommands int - - Commands []api.Cmd // Command list which this graph was build for. - Behaviours []CmdBehaviour // State reads/writes for each command (graph edges). - Roots map[StateAddress]bool // State to mark live at requested commands. - addressMap addressMapping // Remap state keys to integers for performance. -} - -// GetCmdID returns the CmdID for given element in the Commands slice. -func (g *DependencyGraph) GetCmdID(cmdIndex int) api.CmdID { - if cmdIndex < g.NumInitialCommands { - return api.CmdID(0).Derived() - } - return api.CmdID(cmdIndex - g.NumInitialCommands) -} - -func (g *DependencyGraph) GetStateAddressOf(key StateKey) StateAddress { - return g.addressMap.addressOf(key) -} - -func (g *DependencyGraph) GetHierarchyStateMap() map[StateAddress]StateAddress { - return g.addressMap.parent -} - -func (g *DependencyGraph) SetRoot(key StateKey) { - g.Roots[g.GetStateAddressOf(key)] = true -} - -func (g *DependencyGraph) Print(ctx context.Context, b *CmdBehaviour) { - for _, read := range b.Reads { - key := g.addressMap.key[read] - log.I(ctx, " - read [%v]%T%+v", read, key, key) - } - for _, modify := range b.Modifies { - key := g.addressMap.key[modify] - log.I(ctx, " - modify [%v]%T%+v", modify, key, key) - } - for _, write := range b.Writes { - key := g.addressMap.key[write] - log.I(ctx, " - write [%v]%T%+v", write, key, key) - } - if b.Aborted { - log.I(ctx, " - aborted") - } -} - -type StateAddress uint32 - -const NullStateAddress = StateAddress(0) - -// StateKey uniquely represents part of the GL state. -// Think of it as memory range (which stores the state data). -type StateKey interface { - // Parent returns enclosing state (and this state is strict subset of it). - // This allows efficient implementation of operations which access a lot state. - Parent() StateKey -} - -type CmdBehaviour struct { - Reads []StateAddress // States read by a command. - Modifies []StateAddress // States read and written by a command. - Writes []StateAddress // States written by a command. - Roots []StateAddress // States labeled as root by a command. - KeepAlive bool // Force the command to be live. - Aborted bool // Mutation of this command aborts. -} - -type addressMapping struct { - address map[StateKey]StateAddress - key map[StateAddress]StateKey - parent map[StateAddress]StateAddress -} - -func (m *addressMapping) addressOf(state StateKey) StateAddress { - if a, ok := m.address[state]; ok { - return a - } - address := StateAddress(len(m.address)) - m.address[state] = address - m.key[address] = state - m.parent[address] = m.addressOf(state.Parent()) - return address -} - -func (b *CmdBehaviour) Read(g *DependencyGraph, state StateKey) { - if state != nil { - b.Reads = append(b.Reads, g.addressMap.addressOf(state)) - } -} - -func (b *CmdBehaviour) Modify(g *DependencyGraph, state StateKey) { - if state != nil { - b.Modifies = append(b.Modifies, g.addressMap.addressOf(state)) - } -} - -func (b *CmdBehaviour) Write(g *DependencyGraph, state StateKey) { - if state != nil { - b.Writes = append(b.Writes, g.addressMap.addressOf(state)) - } -} - -type DependencyGraphBehaviourProvider interface { - GetDependencyGraphBehaviourProvider(ctx context.Context) BehaviourProvider -} - -type BehaviourProvider interface { - GetBehaviourForCommand(context.Context, *api.GlobalState, api.CmdID, api.Cmd, *DependencyGraph) CmdBehaviour -} - -func GetDependencyGraph(ctx context.Context, device *path.Device) (*DependencyGraph, error) { - r, err := database.Build(ctx, &DependencyGraphResolvable{ - Capture: capture.Get(ctx), - Config: &path.ResolveConfig{ReplayDevice: device}, - }) - if err != nil { - return nil, fmt.Errorf("Could not calculate dependency graph: %v", err) - } - return r.(*DependencyGraph), nil -} - -func (r *DependencyGraphResolvable) Resolve(ctx context.Context) (interface{}, error) { - ctx = resolve.SetupContext(ctx, r.Capture, r.Config) - - c, err := capture.ResolveGraphics(ctx) - if err != nil { - return nil, err - } - cmds := c.Commands - behaviourProviders := map[api.API]BehaviourProvider{} - - initCmds, ranges, err := initialcmds.InitialCommands(ctx, r.Capture) - - if len(initCmds) > 0 { - cmds = append(initCmds, cmds...) - } - - g := &DependencyGraph{ - NumInitialCommands: len(initCmds), - Commands: cmds, - Behaviours: make([]CmdBehaviour, len(cmds)), - Roots: map[StateAddress]bool{}, - addressMap: addressMapping{ - address: map[StateKey]StateAddress{nil: NullStateAddress}, - key: map[StateAddress]StateKey{NullStateAddress: nil}, - parent: map[StateAddress]StateAddress{NullStateAddress: NullStateAddress}, - }, - } - - s := c.NewUninitializedState(ctx).ReserveMemory(ranges) - - dependencyGraphBuildCounter.Time(func() { - api.ForeachCmd(ctx, cmds, true, func(ctx context.Context, index api.CmdID, cmd api.Cmd) error { - a := cmd.API() - id := g.GetCmdID(int(index)) - if _, ok := behaviourProviders[a]; !ok { - if bp, ok := a.(DependencyGraphBehaviourProvider); ok { - behaviourProviders[a] = bp.GetDependencyGraphBehaviourProvider(ctx) - } else { - // API does not provide dependency information, always keep - // commands for such APIs. - g.Behaviours[index].KeepAlive = true - // Even if the command does not belong to an API that provides - // dependency info, we still need to mutate it in the new state, - // because following commands in other APIs may depends on the - // side effect of the current command. - if err := cmd.Mutate(ctx, id, s, nil /* builder */, nil /* watcher */); err != nil { - log.W(ctx, "Command %v %v: %v", id, cmd, err) - g.Behaviours[index].Aborted = true - } - return nil - } - } - g.Behaviours[index] = behaviourProviders[a].GetBehaviourForCommand(ctx, s, id, cmd, g) - return nil - }) - }) - return g, nil -} diff --git a/gapis/resolve/dependencygraph/doc.go b/gapis/resolve/dependencygraph/doc.go deleted file mode 100644 index 646198a288..0000000000 --- a/gapis/resolve/dependencygraph/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dependencygraph diff --git a/gapis/resolve/dependencygraph/resolvables.proto b/gapis/resolve/dependencygraph/resolvables.proto deleted file mode 100644 index bef65c5abf..0000000000 --- a/gapis/resolve/dependencygraph/resolvables.proto +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package dependencygraph; -option go_package = "github.com/google/gapid/gapis/resolve/dependencygraph"; - -import "gapis/service/path/path.proto"; - -message DependencyGraphResolvable { - path.Capture capture = 1; - path.ResolveConfig config = 2; -} From 2bb71a832543616d2666acc54e1fec97b3809db7 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 18 Mar 2020 18:17:21 -0700 Subject: [PATCH 0176/1218] Remove libinterceptor remnants --- gapidapk/gapidapk.go | 10 -------- gapii/cc/connection_header.cpp | 10 ++++---- gapii/cc/connection_header.h | 4 ---- gapii/client/adb.go | 5 ++-- gapii/client/capture.go | 6 ++--- gapii/client/header.go | 14 +++--------- tools/build/BUILD.bazel | 8 ------- tools/build/third_party/libinterceptor.BUILD | 24 -------------------- 8 files changed, 12 insertions(+), 69 deletions(-) delete mode 100644 tools/build/third_party/libinterceptor.BUILD diff --git a/gapidapk/gapidapk.go b/gapidapk/gapidapk.go index 69736990bb..b097ea896f 100644 --- a/gapidapk/gapidapk.go +++ b/gapidapk/gapidapk.go @@ -179,20 +179,10 @@ func (a APK) LibGAPIIPath(abi *device.ABI) string { return a.LibsPath(abi) + "/" + LibGAPIIName } -// LibInterceptorPath returns the path on the Android device to the -// interceptor dynamic library file. -// gapid.apk must be installed for this path to be valid. -func (a APK) LibInterceptorPath(abi *device.ABI) string { - return a.LibsPath(abi) + "/" + LibInterceptorName -} - const ( // LibGAPIIName is the name of the GAPII dynamic library file. LibGAPIIName = "libgapii.so" - // LibInterceptorName is the name of the interceptor dynamic library file. - LibInterceptorName = "libinterceptor.so" - // GraphicsSpyLayerName is the name of the graphics spy layer. GraphicsSpyLayerName = "GraphicsSpy" ) diff --git a/gapii/cc/connection_header.cpp b/gapii/cc/connection_header.cpp index 856f66c688..9a008c3897 100644 --- a/gapii/cc/connection_header.cpp +++ b/gapii/cc/connection_header.cpp @@ -28,8 +28,7 @@ ConnectionHeader::ConnectionHeader() mStartFrame(0), mNumFrames(0), mAPIs(0xFFFFFFFF), - mFlags(0), - mGvrHandle(0) {} + mFlags(0) {} bool ConnectionHeader::read(core::StreamReader* reader) { if (!reader->read(mMagic)) { @@ -48,8 +47,8 @@ bool ConnectionHeader::read(core::StreamReader* reader) { return false; } - const int kMinSupportedVersion = 2; - const int kMaxSupportedVersion = 2; + const int kMinSupportedVersion = 3; + const int kMaxSupportedVersion = 3; if (mVersion < kMinSupportedVersion || mVersion > kMaxSupportedVersion) { GAPID_WARNING( @@ -60,8 +59,7 @@ bool ConnectionHeader::read(core::StreamReader* reader) { if (!reader->read(mObserveFrameFrequency) || !reader->read(mObserveDrawFrequency) || !reader->read(mStartFrame) || !reader->read(mNumFrames) || !reader->read(mAPIs) || - !reader->read(mFlags) || !reader->read(mGvrHandle) || - !reader->read(mLibInterceptorPath)) { + !reader->read(mFlags)) { return false; } diff --git a/gapii/cc/connection_header.h b/gapii/cc/connection_header.h index 87aab76ffa..de611323a2 100644 --- a/gapii/cc/connection_header.h +++ b/gapii/cc/connection_header.h @@ -69,8 +69,6 @@ class ConnectionHeader { mNumFrames = 0; mAPIs = 0; mFlags = 0; - mGvrHandle = 0; - mLibInterceptorPath[0] = '\0'; } uint8_t mMagic[4]; // 's', 'p', 'y', '0' @@ -81,8 +79,6 @@ class ConnectionHeader { uint32_t mNumFrames; // non-zero == Number of frames to capture. uint32_t mAPIs; // Bitset of APIS to enable. uint32_t mFlags; // Combination of FLAG_XX bits. - uint64_t mGvrHandle; // Handle of GVR library. - char mLibInterceptorPath[MAX_PATH]; // Path of libinterceptor.so. }; } // namespace gapii diff --git a/gapii/client/adb.go b/gapii/client/adb.go index 0e8d56df37..a0c4459cbb 100644 --- a/gapii/client/adb.go +++ b/gapii/client/adb.go @@ -184,7 +184,7 @@ func Connect(ctx context.Context, d adb.Device, abi *device.ABI, pipe string, o ctx = log.V{"port": port}.Bind(ctx) log.I(ctx, "Checking gapid.apk is installed") - apk, err := gapidapk.EnsureInstalled(ctx, d, abi) + _, err = gapidapk.EnsureInstalled(ctx, d, abi) if err != nil { return nil, log.Err(ctx, err, "Installing gapid.apk") } @@ -199,8 +199,7 @@ func Connect(ctx context.Context, d adb.Device, abi *device.ABI, pipe string, o Device: d, Options: o, } - interceptorPath := apk.LibInterceptorPath(abi) - if err := process.connect(ctx, 0, interceptorPath); err != nil { + if err := process.connect(ctx); err != nil { return nil, err } return process, nil diff --git a/gapii/client/capture.go b/gapii/client/capture.go index 388dcbfca7..5b569042ba 100644 --- a/gapii/client/capture.go +++ b/gapii/client/capture.go @@ -105,7 +105,7 @@ func (s siSize) String() string { return fmt.Sprintf(f, v) } -func (p *Process) connect(ctx context.Context, gvrHandle uint64, interceptorPath string) error { +func (p *Process) connect(ctx context.Context) error { log.I(ctx, "Waiting for connection to localhost:%d...", p.Port) // ADB has an annoying tendancy to insta-close forwarded sockets when @@ -127,7 +127,7 @@ func (p *Process) connect(ctx context.Context, gvrHandle uint64, interceptorPath conn.Close() return true, log.Errf(ctx, nil, "Got unexpected magic: %v", magic) } - if err := sendHeader(conn, p.Options, gvrHandle, interceptorPath); err != nil { + if err := sendHeader(conn, p.Options); err != nil { conn.Close() return true, log.Err(ctx, err, "Failed to send header") } @@ -185,7 +185,7 @@ func (p *Process) Capture(ctx context.Context, start task.Signal, stop task.Sign }() if p.conn == nil { - if err := p.connect(ctx, 0, ""); err != nil { + if err := p.connect(ctx); err != nil { return 0, err } } diff --git a/gapii/client/header.go b/gapii/client/header.go index d28228f039..bfa1f8ce44 100644 --- a/gapii/client/header.go +++ b/gapii/client/header.go @@ -23,30 +23,26 @@ import ( var magic = [4]byte{'s', 'p', 'y', '0'} -const version = 2 +const version = 3 // The GAPII header is defined as: // -// const size_t MAX_PATH = 512; -// // struct ConnectionHeader { // uint8_t mMagic[4]; // 's', 'p', 'y', '0' -// uint32_t mVersion; // 2 +// uint32_t mVersion; // 3 // uint32_t mObserveFrameFrequency; // non-zero == enabled. // uint32_t mObserveDrawFrequency; // non-zero == enabled. // uint32_t mStartFrame; // non-zero == Frame to start at. // uint32_t mNumFrames; // non-zero == Number of frames to capture. // uint32_t mAPIs; // Bitset of APIS to enable. // uint32_t mFlags; // Combination of FLAG_XX bits. -// char mLibInterceptorPath[MAX_PATH]; // Path to libinterceptor.so // }; // // All fields are encoded little-endian with no compression, regardless of // architecture. All changes must be kept in sync with: // platform/tools/gpu/gapii/cc/connection_header.h -func sendHeader(out io.Writer, options Options, gvrHandle uint64, libInterceptorPath string) error { - const maxPath = 512 +func sendHeader(out io.Writer, options Options) error { w := endian.Writer(out, device.LittleEndian) for _, m := range magic { w.Uint8(m) @@ -58,9 +54,5 @@ func sendHeader(out io.Writer, options Options, gvrHandle uint64, libInterceptor w.Uint32(options.FramesToCapture) w.Uint32(options.APIs) w.Uint32(uint32(options.Flags)) - w.Uint64(gvrHandle) - var path [maxPath]byte - copy(path[:], libInterceptorPath) - w.Data(path[:]) return w.Error() } diff --git a/tools/build/BUILD.bazel b/tools/build/BUILD.bazel index 61a8fc2ade..197c9eefef 100644 --- a/tools/build/BUILD.bazel +++ b/tools/build/BUILD.bazel @@ -101,14 +101,6 @@ config_setting( }, ) -config_setting( - name = "libinterceptor-from-source", - define_values = { - "LIBINTERCEPTOR_FROM_SOURCE": "1", - }, - visibility = ["//visibility:public"], -) - cc_library( name = "jni", hdrs = [ diff --git a/tools/build/third_party/libinterceptor.BUILD b/tools/build/third_party/libinterceptor.BUILD deleted file mode 100644 index f059ed70e9..0000000000 --- a/tools/build/third_party/libinterceptor.BUILD +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2019 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cc_library( - name = "libinterceptor", - srcs = select({ - "@gapid//tools/build:android-armeabi-v7a": ["armeabi-v7a/libinterceptor.so"], - "@gapid//tools/build:android-arm64-v8a": ["arm64-v8a/libinterceptor.so"], - "@gapid//tools/build:android-x86": ["x86/libinterceptor.so"], - }), - linkstatic = 1, - visibility = ["//visibility:public"], -) From bf64bc736b894d55169e0facd6138b9cac5e4ac4 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Fri, 20 Mar 2020 14:32:27 -0700 Subject: [PATCH 0177/1218] Don't make reports if loading pipelines throws DataUnavailableException (#161) Bug: b/151844064 --- gapic/src/main/com/google/gapid/views/PipelineView.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index c92cc85e03..5143c43c1b 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -46,6 +46,7 @@ import com.google.gapid.rpc.Rpc; import com.google.gapid.rpc.RpcException; import com.google.gapid.rpc.UiErrorCallback; +import com.google.gapid.server.Client.DataUnavailableException; import com.google.gapid.util.Loadable; import com.google.gapid.util.Messages; import com.google.gapid.widgets.LoadablePanel; @@ -184,6 +185,8 @@ protected ResultOrError, Loadable.Message> onRpcThread( } } return success(pipelines); + } catch (DataUnavailableException e) { + return error(Loadable.Message.error(e)); } catch (RpcException e) { models.analytics.reportException(e); return error(Loadable.Message.error(e)); From 886aa63605d85f1bf4dd0cdd8217b1a1a659d5d7 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 18 Mar 2020 16:07:25 -0700 Subject: [PATCH 0178/1218] Explicetly check Select.Default for nil in the template. Newer versions of the templating engine appear to treat this differently. We have "{{if $.Default}}" meaning "if there is a default", but apparently, "default: as!uint32(0)" creates an expression that makes the condition false. Changing it to "default: as!uint32(5)" would cause it to be true, but "0" somehow makes it false. Most likely the implementation does "if {arg} is not a zero object", and the struct created by our parsers happens to look like a zero object. --- gapis/api/templates/go_common.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/templates/go_common.tmpl b/gapis/api/templates/go_common.tmpl index c256c699a5..66586d61b6 100644 --- a/gapis/api/templates/go_common.tmpl +++ b/gapis/api/templates/go_common.tmpl @@ -784,7 +784,7 @@ return {{Template "Go.Read" $c.Expression}} {{end}} default: - {{if $.Default}} + {{if not (IsNil $.Default)}} return {{Template "Go.Read" $.Default}} {{else}} // TODO: better unmatched handling From adb3213aa8fb1d6dbfa27a352f82b3dac8df34ac Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 15:04:54 -0700 Subject: [PATCH 0179/1218] Remove the now unused GLES->GL shader conversion code. --- cmd/shadertool/BUILD.bazel | 33 - cmd/shadertool/main.go | 114 -- gapis/shadertools/cc/README.md | 58 - gapis/shadertools/cc/common.cpp | 79 -- gapis/shadertools/cc/common.h | 29 - gapis/shadertools/cc/libmanager.cpp | 131 +- gapis/shadertools/cc/libmanager.h | 33 - gapis/shadertools/cc/name_manager.cpp | 116 -- gapis/shadertools/cc/name_manager.h | 62 - gapis/shadertools/cc/spirv2glsl.cpp | 37 - gapis/shadertools/cc/spirv2glsl.h | 21 - gapis/shadertools/cc/spv_manager.cpp | 1051 ----------------- gapis/shadertools/cc/spv_manager.h | 195 --- ...ce24c54214efa0dc896734b22dd1dbaac80b9.frag | 62 - ...54214efa0dc896734b22dd1dbaac80b9.frag.out3 | 199 ---- ...d3b78fd079ef9351eaaa548e4ef8aab00191f.frag | 53 - ...fd079ef9351eaaa548e4ef8aab00191f.frag.out3 | 158 --- ...99553c708364771961a1f61d5dd59c40.vert.out3 | 204 ---- ...b6e0642a25204a333b495d2bc9fd20014f8a6.vert | 30 - ...42a25204a333b495d2bc9fd20014f8a6.vert.out3 | 99 -- ...b18c3bc5d39d4a6b353f00112bf820ec66f2e.frag | 239 ---- ...bc5d39d4a6b353f00112bf820ec66f2e.frag.out3 | 109 -- ...060f1baa60016a23927c97c8a29d9478458c2.frag | 43 - ...baa60016a23927c97c8a29d9478458c2.frag.out3 | 132 --- ...0be7dea7d9bcdef8ea7cedda537700125020e.vert | 164 --- ...ea7d9bcdef8ea7cedda537700125020e.vert.out3 | 140 --- ...7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert | 72 -- ...e6c5c0016c5a1c1d94f2f26df319a113.vert.out3 | 229 ---- ...1db668374bd88249acd0600179fb0ce42c93d.vert | 53 - ...8374bd88249acd0600179fb0ce42c93d.vert.out3 | 143 --- gapis/shadertools/shadertools.go | 151 --- gapis/shadertools/shadertools_test.go | 67 -- 32 files changed, 1 insertion(+), 4305 deletions(-) delete mode 100644 cmd/shadertool/BUILD.bazel delete mode 100644 cmd/shadertool/main.go delete mode 100644 gapis/shadertools/cc/README.md delete mode 100644 gapis/shadertools/cc/common.cpp delete mode 100644 gapis/shadertools/cc/common.h delete mode 100644 gapis/shadertools/cc/name_manager.cpp delete mode 100644 gapis/shadertools/cc/name_manager.h delete mode 100644 gapis/shadertools/cc/spirv2glsl.cpp delete mode 100644 gapis/shadertools/cc/spirv2glsl.h delete mode 100644 gapis/shadertools/cc/spv_manager.cpp delete mode 100644 gapis/shadertools/cc/spv_manager.h delete mode 100644 gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag delete mode 100644 gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag delete mode 100644 gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/31970cd999553c708364771961a1f61d5dd59c40.vert.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert delete mode 100644 gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag delete mode 100644 gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag delete mode 100644 gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert delete mode 100644 gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert delete mode 100644 gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert.out3 delete mode 100644 gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert delete mode 100644 gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert.out3 diff --git a/cmd/shadertool/BUILD.bazel b/cmd/shadertool/BUILD.bazel deleted file mode 100644 index 7630bb11cd..0000000000 --- a/cmd/shadertool/BUILD.bazel +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = ["main.go"], - importpath = "github.com/google/gapid/cmd/shadertool", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//core/app/crash:go_default_library", - "//gapis/shadertools:go_default_library", - ], -) - -go_binary( - name = "shadertool", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/cmd/shadertool/main.go b/cmd/shadertool/main.go deleted file mode 100644 index f7f91b1be6..0000000000 --- a/cmd/shadertool/main.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The shadertool command modifies shader source code. -// For example, it converts GLSL to the desktop dialect. -package main - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "path/filepath" - "sync" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/gapis/shadertools" -) - -var ( - out = flag.String("out", "", "Directory for the converted shaders") - check = flag.Bool("check", true, "Verify that the output compiles") - debug = flag.Bool("debug", false, "Make the shader debuggable") - asm = flag.Bool("asm", false, "Print disassembled info") -) - -func main() { - app.Name = "shadertool" - app.ShortHelp = "Converts GLSL ES shader to the desktop GLSL dialect" - app.ShortUsage = "" - app.Run(run) -} - -func run(ctx context.Context) error { - args := flag.Args() - if len(args) == 0 { - flag.Usage() - return nil - } - - // Read input - var wg sync.WaitGroup - for _, input := range args { - input := input - source, err := ioutil.ReadFile(input) - if err != nil { - return err - } - - wg.Add(1) - crash.Go(func() { - defer wg.Done() - - // Process the shader - result, err := convert(string(source), filepath.Ext(input)) - if err != nil { - fmt.Printf("%v: %v\n", input, err) - return - } - - // Write output - if *out == "" { - fmt.Print(result) - } else { - output := filepath.Join(*out, filepath.Base(input)) - err := ioutil.WriteFile(output, []byte(result), 0666) - if err != nil { - fmt.Printf("%v: %v\n", input, err) - return - } - } - }) - } - wg.Wait() - - return nil -} - -func convert(source, shaderType string) (result string, err error) { - opts := shadertools.ConvertOptions{} - switch shaderType { - case ".vert": - opts.ShaderType = shadertools.TypeVertex - case ".frag": - opts.ShaderType = shadertools.TypeFragment - default: - return "", fmt.Errorf("File extension must be .vert or .frag (seen %v)", shaderType) - } - opts.MakeDebuggable = *debug - opts.CheckAfterChanges = *check - opts.Disassemble = *asm - res, err := shadertools.ConvertGlsl(string(source), &opts) - if err != nil { - return "", err - } - if *asm { - result += "/* Disassembly:\n" + res.DisassemblyString + "\n*/\n" - result += "/* Debug info:\n" + shadertools.FormatDebugInfo(res.Info, " ") + "\n*/\n" - } - result += res.SourceCode - return result, nil -} diff --git a/gapis/shadertools/cc/README.md b/gapis/shadertools/cc/README.md deleted file mode 100644 index 841cf82cff..0000000000 --- a/gapis/shadertools/cc/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Shadertools, libmanager - -/** - * Karolina Gawryszczak - * 18.10.2016 - **/ - -Library libmanager provides 2 function: - -``` - -> code_with_debug_info_t* convertGlsl(const char*, size_t, options_t*); - 1. compiles GLSL source code in ES version to spirv code (using glslang tool) - 2. makes some changes in compiled spirv code (using my class SpvManager; those changes depend on provided options). - 3. decompile changed spirv code to source code in desktop version (using spirv-cross tool) - 4. again, compiles source code in desktop version (again, using glslang tool) - - -> void deleteGlslCodeWithDebug(code_with_debug_info_t*); -``` - -Options: - -``` - typedef struct options_t { - bool is_fragment_shader; - bool is_vertex_shader; - bool prefix_names; - /* Remaps all user declaration names to avoid names collisions between different GLSL versions - with default prefix or 'name_prefix' if given. */ - const char* names_prefix; /* optional */ - bool add_outputs_for_inputs; - /* Creates outputs for inputs with default or given 'output_prefix'. */ - const char* output_prefix; /* optional */ - bool make_debuggable; - /* Inserts variables prints. */ - bool check_after_changes; - /* Check if changed source code compiles, using glslang. */ - bool disassemble; - /* Return disassemble code after all changes. */ - } options_t; -``` - - -Usage: - -Simple library usage is shown in main.cpp program. - -``` -./main ` -``` - -Tests: - -- script tests/run_tests.py - - script takes one argument 'step', which is a number. - Variable 'width' means how many files you want to test. - Files from (step * width) to ((step + 1) * width) will be tested. - - Creates output files in test/shaders/ directory. - Output file name: .out3 diff --git a/gapis/shadertools/cc/common.cpp b/gapis/shadertools/cc/common.cpp deleted file mode 100644 index 587825cccf..0000000000 --- a/gapis/shadertools/cc/common.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "common.h" -#include - -std::vector makeVector(uint32_t word) { - std::vector result = {word}; - return result; -} - -std::vector makeVector(std::initializer_list list) { - std::vector result(list); - return result; -} - -std::vector makeVector(const char* str) { - assert(str != nullptr && "makeVector: making vector from null pointer."); - uint32_t word; - std::vector result; - char* word_string = (char*)&word; - char* word_ptr = word_string; - int char_count = 0; - char c; - - if (str != nullptr) { - do { - c = *(str++); - *(word_ptr++) = c; - ++char_count; - if (char_count == 4) { - result.push_back(word); - word_ptr = word_string; - char_count = 0; - } - } while (c != 0); - - // deal with partial last word - if (char_count > 0) { - // pad with 0s - for (; char_count < 4; ++char_count) *(word_ptr++) = 0; - result.push_back(word); - } - } - return result; -} - -/** - * Return string represented by given binary. - **/ -std::string extractString(const std::vector& words) { - std::string ret; - for (uint32_t i = 0; i < words.size(); i++) { - uint32_t w = words[i]; - - for (uint32_t j = 0; j < 4; j++, w >>= 8) { - char c = w & 0xff; - if (c == '\0') return ret; - ret += c; - } - } - assert(false && - "extractString: expected the vector to represent a null-terminated " - "string"); - return ret; -} diff --git a/gapis/shadertools/cc/common.h b/gapis/shadertools/cc/common.h deleted file mode 100644 index 162aff65d6..0000000000 --- a/gapis/shadertools/cc/common.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COMMON_MANAGER_H_ -#define COMMON_MANAGER_H_ - -#include -#include -#include - -std::vector makeVector(uint32_t); -std::vector makeVector(std::initializer_list); -std::vector makeVector(const char*); -std::string extractString(const std::vector&); - -#endif // COMMON_MANAGER_H_ \ No newline at end of file diff --git a/gapis/shadertools/cc/libmanager.cpp b/gapis/shadertools/cc/libmanager.cpp index 3301bbaff2..7e4775f1ad 100644 --- a/gapis/shadertools/cc/libmanager.cpp +++ b/gapis/shadertools/cc/libmanager.cpp @@ -14,13 +14,10 @@ * limitations under the License. */ +#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp" #include "third_party/glslang/SPIRV/GlslangToSpv.h" -#include "third_party/glslang/SPIRV/disassemble.h" -#include "third_party/glslang/glslang/Public/ShaderLang.h" #include "libmanager.h" -#include "spirv2glsl.h" -#include "spv_manager.h" #include #include @@ -125,12 +122,6 @@ const TBuiltInResource DefaultTBuiltInResource = { /* .generalConstantMatrixVectorIndexing = */ 1, }}; -void set_error_msg(code_with_debug_info_t* x, std::string msg) { - x->ok = false; - x->message = new char[msg.length() + 1]; - strcpy(x->message, msg.c_str()); -} - std::vector parseGlslang(const char* code, const char* preamble, std::string* err_msg, shader_type shader_ty, @@ -259,122 +250,6 @@ std::vector parseGlslang(const char* code, const char* preamble, return spirv; } -/** - * Only Vertex and Fragment shaders are supported. - * 1. Compiles source code to spirv using glslang, - * 2. Changes spirv code to insert debug information using SpvManager, - * 3. Decompiles changed spirv to source code using spirv-cross, - * 4. Check, if changed source code correctly compiles. - **/ -code_with_debug_info_t* convertGlsl(const char* input, size_t length, - const convert_options_t* options) { - code_with_debug_info_t* result = new code_with_debug_info_t{}; - std::string err_msg; - - std::vector spirv = - parseGlslang(input, options->preamble, &err_msg, options->shader_type, - OPENGLES, options->relaxed); - - if (!err_msg.empty()) { - set_error_msg(result, "Failed to parse original source code:\n" + err_msg); - return result; - } - - // makes changes - spvmanager::SpvManager my_manager(spirv); - if (options->prefix_names) { - if (options->names_prefix) { - my_manager.mapDeclarationNames(options->names_prefix); - } else { - my_manager.mapDeclarationNames(); - } - } - if (options->add_outputs_for_inputs) { - if (options->output_prefix) { - my_manager.addOutputForInputs(options->output_prefix); - } else { - my_manager.addOutputForInputs(); - } - } - if (options->make_debuggable) { - my_manager.makeSpvDebuggable(); - } - my_manager.renameViewIndex(); - my_manager.removeLayoutLocations(); - my_manager.initLocals(); - - std::vector spirv_new = my_manager.getSpvBinary(); - - if (spirv_new.empty()) { - set_error_msg(result, "SpvManager did not produce any code."); - return result; - } - - if (options->disassemble) { - std::stringstream disassembly_stream; - spv::Disassemble(disassembly_stream, spirv_new); - const std::string& tmp = disassembly_stream.str(); - result->disassembly_string = new char[tmp.length() + 1]; - strcpy(result->disassembly_string, tmp.c_str()); - } - // Sometimes SPIR-V cross throws exceptions. \o/ - // This is a big hammer, but should handle all of the cases - try { - std::string source = - spirv2glsl(std::move(spirv_new), options->target_glsl_version, - options->strip_optimizations); - - result->source_code = new char[source.length() + 1]; - strcpy(result->source_code, source.c_str()); - result->source_code[source.length()] = '\0'; - - // check if changed source code compiles again - if (options->check_after_changes) { - parseGlslang(result->source_code, nullptr, &err_msg, options->shader_type, - OPENGL, false); - } - - if (!err_msg.empty()) { - set_error_msg(result, - "Failed to parse modified source code:\n" + err_msg); - return result; - } - } catch (const std::runtime_error& e) { - set_error_msg(result, std::string("Exception thrown from spirv-cross: \n") + - e.what()); - return result; - } catch (...) { - set_error_msg(result, "Unknown thrown from spirv-cross\n"); - return result; - } - - result->info = my_manager.getDebugInstructions(); - result->ok = true; - - return result; -} - -/** - * Releses memory allocated by SpvManager. - * May needs update after changes. - **/ -void deleteGlslCodeWithDebug(code_with_debug_info_t* debug) { - delete debug->message; - delete[] debug->source_code; - delete[] debug->disassembly_string; - - if (debug->info) { - for (uint32_t i = 0; i < debug->info->insts_num; i++) { - delete[] debug->info->insts[i].words; - delete[] debug->info->insts[i].name; - } - delete[] debug->info->insts; - delete debug->info; - } - - delete debug; -} - /** * Returns pointer to disassemble text. **/ @@ -431,10 +306,6 @@ void deleteBinary(spirv_binary_t* binary) { delete binary; } -const char* opcodeToString(uint32_t opcode) { - return spvOpcodeString(static_cast(opcode)); -} - glsl_compile_result_t* compileGlsl(const char* code, const compile_options_t* options) { glsl_compile_result_t* result = diff --git a/gapis/shadertools/cc/libmanager.h b/gapis/shadertools/cc/libmanager.h index 439fd907bc..7584618196 100644 --- a/gapis/shadertools/cc/libmanager.h +++ b/gapis/shadertools/cc/libmanager.h @@ -38,14 +38,6 @@ typedef struct debug_instructions_t { uint32_t insts_num; } debug_instructions_t; -typedef struct code_with_debug_info_t { - bool ok; - char* message; - char* source_code; - char* disassembly_string; - debug_instructions_t* info; -} code_with_debug_info_t; - typedef enum shader_type_t { VERTEX, TESS_CONTROL, @@ -61,24 +53,6 @@ typedef enum client_type_t { VULKAN, } client_type; -/** - * Debug options - **/ -typedef struct convert_options_t { - shader_type shader_type; - const char* preamble; /* optional */ - bool prefix_names; - const char* names_prefix; /* optional */ - bool add_outputs_for_inputs; - const char* output_prefix; /* optional */ - bool make_debuggable; - bool check_after_changes; - bool disassemble; - bool relaxed; - bool strip_optimizations; - int target_glsl_version; -} convert_options_t; - typedef struct compile_options_t { shader_type shader_type; client_type client_type; @@ -96,11 +70,6 @@ typedef struct glsl_compile_result_t { spirv_binary_t binary; } glsl_compile_result_t; -code_with_debug_info_t* convertGlsl(const char*, size_t, - const convert_options_t*); - -void deleteGlslCodeWithDebug(code_with_debug_info_t*); - const char* getDisassembleText(uint32_t*, size_t); void deleteDisassembleText(const char*); @@ -109,8 +78,6 @@ spirv_binary_t* assembleToBinary(const char*); void deleteBinary(spirv_binary_t*); -const char* opcodeToString(uint32_t); - glsl_compile_result_t* compileGlsl(const char* code, const compile_options_t*); void deleteCompileResult(glsl_compile_result_t*); diff --git a/gapis/shadertools/cc/name_manager.cpp b/gapis/shadertools/cc/name_manager.cpp deleted file mode 100644 index ac13e3152f..0000000000 --- a/gapis/shadertools/cc/name_manager.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "name_manager.h" -#include -#include "common.h" - -namespace namemanager { - -/*********************************************************************** - **************************** public *********************************** - ***********************************************************************/ -/** - * Returns string of the variable with a given id and without offset - **/ -std::string NameManager::getStrName(uint32_t id) { - return getStrName(id_offset(id, NONMEMBER_OFFSET)); -} - -/** - * Returns string of the variable with a given id and offset - **/ -std::string NameManager::getStrName(id_offset id) { - name_map::iterator it = id_to_inst.find(id); - std::string res; - - assert(it != id_to_inst.end() && - "getStrName: not recognized instruction id with given offset."); - if (it != id_to_inst.end()) - res = extractString( - it->second->GetOperand(getStringPosition(it->second->opcode())).words); - return res; -} - -void NameManager::addName(Instruction* inst) { - if ((inst->opcode() == SpvOpName && inst->NumOperands() >= 2) || - (inst->opcode() == SpvOpMemberName && inst->NumOperands() >= 3)) { - uint32_t id = inst->GetSingleWordOperand(0); - uint32_t offset = getNameOffset(inst); - id_to_inst.insert( - std::pair(id_offset(id, offset), inst)); - names_ids.insert(id); - } -} - -void NameManager::setIfName(id_offset id, std::string new_name) { - name_map::iterator it = id_to_inst.find(id); - - if (it != id_to_inst.end()) { - uint32_t string_pos = getStringPosition(it->second->opcode()); - it->second->SetInOperand(string_pos, makeVector(new_name.c_str())); - } -} - -/** - * Check if given name is deprecated name. - **/ -bool NameManager::isDeprecatedBuiltInName(std::string name) const { - if (name == "gl_FragColor" || name == "gl_FragData") - return true; - else - return false; -} - -/*********************************************************************** - **************************** private ********************************** - ***********************************************************************/ -void NameManager::collectNames(Module* module) { - // debugs2 returns OpName and OpMemeberName instructions. - for (auto& inst : module->debugs2()) { - addName(&inst); - } -} - -uint32_t NameManager::getStringPosition(SpvOp_ op) { - uint32_t res = 0; - switch (op) { - case SpvOpName: - res = 1; - break; - case SpvOpMemberName: - res = 2; - break; - default: - break; - } - assert(res != 0 && "getStringPosition: given opcode has to be name opcode."); - return res; -} - -uint32_t NameManager::getNameOffset(Instruction* inst) { - uint32_t res = NONMEMBER_OFFSET; - switch (inst->opcode()) { - case SpvOpMemberName: - res = inst->GetSingleWordOperand(1); - break; - case SpvOpName: - default: - break; - } - return res; -} -} // namespace namemanager diff --git a/gapis/shadertools/cc/name_manager.h b/gapis/shadertools/cc/name_manager.h deleted file mode 100644 index 6a4bd6ea70..0000000000 --- a/gapis/shadertools/cc/name_manager.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef NAME_MANAGER_H_ -#define NAME_MANAGER_H_ - -#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.h" -#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp" -#include "third_party/SPIRV-Tools/source/opt/instruction.h" -#include "third_party/SPIRV-Tools/source/opt/iterator.h" -#include "third_party/SPIRV-Tools/source/opt/module.h" - -#include -#include - -using spvtools::ir::Instruction; -using spvtools::ir::Module; - -namespace namemanager { - -#define NONMEMBER_OFFSET ~0u - -typedef std::pair id_offset; -typedef std::map name_map; - -class NameManager { - public: - NameManager(Module* module) { collectNames(module); } - - void addName(Instruction*); - std::string getStrName(uint32_t); - std::string getStrName(id_offset); - std::unordered_set getNamedIds() { return names_ids; }; - - name_map::iterator begin() { return id_to_inst.begin(); }; - name_map::iterator end() { return id_to_inst.end(); }; - void setIfName(id_offset, std::string); - bool isDeprecatedBuiltInName(std::string) const; - - private: - name_map id_to_inst; - std::unordered_set names_ids; - void collectNames(Module*); - uint32_t getStringPosition(SpvOp_); - uint32_t getNameOffset(Instruction*); -}; -} // namespace namemanager - -#endif // NAME_MANAGER_H_ diff --git a/gapis/shadertools/cc/spirv2glsl.cpp b/gapis/shadertools/cc/spirv2glsl.cpp deleted file mode 100644 index 64d0fd1288..0000000000 --- a/gapis/shadertools/cc/spirv2glsl.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "spirv2glsl.h" - -// This will include copy of SPIRV headers form SPIRV-Cross. -// The version might not exactly match the one in SPRTV-Tools, -// so it is important we never include both at the same time. -#include "third_party/SPIRV-Cross/spirv_glsl.hpp" - -std::string spirv2glsl(std::vector spirv, int glsl_version, - bool strip_optimizations) { - spirv_cross::CompilerGLSL glsl(std::move(spirv)); - spirv_cross::CompilerGLSL::Options cross_options; - cross_options.version = glsl_version == 0 ? 330 : glsl_version; - cross_options.es = false; - cross_options.force_temporary = false; - cross_options.vertex.fixup_clipspace = false; - glsl.set_common_options(cross_options); - if (strip_optimizations) { - glsl.unset_execution_mode(spv::ExecutionModeEarlyFragmentTests); - } - return glsl.compile(); -} diff --git a/gapis/shadertools/cc/spirv2glsl.h b/gapis/shadertools/cc/spirv2glsl.h deleted file mode 100644 index 833018617d..0000000000 --- a/gapis/shadertools/cc/spirv2glsl.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -std::string spirv2glsl(std::vector spirv, int glsl_version, - bool strip_optimizations); diff --git a/gapis/shadertools/cc/spv_manager.cpp b/gapis/shadertools/cc/spv_manager.cpp deleted file mode 100644 index b8ff536820..0000000000 --- a/gapis/shadertools/cc/spv_manager.cpp +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "spv_manager.h" -#include - -namespace spvmanager { - -#define PRINT_NAME "print" -#define LABEL_PRINT_NAME "label" -#define PRINT_PARAM_NAME "value" -#define WIDTH 32 -#define RESULT_VEC_SIZE 4 -#define COORDINATE_SIZE 2 -#define FIRST_CHAIN_INDEX_OPERAND 3 - -/*********************************************************************** - **************************** public *********************************** - ***********************************************************************/ -/** - * Changes spv handled by module to prepare debug instructions. - * Firstly, changes all non-build-in names to avoid versions incompatybility. - * Secondly, for every input creates output variable to show value of each - *input. Finally, insert print functions and call instructions to appropriate - *print after each 'store' inst. - **/ -void SpvManager::makeSpvDebuggable() { - declareDebugVariables(); - declarePrints(); - insertPrintCallsIntoFunctions(); -} - -/** - * Adds output variable for each input. - * Assigns value of input value to appropriate output in the beginning of main - *function. Output variable has the same name as input with added prefix (option - *'outs_pref'). - **/ -void SpvManager::addOutputForInputs(std::string outs_pref) { - Variable out_var; - curr_block_insts.clear(); - std::unordered_set names = name_mgr->getNamedIds(); - for (auto& id : names) { - Instruction* def_inst = def_use_mgr->GetDef(id); - if (isInputVariable(*def_inst)) { - std::string in_name = name_mgr->getStrName(id); - out_var.name = outs_pref + in_name; - - const Type* type = getPointeeIfPointer(def_inst->GetSingleWordOperand(0)); - out_var.type_id = TypeToId(type); - addGlobalVariable(spv::StorageClassOutput, &out_var); - // instructions stored in curr_block_insts - uint32_t ref_id = collectInstWithResult( - SpvOpLoad, {{def_inst->GetSingleWordOperand(1)}}, out_var.type_id); - collectInstWithoutResult(SpvOpStore, {{out_var.ref_id}, {ref_id}}); - } - } - // add curr_block_insts to first block in main - auto it = context->module()->begin()->begin()->begin(); - for (auto& curr_block_inst : curr_block_insts) { - it = it.InsertBefore(std::move(curr_block_inst)); - ++it; - } - curr_block_insts.clear(); -} - -/** - * Changes all declared names with adding name_pref. - **/ -void SpvManager::mapDeclarationNames(std::string name_pref) { - std::unordered_set builtIns; - for (auto& annotations_it : context->annotations()) - if (isBuiltInDecoration(annotations_it)) - builtIns.insert(annotations_it.GetSingleWordOperand(0)); - - namemanager::name_map::iterator it; - for (it = name_mgr->begin(); it != name_mgr->end(); it++) { - std::string name = name_mgr->getStrName(it->first); - if (name != "main") // special word - if (name_mgr->isDeprecatedBuiltInName(name) || - builtIns.find(it->first.first) == builtIns.end()) { - std::string out_name = name_pref + name; - name_mgr->setIfName(it->first, out_name); - } - } -} - -// Replace the built-in gl_ViewID_OVR with custom uniform. -void SpvManager::renameViewIndex() { - for (auto& id : name_mgr->getNamedIds()) { - if (name_mgr->getStrName(id) == "gl_ViewID_OVR") { - globals.viewID.type_id = addTypeInst(SpvOpTypeInt, {{WIDTH}, {0}}); - addGlobalVariable(spv::StorageClassUniformConstant, &globals.viewID); - def_use_mgr->ForEachUser(id, [this](Instruction* user) { - if (user->opcode() == SpvOpLoad) { - user->SetInOperand(0, {globals.viewID.ref_id}); - } - }); - return; - } - } -} - -// Explicitly initialize locals. This is a work around for SPIR-V cross problem -// where it may generate code which reads locals before initializing them. -// For example, "v.x = 42.0;" becomes "v = vec4(42.0, v.y, v.z, v.w);" -void SpvManager::initLocals() { - for (auto& function : *context->module()) { - std::map> replacement; - std::unordered_set seen; - function.ForEachInst([this, &seen, &replacement](Instruction* inst) { - if (inst->opcode() == SpvOpLoad || inst->opcode() == SpvOpStore) { - Instruction* var = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - if (seen.insert(var).second) { - if (inst->opcode() == SpvOpLoad && var->opcode() == SpvOpVariable && - (var->GetSingleWordInOperand(0) == spv::StorageClassFunction || - var->GetSingleWordInOperand(0) == spv::StorageClassPrivate) && - var->NumInOperands() == 1 /* No initializer */) { - // We have found Load before Store to a local variable (function - // scope) - auto* vecType = getPointeeIfPointer(var->type_id())->AsVector(); - if (vecType && vecType->element_count() == 4) { - // TODO: Handle more then just vec4 types, or fix the issue in - // SPIRV-Cross - uint32_t elem_type_id = TypeToId(vecType->element_type()); - uint32_t elem_id = addConstant(elem_type_id, {0}); - uint32_t init_value_id = getUnique(); - context->AddGlobalValue(makeInstruction( - SpvOpConstantComposite, TypeToId(vecType), init_value_id, - {{elem_id, elem_id, elem_id, elem_id}})); - replacement[var] = makeInstruction( - var->opcode(), var->type_id(), var->result_id(), - {{var->GetSingleWordInOperand(0)}, {init_value_id}}); - } - } - } - } - }); - for (auto& basic_block : function) { - for (auto it = basic_block.begin(); it != basic_block.end(); ++it) { - std::unique_ptr newInst(std::move(replacement[&*it])); - if (newInst != nullptr) { - it = it.Erase().InsertBefore(std::move(newInst)); - } - } - } - for (auto it = context->types_values_begin(); - it != context->types_values_end(); ++it) { - std::unique_ptr newInst(std::move(replacement[&*it])); - if (newInst != nullptr) { - it = it.Erase().InsertBefore(std::move(newInst)); - } - } - } -} - -// Remove all layout(location = ...) qualifiers. -// For most use cases we should be binding/remapping locations regardless -// whether they are assigned explicit location or compiler generated one. -// TODO: Handle separate shader objects - we just hope the game uses consistent -// block names for now. -void SpvManager::removeLayoutLocations() { - for (auto& it : context->annotations()) { - if (it.opcode() == SpvOpDecorate && - it.GetSingleWordOperand(1) == SpvDecorationLocation) { - it.ToNop(); - } - } -} - -/** - * Return binary currently handled by module - **/ -std::vector SpvManager::getSpvBinary() { - std::vector res; - context->module()->ToBinary(&res, false); - - return res; -} - -/** - * Returns set of debug instructions searching through the module. - **/ -debug_instructions_t* SpvManager::getDebugInstructions() { - debug_instructions_t* result = new debug_instructions_t{}; - std::vector insts; - context->module()->ForEachInst(std::bind(&SpvManager::appendDebugInstruction, - this, &insts, std::placeholders::_1), - true); - - // Little bit of reordering to improve debug readability of the disassembly. - std::multimap names; - - result->insts = new instruction_t[insts.size()]; - for (auto& inst : insts) { - // Push names for later... - if (inst.opcode == SpvOpName || inst.opcode == SpvOpMemberName) { - names.emplace(inst.words[0], &inst); - continue; - } - - result->insts[result->insts_num++] = inst; - - // Pop any names related to this instruction... - auto range = names.equal_range(inst.id); - for (auto it = range.first; it != range.second; it++) { - result->insts[result->insts_num++] = *it->second; - } - names.erase(range.first, range.second); - } - // Pop any left over names, just in case... - for (auto& it : names) { - result->insts[result->insts_num++] = *it.second; - } - - return result; -} - -/*********************************************************************** - **************************** private ********************************** - ***********************************************************************/ -std::vector SpvManager::makeOperands( - spv_opcode_desc& op_desc, - std::initializer_list>& words, - const char* literal_string) { - std::vector operands; - std::initializer_list>::iterator it = - words.begin(); - for (int i = 0; i < op_desc->numTypes; i++) { - spv_operand_type_t operand_type = op_desc->operandTypes[i]; - - switch (operand_type) { - case SPV_OPERAND_TYPE_TYPE_ID: - case SPV_OPERAND_TYPE_RESULT_ID: - break; - - case SPV_OPERAND_TYPE_LITERAL_STRING: { - assert(literal_string && - "makeOperands: SPV_OPERAND_TYPE_LITERAL_STRING is missing."); - operands.emplace_back(operand_type, makeVector(literal_string)); - break; - } - case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { - if (literal_string) - operands.emplace_back(operand_type, makeVector(literal_string)); - break; - } - default: { - assert((it != words.end() || spvOperandIsOptional(operand_type) || - spvOperandIsVariable(operand_type)) && - "makeOperands: too few operands to make vector of operands."); - - if (it != words.end()) { - operands.emplace_back(operand_type, makeVector(*it)); - it++; - } - break; - } - } - } - assert((it == words.end() || it->size() == 0) && - "makeOperands: too many operands to make vector of operands."); - return operands; -} - -std::unique_ptr SpvManager::makeInstruction( - SpvOp_ op, uint32_t type_id, uint32_t result_id, - std::initializer_list> words, - const char* literal_string) { - spv_opcode_desc op_desc; - spv_result_t res; - std::unique_ptr inst; - res = grammar->lookupOpcode(op, &op_desc); - assert(res == SPV_SUCCESS && - "makeInstruction: cannot find opcode description"); - if (res == SPV_SUCCESS) { - inst = spvtools::MakeUnique( - context.get(), op, type_id, result_id, - makeOperands(op_desc, words, literal_string)); - def_use_mgr->AnalyzeInstDefUse(inst.get()); - } - return inst; -} - -/** - * Returns pointer to created BasicBlock (body of appropriate print function). - **/ -std::unique_ptr SpvManager::makeBasicBlock( - uint32_t label_id, Function* parent, - std::vector>&& body) { - auto label_inst = makeInstruction(SpvOpLabel, 0, label_id, {{}}); - std::unique_ptr bb = - spvtools::MakeUnique(std::move(label_inst)); - - for (auto& inst : body) { - bb->AddInstruction(std::move(inst)); - } - - bb->SetParent(parent); - return bb; -} - -/** - * Functions that create Instructions and add them directly to the module. - **/ -uint32_t SpvManager::addName(const char* name) { - uint32_t ref_id = getUnique(); - auto inst = makeInstruction(SpvOpName, 0, 0, {{ref_id}}, name); - name_mgr->addName(inst.get()); - context->AddDebug2Inst(std::move(inst)); - return ref_id; -} - -/** - * OpConstant has SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER operand. - * This operand is a literal number whose format and size are determined by a - *previous operand in this instruction. It's a signed integer, an unsigned - *integer, or a floating point number, so can occupy multiple SPIR-V words - **/ -uint32_t SpvManager::addConstant(uint32_t type_id, - std::initializer_list num) { - uint32_t result_id = getUnique(); - auto inst = makeInstruction(SpvOpConstant, type_id, result_id, {num}); - context->AddGlobalValue(std::move(inst)); - return result_id; -} - -uint32_t SpvManager::addTypeInst( - SpvOp_ op, std::initializer_list> words, - uint32_t type_id) { - uint32_t result_id = getUnique(); - auto inst = makeInstruction(op, type_id, result_id, words); - // Kill type-manager, we will lazily rebuild it. - // TODO: Add functions to SPRV-Tool to make sure it stays up to date. - type_mgr.reset(); - context->AddType(std::move(inst)); - return result_id; -} - -uint32_t SpvManager::TypeToId(const Type* type) { - if (type_mgr == nullptr) { - auto print_msg_to_stderr = [](spv_message_level_t, const char*, - const spv_position_t&, const char* m) { - std::cerr << "error: " << m << std::endl; - }; - type_mgr.reset(new TypeManager(print_msg_to_stderr, context.get())); - } - return type_mgr->GetId(type); -} - -Type* SpvManager::IdToType(uint32_t id) { - if (type_mgr == nullptr) { - auto print_msg_to_stderr = [](spv_message_level_t, const char*, - const spv_position_t&, const char* m) { - std::cerr << "error: " << m << std::endl; - }; - type_mgr.reset(new TypeManager(print_msg_to_stderr, context.get())); - } - return type_mgr->GetType(id); -} - -void SpvManager::addVariable(uint32_t type_id, uint32_t ref_id, - spv::StorageClass storage_class) { - auto inst = makeInstruction(SpvOpVariable, type_id, ref_id, - {{static_cast(storage_class)}}); - if (storage_class == spv::StorageClassFunction) - curr_block_insts.emplace_back(std::move(inst)); - else - context->AddGlobalValue(std::move(inst)); -} - -void SpvManager::addGlobalVariable(spv::StorageClass storage_class, - Variable* const var) { - if (!var->name.empty() && var->type_id) { - var->ref_id = addName(var->name.c_str()); - uint32_t ptr_id = - addTypeInst(SpvOpTypePointer, - {{static_cast(storage_class)}, {var->type_id}}); - addVariable(ptr_id, var->ref_id, storage_class); - } -} - -/** - * Adds function (with exactly one parameter) to the module - **/ -uint32_t SpvManager::addFunction(const char* name, uint32_t result_type_id, - uint32_t param_type) { - uint32_t name_id = addName(name); - uint32_t param_type_id = addTypeInst( - SpvOpTypePointer, {{spv::StorageClassFunction}, {param_type}}); - uint32_t fun_type_id = - addTypeInst(SpvOpTypeFunction, {{globals.void_id}, {param_type_id}}); - - auto fun_inst = - makeInstruction(SpvOpFunction, result_type_id, name_id, - {{spv::FunctionControlMaskNone}, {fun_type_id}}); - std::unique_ptr fun = - spvtools::MakeUnique(std::move(fun_inst)); - - uint32_t param_name_id = addName(PRINT_PARAM_NAME); - auto param_inst = makeInstruction(SpvOpFunctionParameter, param_type_id, - param_name_id, {{}}); - fun->AddParameter(std::move(param_inst)); - - name_type param(param_name_id, param_type); - - curr_block_insts.clear(); - if (param_type == globals.result.type_id) { - uint32_t true_label_id = getUnique(); - uint32_t false_label_id = getUnique(); - - // condition block - uint32_t load_id = collectInstWithResult( - SpvOpLoad, {{globals.curr_step.ref_id}}, globals.curr_step.type_id); - uint32_t sub_id = collectInstWithResult( - SpvOpISub, {{load_id}, {getConstId(1)}}, globals.curr_step.type_id); - collectInstWithoutResult(SpvOpStore, - {{globals.curr_step.ref_id}, {sub_id}}); - collectCondition(true_label_id, false_label_id); - fun->AddBasicBlock( - makeBasicBlock(getUnique(), fun.get(), std::move(curr_block_insts))); - curr_block_insts.clear(); - - // true block - load_id = collectInstWithResult(SpvOpLoad, {{param.first}}, - globals.result.type_id); - collectInstWithoutResult(SpvOpStore, {{globals.result.ref_id}, {load_id}}); - collectInstWithoutResult(SpvOpBranch, {{false_label_id}}); - fun->AddBasicBlock( - makeBasicBlock(true_label_id, fun.get(), std::move(curr_block_insts))); - curr_block_insts.clear(); - - // after-if-statement block - collectInstWithoutResult(SpvOpReturn); - fun->AddBasicBlock( - makeBasicBlock(false_label_id, fun.get(), std::move(curr_block_insts))); - curr_block_insts.clear(); - - } else { - // call-another-print block - const Type* arg_type = IdToType(param.second); - uint32_t type_to_convert = getTypeToConvert(arg_type); - collectPrintCall(param, type_to_convert); - collectInstWithoutResult(SpvOpReturn); - fun->AddBasicBlock( - makeBasicBlock(getUnique(), fun.get(), std::move(curr_block_insts))); - curr_block_insts.clear(); - } - - auto inst_end = makeInstruction(SpvOpFunctionEnd, 0, 0, {{}}); - fun->SetFunctionEnd(std::move(inst_end)); - context->AddFunction(std::move(fun)); - return name_id; -} - -/** - * Functions that create Instructions and add them to currently constructed - *block instructions. - **/ -uint32_t SpvManager::collectInstWithResult( - SpvOp_ op, std::initializer_list> data, - uint32_t type_id) { - uint32_t result_id = getUnique(); - auto inst = makeInstruction(op, type_id, result_id, data); - curr_block_insts.emplace_back(std::move(inst)); - return result_id; -} - -void SpvManager::collectInstWithoutResult( - SpvOp_ op, std::initializer_list> data, - uint32_t type_id) { - auto inst = makeInstruction(op, 0, type_id, data); - curr_block_insts.emplace_back(std::move(inst)); -} - -uint32_t SpvManager::collectCompositeConstruct( - std::initializer_list> data, - uint32_t type_id) { - const spvtools::opt::analysis::Vector* vec = IdToType(type_id)->AsVector(); - (void)vec; // Not referenced in release builds. - assert((vec != nullptr && vec->element_count() == data.begin()->size()) && - "collectCompositeConstruct: wrong data size to construct vector"); - - return collectInstWithResult(SpvOpCompositeConstruct, data, type_id); -} - -void SpvManager::collectCondition(uint32_t true_label_id, - uint32_t false_label_id) { - uint32_t load_id = collectInstWithResult( - SpvOpLoad, {{globals.curr_step.ref_id}}, globals.curr_step.type_id); - uint32_t bool_id = addTypeInst(SpvOpTypeBool, {{}}); - uint32_t cond_id = - collectInstWithResult(SpvOpIEqual, {{load_id}, {getConstId(0)}}, bool_id); - - collectInstWithoutResult(SpvOpSelectionMerge, - {{false_label_id}, {SpvSelectionControlMaskNone}}); - collectInstWithoutResult(SpvOpBranchConditional, - {{cond_id}, {true_label_id}, {false_label_id}}); -} - -/** - * Converts given type 'from' to 'to_type' type and returns 'ref_id' to new - *converted element. Type conversion only for: bool, float, sint --> uint uint, - *vec --> uvec4 - **/ -uint32_t SpvManager::collectTypeConversion(name_type from, uint32_t to_type) { - const Type* from_type = IdToType(from.second); - - uint32_t ref_id = 0; - if (from_type->AsBool()) { - ref_id = collectInstWithResult( - SpvOpSelect, {{from.first}, {getConstId(1)}, {getConstId(0)}}, to_type); - } else if (from_type->AsFloat()) { - ref_id = collectInstWithResult(SpvOpBitcast, {{from.first}}, to_type); - } else if (from_type->AsInteger()) { - if (from_type->AsInteger()->IsSigned()) { - ref_id = collectInstWithResult(SpvOpBitcast, {{from.first}}, to_type); - } else { - ref_id = collectCompositeConstruct( - {{from.first, getConstId(0), getConstId(0), getConstId(0)}}, to_type); - } - } else if (from_type->AsVector()) { - uint32_t elem_type_id = TypeToId(from_type->AsVector()->element_type()); - uint32_t elem_count = from_type->AsVector()->element_count(); - std::vector components(RESULT_VEC_SIZE); - for (uint32_t i = 0; i < RESULT_VEC_SIZE; i++) { - if (i < elem_count) { - uint32_t elem_id = collectInstWithResult( - SpvOpAccessChain, {{from.first}, {getConstId(i)}}, elem_type_id); - components[i] = collectTypeConversion( - std::make_pair(elem_id, elem_type_id), globals.uint_type_id); - } else { - components[i] = getConstId(0); - } - } - assert(RESULT_VEC_SIZE == 4 && - "collectTypeConversion: assumption that resulting vec size is 4."); - ref_id = collectCompositeConstruct( - {{components[0], components[1], components[2], components[3]}}, - to_type); - } - - assert(ref_id != 0 && - "collectTypeConversion: conversion only from types: bool, float, " - "sint, uint, vec."); - return ref_id; -} - -/** - * Collects FunctionCall instruction with appropriate fun_id and arg. - * If fun_param_type_id is given then argument type should be different then - *fun_param_type_id. By default fun_param_type_id = 0 and that means that - *conversion shouldn't be needed. - **/ -void SpvManager::collectPrintCall(name_type arg, uint32_t fun_param_type_id) { - uint32_t fun_id; - uint32_t arg_name_id; - - if (fun_param_type_id && fun_param_type_id != arg.second) { - fun_id = getPrintFunction(fun_param_type_id); - uint32_t source = - collectInstWithResult(SpvOpLoad, {{arg.first}}, arg.second); - arg_name_id = collectTypeConversion(std::make_pair(source, arg.second), - fun_param_type_id); - - } else { - fun_id = getPrintFunction(arg.second); - arg_name_id = arg.first; - } - - collectInstWithResult(SpvOpFunctionCall, {{fun_id}, {arg_name_id}}, - globals.void_id); -} - -void SpvManager::collectPrintChain(name_type arg) { - const Type* arg_type = IdToType(arg.second); - - if (isConvertedType(arg_type)) { - collectPrintCall(arg); - return; - } - - uint32_t print_elem_type; - uint32_t elem_id; - uint32_t elem_count; - - if (arg_type->AsMatrix()) { - const spvtools::opt::analysis::Matrix* matrix = arg_type->AsMatrix(); - print_elem_type = TypeToId(matrix->element_type()); - elem_count = matrix->element_count(); - for (uint32_t i = 0; i < elem_count; i++) { - elem_id = collectInstWithResult( - SpvOpAccessChain, {{arg.first}, {getConstId(i)}}, print_elem_type); - collectPrintChain(std::make_pair(elem_id, print_elem_type)); - } - } - if (arg_type->AsStruct()) { - const std::vector& element_types = - arg_type->AsStruct()->element_types(); - elem_count = element_types.size(); - for (uint32_t i = 0; i < elem_count; i++) { - print_elem_type = TypeToId(element_types[i]); - elem_id = collectInstWithResult( - SpvOpAccessChain, {{arg.first}, {getConstId(i)}}, print_elem_type); - collectPrintChain(std::make_pair(elem_id, print_elem_type)); - } - } - if (arg_type->AsArray()) { - print_elem_type = TypeToId(arg_type->AsArray()->element_type()); - elem_count = getArrayLength(arg_type); - for (uint32_t i = 0; i < elem_count; i++) { - elem_id = collectInstWithResult( - SpvOpAccessChain, {{arg.first}, {getConstId(i)}}, print_elem_type); - collectPrintChain(std::make_pair(elem_id, print_elem_type)); - } - } -} - -/** - * Declares global debug variables: result, sampler, coordinate, curr_step. - **/ -void SpvManager::declareDebugVariables() { - globals.uint_type_id = addTypeInst(SpvOpTypeInt, {{WIDTH}, {0}}); - - globals.result.type_id = - addTypeInst(SpvOpTypeVector, {{globals.uint_type_id}, {RESULT_VEC_SIZE}}); - addGlobalVariable(spv::StorageClassOutput, &globals.result); - - uint32_t float_type_id = addTypeInst(SpvOpTypeFloat, {{WIDTH}}); - globals.coordinate.type_id = - addTypeInst(SpvOpTypeVector, {{float_type_id}, {COORDINATE_SIZE}}); - addGlobalVariable(spv::StorageClassInput, &globals.coordinate); - - uint32_t image_type = addTypeInst(SpvOpTypeImage, {{globals.uint_type_id}, - {SpvDim2D}, - {0}, - {0}, - {0}, - {1}, - {SpvImageFormatUnknown}}); - uint32_t sampler_type = addTypeInst(SpvOpTypeSampledImage, {{image_type}}); - globals.sampler.type_id = sampler_type; - addGlobalVariable(spv::StorageClassUniformConstant, &globals.sampler); - - globals.curr_step.type_id = globals.uint_type_id; - addGlobalVariable(spv::StorageClassPrivate, &globals.curr_step); -} - -/** - * Adds print functions (declarations) to module. - * For every different type that type_mgr holds prepares print function with - *this parameter type. - **/ -void SpvManager::declarePrints() { - globals.void_id = addTypeInst(SpvOpTypeVoid, {{}}); - // declares those two functions first, because other print functions call them - insertPrintDeclaration(globals.result.type_id); - insertPrintDeclaration(globals.uint_type_id); - // special 'print' for labels printing - globals.label_print_id = - addFunction(LABEL_PRINT_NAME, globals.void_id, globals.uint_type_id); - - // makes a copy, because iterating through all types insertPrintDeclaration - // adds new types - std::set type_ids; - for (auto const& it : *type_mgr) { - type_ids.emplace(it.first); - } - - for (uint32_t type_id : type_ids) { - insertPrintDeclaration(type_id); - } -} - -/** - * Variable 'curr_step' is stored in Sampler2D. - * Retrieves that data and assign to 'curr_step'. - **/ -void SpvManager::setStepVariable() { - uint32_t sampler_id = collectInstWithResult( - SpvOpLoad, {{globals.sampler.ref_id}}, globals.sampler.type_id); - uint32_t coor_id = collectInstWithResult( - SpvOpLoad, {{globals.coordinate.ref_id}}, globals.coordinate.type_id); - uint32_t float_type_id = addTypeInst(SpvOpTypeFloat, {{WIDTH}}); - uint32_t vec = addTypeInst(SpvOpTypeVector, {{float_type_id}, {4}}); - uint32_t texture_res = collectInstWithResult(SpvOpImageSampleImplicitLod, - {{sampler_id}, {coor_id}}, vec); - uint32_t float_val = collectInstWithResult( - SpvOpAccessChain, {{texture_res}, {getConstId(0)}}, float_type_id); - collectInstWithoutResult(SpvOpStore, - {{globals.curr_step.ref_id}, {float_val}}); -} - -/** - * Traverses function blocks to insert print function calls. - **/ -void SpvManager::insertPrintCallsIntoFunctions() { - // main function is first, add insts to the first block - setStepVariable(); - - for (Module::iterator it = context->module()->begin(); - it != context->module()->end(); it++) { - if (isDebugFunction(*it)) continue; - - for (Function::iterator fun_it = it->begin(); fun_it != it->end(); fun_it++) - insertPrintCallsIntoBlock(*fun_it); - } -} - -void SpvManager::moveCollectedBlockInsts(BasicBlock::iterator& it) { - for (auto& i : curr_block_insts) { - it = it.InsertBefore(std::move(i)); - ++it; - } - curr_block_insts.clear(); -} - -/** - * Inserts FunctionCall instruction after Store instructions. - **/ -void SpvManager::insertPrintCallsIntoBlock(BasicBlock& bb) { - BasicBlock::iterator it = bb.begin(); - uint32_t label_id = bb.id(); - // print label id to indicate current BasicBlock - assert( - globals.label_print_id != 0 && - "insertPrintCallsIntoBlock: label_print_id has to be bigger then zero."); - collectInstWithResult(SpvOpFunctionCall, - {{globals.label_print_id}, {getConstId(label_id)}}, - globals.void_id); - moveCollectedBlockInsts(it); - - while (it != bb.end()) { - if (it->opcode() == SpvOpStore && !isArgStoreInst(it, bb.end())) { - uint32_t pointer = it->GetSingleWordOperand(0); - Instruction* pointer_def = def_use_mgr->GetDef(pointer); - - const Type* pointee_type = getPointeeIfPointer(pointer_def->type_id()); - assert(pointee_type != nullptr && - "insertPrintCallsIntoBlock: not recognized pointee type."); - if (pointee_type) { - uint32_t opcode = pointer_def->opcode(); - if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) { - uint32_t offset_id; - for (uint32_t i = FIRST_CHAIN_INDEX_OPERAND; - i < pointer_def->NumOperands(); i++) { - offset_id = pointer_def->GetSingleWordOperand(i); - collectPrintCall( - std::make_pair(offset_id, getVariableTypeId(offset_id))); - } - } - - uint32_t pointee_type_id = TypeToId(pointee_type); - collectPrintChain(std::make_pair(pointer, pointee_type_id)); - } - } - - ++it; - moveCollectedBlockInsts(it); - } -} - -/** - * Extends typeid_to_printid by inserting new pair , - * where fun_id is function made for type_id type. - * If function for this type already exists, return fun_id. - * Attention! addFunction uses curr_block_insts vector to collect function body. - **/ -uint32_t SpvManager::insertPrintDeclaration(uint32_t type_id) { - const Type* type = IdToType(type_id); - - if (isConvertedType(type)) { - for (map_uint::iterator it = typeid_to_printid.begin(); - it != typeid_to_printid.end(); ++it) { - if (type->IsSame(IdToType(it->first))) { - return it->second; - } - } - - if (type->AsVector() && type_id != globals.result.type_id) { - uint32_t elem_type_id = TypeToId(type->AsVector()->element_type()); - insertPrintDeclaration(elem_type_id); - } - - typeid_to_printid[type_id] = - addFunction(PRINT_NAME, globals.void_id, type_id); - return typeid_to_printid[type_id]; - } - return 0; -} - -uint32_t SpvManager::getVariableTypeId(uint32_t var_id) { - Instruction* var_inst = def_use_mgr->GetDef(var_id); - uint32_t type_id = var_inst->type_id(); - - assert(type_id != 0 && "getVariableTypeId: variable type not found."); - return type_id; -} - -/** - * Returns type_id of element which we want to print for given type. - **/ -uint32_t SpvManager::getTypeToConvert(const Type* type) { - uint32_t res_id = 0; - if ((type->AsInteger() && !type->AsInteger()->IsSigned()) || - type->AsVector()) { - res_id = globals.result.type_id; - } else if (type->AsBool() || type->AsInteger() || type->AsFloat()) { - res_id = globals.uint_type_id; - } - - assert(res_id != 0 && "getTypeToConvert: type id to convert not found."); - return res_id; -} - -/** - * Determines length of array if given type represents array. - **/ -uint32_t SpvManager::getArrayLength(const Type* type) { - uint32_t length = 0; - - if (type->AsArray()) { - const spvtools::opt::analysis::Array* array = type->AsArray(); - Instruction* const_inst = def_use_mgr->GetDef(array->LengthId()); - assert((const_inst->opcode() == SpvOpConstant && - const_inst->NumOperands() == 3) && - "getArrayLength: array length must come from constant instruction."); - length = const_inst->GetSingleWordOperand(2); - } - - assert(length != 0 && "getArrayLength: array length must be at least 1."); - return length; -} - -/** - * Returns pointer to pointee_type if given id defines Pointer type. - **/ -const Type* SpvManager::getPointeeIfPointer(uint32_t id) { - const Type* type = IdToType(id); - if (type) { - const spvtools::opt::analysis::Pointer* pointer = type->AsPointer(); - if (pointer) { - return pointer->pointee_type(); - } - } - return nullptr; -} - -/** - * Returns id to function declaration with the same parameter type - * as given type_id. - **/ -uint32_t SpvManager::getPrintFunction(uint32_t type_id) { - uint32_t fun_id = 0; - - map_uint::iterator it = typeid_to_printid.find(type_id); - - if (it != typeid_to_printid.end()) { - fun_id = it->second; - } else { - const Type* type = IdToType(type_id); - it = typeid_to_printid.begin(); - while (it != typeid_to_printid.end()) { - if (type->IsSame(IdToType(it->first))) { - fun_id = it->second; - break; - } - it++; - } - } - - assert(fun_id != 0 && "getPrintFunction: function id must be bigger then 0."); - return fun_id; -} - -bool SpvManager::isConvertedType(const Type* type) { - return (type->AsBool() || type->AsInteger() || type->AsFloat() || - type->AsVector()); -} - -/** - * Checks if given function is print function added for debugging. - **/ -bool SpvManager::isDebugFunction(Function& f) { - std::string name = name_mgr->getStrName(f.DefInst().result_id()); - return name == PRINT_NAME || name == LABEL_PRINT_NAME; -} - -/** - * Checks if given inst is Store instruction and - * stores variable on function argument. - **/ -bool SpvManager::isArgStoreInst(BasicBlock::iterator bb_curr, - BasicBlock::iterator bb_end) { - if (bb_curr->NumOperands() >= 2) { - uint32_t dest_id = bb_curr->GetSingleWordOperand(0); - - while (bb_curr->opcode() == SpvOpStore && bb_curr != bb_end) { - ++bb_curr; - } - - if (bb_curr != bb_end) - if (bb_curr->opcode() == SpvOpFunctionCall && bb_curr->NumOperands() >= 4) - for (uint32_t i = 3; i < bb_curr->NumOperands(); i++) - if (dest_id == bb_curr->GetSingleWordOperand(i)) return true; - } - - return false; -} - -/** - * Checks if given instruction is decoration of built in variable. - **/ -bool SpvManager::isBuiltInDecoration(const Instruction& inst) const { - spv_opcode_desc op_decoration_desc; - - if (grammar->lookupOpcode(inst.opcode(), &op_decoration_desc) == - SPV_SUCCESS) { - switch (inst.opcode()) { - case SpvOpDecorate: - if (op_decoration_desc->numTypes >= 2 && - inst.GetSingleWordOperand(1) == SpvDecorationBuiltIn) - return true; - case SpvOpMemberDecorate: - if (op_decoration_desc->numTypes >= 3 && - inst.GetSingleWordOperand(2) == SpvDecorationBuiltIn) - return true; - default: - break; - } - } - - return false; -} - -/** - * Checks if instuction represents some input variable. - **/ -bool SpvManager::isInputVariable(const Instruction& inst) const { - return (inst.opcode() == SpvOpVariable && inst.NumOperands() >= 3 && - inst.GetSingleWordOperand(2) == spv::StorageClassInput); -} - -/** - * Returns id to const instruction with a given value. - * Adds new constant instruction if not added before. - **/ -uint32_t SpvManager::getConstId(uint32_t val) { - if (consts.find(val) == consts.end()) { - consts[val] = addConstant(globals.uint_type_id, {val}); - } - return consts[val]; -} - -/** - * Returns first free unique id. - **/ -uint32_t SpvManager::getUnique() { - uint32_t res; - res = context->module()->IdBound(); - context->module()->SetIdBound(res + 1); - return res; -} - -/** - * Checks if instruction gives useful information in debugging process. - **/ -bool SpvManager::isDebugInstruction(Instruction* inst) { - if (spvtools::ir::IsTypeInst(inst->opcode())) { - return true; - } - - switch (inst->opcode()) { - case SpvOpName: - case SpvOpMemberName: - case SpvOpLine: - case SpvOpVariable: - case SpvOpLabel: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - return true; - case SpvOpFunctionCall: { - uint32_t ref_id = inst->GetSingleWordOperand(2); - Instruction* def_inst = def_use_mgr->GetDef(ref_id); - if (def_inst->opcode() == SpvOpFunction) { - std::string name = name_mgr->getStrName(def_inst->result_id()); - return name == PRINT_NAME || name == LABEL_PRINT_NAME; - } - return false; - } - default: - return false; - } -} - -/** - * Adds instruction to 'debugs' vector if it is usuful in debugging process. - * If instruction is a Name or MemberName instruction remember name as a char - *array. - **/ -void SpvManager::appendDebugInstruction(std::vector* debugs, - Instruction* inst) { - SpvOp_ opcode = inst->opcode(); - - if (isDebugInstruction(inst)) { - instruction_t i{}; - i.id = inst->result_id(); - i.opcode = opcode; - - if (opcode == SpvOpName || opcode == SpvOpMemberName) { - std::string str_name; - if (opcode == SpvOpName) - str_name = name_mgr->getStrName(inst->GetSingleWordOperand(0)); - else - str_name = name_mgr->getStrName(namemanager::id_offset( - inst->GetSingleWordOperand(0), inst->GetSingleWordOperand(1))); - - i.name = new char[str_name.length() + 1]; - std::strcpy(i.name, str_name.c_str()); - } - - // copy operands words - i.words = new uint32_t[inst->NumOperands()]; - for (uint32_t op = 0; op < inst->NumOperands(); op++) { - switch (inst->GetOperand(op).type) { - case SPV_OPERAND_TYPE_RESULT_ID: - case SPV_OPERAND_TYPE_LITERAL_STRING: - break; // Skip - default: - i.words[i.words_num++] = inst->GetSingleWordOperand(op); - } - } - - debugs->emplace_back(std::move(i)); - } -} - -} // namespace spvmanager diff --git a/gapis/shadertools/cc/spv_manager.h b/gapis/shadertools/cc/spv_manager.h deleted file mode 100644 index b0268fbd00..0000000000 --- a/gapis/shadertools/cc/spv_manager.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SPV_MANAGER_H_ -#define SPV_MANAGER_H_ - -#include "third_party/SPIRV-Headers/include/spirv/unified1/spirv.hpp" -#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.h" -#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp" -#include "third_party/SPIRV-Tools/source/assembly_grammar.h" -#include "third_party/SPIRV-Tools/source/opcode.h" -#include "third_party/SPIRV-Tools/source/operand.h" -#include "third_party/SPIRV-Tools/source/opt/build_module.h" -#include "third_party/SPIRV-Tools/source/opt/def_use_manager.h" -#include "third_party/SPIRV-Tools/source/opt/ir_context.h" -#include "third_party/SPIRV-Tools/source/opt/make_unique.h" -#include "third_party/SPIRV-Tools/source/opt/reflect.h" -#include "third_party/SPIRV-Tools/source/opt/type_manager.h" -#include "third_party/SPIRV-Tools/source/opt/types.h" - -#include "common.h" -#include "name_manager.h" - -#include "libmanager.h" - -#include -#include -#include -#include -#include -#include -#include // std::pair, std::make_pair -#include - -namespace spvmanager { - -using spvtools::ir::BasicBlock; -using spvtools::ir::Function; -using spvtools::ir::Instruction; -using spvtools::ir::IRContext; -using spvtools::ir::Module; -using spvtools::opt::analysis::DefUseManager; -using spvtools::opt::analysis::Type; -using spvtools::opt::analysis::TypeManager; - -#define MANAGER_SPV_ENV SPV_ENV_UNIVERSAL_1_1 // from spirv-tools - -typedef std::map map_uint; -typedef std::pair name_type; - -class SpvManager { - public: - SpvManager(const std::vector& spv_binary) { - globals.result.name = "gapid_result"; - globals.sampler.name = "gapid_sampler"; - globals.coordinate.name = "gapid_coor"; - globals.curr_step.name = "gapid_curr_step"; - globals.viewID.name = "gapid_gl_ViewID_OVR"; - globals.uint_type_id = 0; - globals.void_id = 0; - globals.label_print_id = 0; - - auto print_msg_to_stderr = [](spv_message_level_t, const char*, - const spv_position_t&, const char* m) { - std::cerr << "error: " << m << std::endl; - }; - - std::unique_ptr spvContext( - spvContextCreate(MANAGER_SPV_ENV)); - grammar.reset(new libspirv::AssemblyGrammar(spvContext.get())); - // init module - context = spvtools::BuildModule(MANAGER_SPV_ENV, print_msg_to_stderr, - spv_binary.data(), spv_binary.size()); - type_mgr.reset(new TypeManager(print_msg_to_stderr, context.get())); - def_use_mgr.reset(new DefUseManager(context->module())); - name_mgr.reset(new namemanager::NameManager(context->module())); - } - - void addOutputForInputs(std::string = "_out"); - void mapDeclarationNames(std::string = "x"); - void renameViewIndex(); - void removeLayoutLocations(); - void initLocals(); - void makeSpvDebuggable(); - std::vector getSpvBinary(); - debug_instructions_t* getDebugInstructions(); - - private: - struct Variable { - std::string name; - uint32_t ref_id = 0; - uint32_t type_id = 0; - }; - - struct ManagerGlobals { - Variable result; - Variable sampler; - Variable coordinate; - Variable curr_step; - Variable viewID; - uint32_t uint_type_id; - uint32_t void_id; - uint32_t label_print_id; - }; - - std::unique_ptr grammar; - std::unique_ptr context; - std::unique_ptr type_mgr; - std::unique_ptr def_use_mgr; - std::unique_ptr name_mgr; - - ManagerGlobals globals; - - // accumulator - std::vector> curr_block_insts; - map_uint typeid_to_printid; - map_uint consts; - - std::vector makeOperands( - spv_opcode_desc&, std::initializer_list>&, - const char* = nullptr); - std::unique_ptr makeInstruction( - SpvOp_, uint32_t, uint32_t, - std::initializer_list>, - const char* = nullptr); - std::unique_ptr makeBasicBlock( - uint32_t, Function*, std::vector>&&); - - uint32_t addName(const char*); - uint32_t addConstant(uint32_t, std::initializer_list); - uint32_t addTypeInst(SpvOp_, - std::initializer_list>, - uint32_t = 0); - void addVariable(uint32_t, uint32_t, spv::StorageClass); - void addGlobalVariable(spv::StorageClass, Variable*); - uint32_t addFunction(const char*, uint32_t, uint32_t); - - uint32_t collectInstWithResult( - SpvOp_, std::initializer_list> = {{}}, - uint32_t = 0); - void collectInstWithoutResult( - SpvOp_, std::initializer_list> = {{}}, - uint32_t = 0); - uint32_t collectCompositeConstruct( - std::initializer_list>, uint32_t); - void collectCondition(uint32_t, uint32_t); - uint32_t collectTypeConversion(name_type, uint32_t); - void collectPrintCall(name_type, uint32_t = 0); - void collectPrintChain(name_type); - - void declareDebugVariables(); - void declarePrints(); - void setStepVariable(); - void insertPrintCallsIntoFunctions(); - void moveCollectedBlockInsts(BasicBlock::iterator&); - void insertPrintCallsIntoBlock(BasicBlock&); - uint32_t insertPrintDeclaration(uint32_t); - - uint32_t getVariableTypeId(uint32_t); - uint32_t getTypeToConvert(const Type*); - uint32_t getArrayLength(const Type*); - const Type* getPointeeIfPointer(uint32_t); - uint32_t getPrintFunction(uint32_t); - - bool isConvertedType(const Type*); - bool isDebugFunction(Function&); - bool isDebugInstruction(Instruction*); - bool isArgStoreInst(BasicBlock::iterator, BasicBlock::iterator); - bool isBuiltInDecoration(const Instruction&) const; - bool isInputVariable(const Instruction&) const; - uint32_t getConstId(uint32_t); - uint32_t getUnique(); - - uint32_t TypeToId(const Type*); - Type* IdToType(uint32_t); - - void appendDebugInstruction(std::vector*, Instruction*); -}; - -} // namespace spvmanager - -#endif // SPV_MANAGER_H_ diff --git a/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag b/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag deleted file mode 100644 index 1c52467469..0000000000 --- a/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag +++ /dev/null @@ -1,62 +0,0 @@ -#version 330 - -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -uniform sampler2D _MainTex; -in mediump vec2 xlv_TEXCOORD2; - -mat3 theMatrix; -mat3 matrix2; - -int i; - - -struct struct_type { - float a; - int b; - bool arr[5]; -} struct_val; - - - -void main () -{ - - i = 0; - float arr4[7]; - - while (i < 7) { - arr4[i] = 3; - } - arr4[6] = 4; - - float arr3[] = arr4; - - float arr2[6] = float[6](1, 2,3, 4, 5, 6); - float arr[] = float[](1,2,3,4,5); - i = arr.length(); - - struct_val = struct_type(1.2, 3, bool[5](true, true, true, false, false)); - struct_val.a = 2.2; - struct_val.arr[struct_val.b] = (struct_val.a > 2); - - - theMatrix[1] = vec3(3.0, 3.0, 3.0); //Sets the second column to all 3.0s - theMatrix[2][0] = 16.0; - - matrix2 = theMatrix; - - gl_FragDepth = 1.2; -} diff --git a/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag.out3 b/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag.out3 deleted file mode 100644 index 00798b5ce0..0000000000 --- a/gapis/shadertools/cc/tests/shaders/0001ce24c54214efa0dc896734b22dd1dbaac80b9.frag.out3 +++ /dev/null @@ -1,199 +0,0 @@ -Fragment mode -compiled -linked -label 5 -action type: 1, words: 93, 94, 0, 1, -action type: 0, words: 23, -action type: 1, words: 9, 8, 0, 1, -label 11 -label 15 -label 12 -action type: 0, words: 27, -action type: 1, words: 25, 24, 1, 1, -label 14 -label 13 -action type: 0, words: 29, -action type: 1, words: 25, 24, 1, 1, -action type: 0, words: 31, -action type: 1, words: 33, 24, 0, 7, -action type: 0, words: 33, -action type: 1, words: 38, 37, 0, 6, -action type: 0, words: 34, -action type: 1, words: 47, 46, 0, 5, -action type: 0, words: 35, -action type: 1, words: 9, 8, 0, 1, -action type: 0, words: 37, -action type: 1, words: 53, 52, 0, 7, -action type: 0, words: 38, -action type: 1, words: 53, 52, 1, 1, -action type: 0, words: 39, -action type: 1, words: 53, 52, 2, 1, -action type: 0, words: 42, -action type: 1, words: 75, 74, 1, 1, -action type: 0, words: 43, -action type: 1, words: 75, 74, 2, 1, -action type: 0, words: 45, -action type: 1, words: 82, 74, 0, 3, -action type: 0, words: 47, -action type: 1, words: 85, 84, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -struct xstruct_type -{ - float xa; - int xb; - bool xarr[5]; -}; - -uniform sampler2D x_MainTex; -uniform usampler2D gapid_sampler; - -in vec2 xxlv_TEXCOORD2; -out vec2 x_oxlv_TEXCOORD2; -out uvec4 gapid_result; -in vec2 gapid_coor; -int xi; -xstruct_type xstruct_val; -mat3 xtheMatrix; -mat3 xmatrix2; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(bool value) -{ - print(value ? 1u : 0u); -} - -void print(vec3 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), 0u)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_oxlv_TEXCOORD2 = xxlv_TEXCOORD2; - print(x_oxlv_TEXCOORD2); - xi = 0; - print(xi); - float xarr4[7]; - float xarr3[7]; - float xarr2[6]; - float xarr[5]; - for (;;) - { - label(11u); - label(15u); - if ((xi < 7)) - { - label(12u); - int _26 = xi; - xarr4[_26] = 3.0; - print(_26); - print(xarr4[_26]); - label(14u); - continue; - } - else - { - break; - } - } - label(13u); - xarr4[6] = 4.0; - print(6); - print(xarr4[6]); - xarr3 = xarr4; - print(xarr3[0u]); - print(xarr3[1u]); - print(xarr3[2u]); - print(xarr3[3u]); - print(xarr3[4u]); - print(xarr3[5u]); - print(xarr3[6u]); - xarr2 = float[](1.0, 2.0, 3.0, 4.0, 5.0, 6.0); - print(xarr2[0u]); - print(xarr2[1u]); - print(xarr2[2u]); - print(xarr2[3u]); - print(xarr2[4u]); - print(xarr2[5u]); - xarr = float[](1.0, 2.0, 3.0, 4.0, 5.0); - print(xarr[0u]); - print(xarr[1u]); - print(xarr[2u]); - print(xarr[3u]); - print(xarr[4u]); - xi = 5; - print(xi); - xstruct_val = xstruct_type(1.2000000476837158203125, 3, bool[](true, true, true, false, false)); - print(xstruct_val.xa); - print(xstruct_val.xb); - print(xstruct_val.xarr[0u]); - print(xstruct_val.xarr[1u]); - print(xstruct_val.xarr[2u]); - print(xstruct_val.xarr[3u]); - print(xstruct_val.xarr[4u]); - xstruct_val.xa = 2.2000000476837158203125; - print(0); - print(xstruct_val.xa); - int _66 = xstruct_val.xb; - xstruct_val.xarr[_66] = (xstruct_val.xa > 2.0); - print(2); - print(_66); - print(xstruct_val.xarr[_66]); - xtheMatrix[1] = vec3(3.0); - print(1); - print(xtheMatrix[1]); - xtheMatrix[2].x = 16.0; - print(2); - print(0u); - print(xtheMatrix[2].x); - xmatrix2 = xtheMatrix; - print(xmatrix2[0u]); - print(xmatrix2[1u]); - print(xmatrix2[2u]); - gl_FragDepth = 1.2000000476837158203125; - print(gl_FragDepth); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag b/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag deleted file mode 100644 index 37ada1b125..0000000000 --- a/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -precision highp float; -uniform lowp vec4 _SpecColor; -uniform sampler2D _MainTex; -uniform lowp vec4 _Color; -uniform sampler2D _LightBuffer; -varying highp vec2 xlv_TEXCOORD0; -varying highp vec4 xlv_TEXCOORD1; -varying highp vec3 xlv_TEXCOORD2; -void main () -{ - lowp vec4 tmpvar_1; - mediump vec4 c_2; - mediump vec4 light_3; - lowp vec4 tmpvar_4; - tmpvar_4 = texture2D (_MainTex, xlv_TEXCOORD0); - lowp vec3 tmpvar_5; - tmpvar_5 = (tmpvar_4.xyz * _Color.xyz); - lowp vec4 tmpvar_6; - tmpvar_6 = texture2DProj (_LightBuffer, xlv_TEXCOORD1); - light_3 = tmpvar_6; - mediump vec4 tmpvar_7; - tmpvar_7 = -(log2(max (light_3, vec4(0.001, 0.001, 0.001, 0.001)))); - light_3.w = tmpvar_7.w; - highp vec3 tmpvar_8; - tmpvar_8 = (tmpvar_7.xyz + xlv_TEXCOORD2); - light_3.xyz = tmpvar_8; - lowp vec4 c_9; - lowp float spec_10; - mediump float tmpvar_11; - tmpvar_11 = (tmpvar_7.w * tmpvar_4.w); - spec_10 = tmpvar_11; - mediump vec3 tmpvar_12; - tmpvar_12 = ((tmpvar_5 * light_3.xyz) + ((light_3.xyz * _SpecColor.xyz) * spec_10)); - c_9.xyz = tmpvar_12; - c_9.w = ((tmpvar_4.w * _Color.w) + (spec_10 * _SpecColor.w)); - c_2 = c_9; - tmpvar_1 = c_2; - gl_FragData[0] = tmpvar_1; -} diff --git a/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag.out3 b/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag.out3 deleted file mode 100644 index 597a70e331..0000000000 --- a/gapis/shadertools/cc/tests/shaders/02dd3b78fd079ef9351eaaa548e4ef8aab00191f.frag.out3 +++ /dev/null @@ -1,158 +0,0 @@ -Fragment mode -compiled -linked -label 5 -action type: 1, words: 116, 117, 0, 1, -action type: 1, words: 119, 120, 0, 1, -action type: 1, words: 122, 123, 0, 1, -action type: 0, words: 20, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 22, -action type: 1, words: 23, 22, 0, 1, -action type: 0, words: 24, -action type: 1, words: 31, 9, 0, 1, -action type: 0, words: 25, -action type: 1, words: 40, 9, 0, 1, -action type: 0, words: 27, -action type: 1, words: 42, 9, 0, 1, -action type: 0, words: 28, -action type: 1, words: 40, 9, 1, 1, -action type: 0, words: 30, -action type: 1, words: 55, 22, 0, 1, -action type: 0, words: 31, -action type: 1, words: 40, 9, 0, 1, -action type: 0, words: 35, -action type: 1, words: 65, 51, 0, 1, -action type: 0, words: 36, -action type: 1, words: 71, 51, 0, 1, -action type: 0, words: 38, -action type: 1, words: 73, 22, 0, 1, -action type: 0, words: 39, -action type: 1, words: 87, 9, 0, 1, -action type: 0, words: 40, -action type: 1, words: 87, 9, 1, 1, -action type: 0, words: 41, -action type: 1, words: 103, 9, 0, 1, -action type: 0, words: 42, -action type: 1, words: 105, 9, 0, 1, -action type: 0, words: 43, -action type: 1, words: 110, 109, 1, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform sampler2D x_MainTex; -uniform vec4 x_Color; -uniform sampler2D x_LightBuffer; -uniform vec4 x_SpecColor; -uniform usampler2D gapid_sampler; - -in vec2 xxlv_TEXCOORD0; -in vec4 xxlv_TEXCOORD1; -in vec3 xxlv_TEXCOORD2; -out vec4 xgl_FragData[32]; -out vec3 x_oxlv_TEXCOORD2; -out vec2 x_oxlv_TEXCOORD0; -out vec4 x_oxlv_TEXCOORD1; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(vec3 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), 0u)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(int value) -{ - print(uint(value)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_oxlv_TEXCOORD2 = xxlv_TEXCOORD2; - print(x_oxlv_TEXCOORD2); - x_oxlv_TEXCOORD0 = xxlv_TEXCOORD0; - print(x_oxlv_TEXCOORD0); - x_oxlv_TEXCOORD1 = xxlv_TEXCOORD1; - print(x_oxlv_TEXCOORD1); - vec4 xtmpvar_4 = texture(x_MainTex, xxlv_TEXCOORD0); - print(xtmpvar_4); - vec3 xtmpvar_5 = (xtmpvar_4.xyz * x_Color.xyz); - print(xtmpvar_5); - vec4 _38 = xxlv_TEXCOORD1; - _38.z = xxlv_TEXCOORD1.w; - vec4 xtmpvar_6 = textureProj(x_LightBuffer, _38.xyz); - print(xtmpvar_6); - vec4 xlight_3 = xtmpvar_6; - print(xlight_3); - vec4 xtmpvar_7 = (-log2(max(xlight_3, vec4(0.001000000047497451305389404296875)))); - print(xtmpvar_7); - xlight_3.w = xtmpvar_7.w; - print(3u); - print(xlight_3.w); - vec3 xtmpvar_8 = (xtmpvar_7.xyz + xxlv_TEXCOORD2); - print(xtmpvar_8); - xlight_3 = vec4(xtmpvar_8.x, xtmpvar_8.y, xtmpvar_8.z, xlight_3.w); - print(xlight_3); - float xtmpvar_11 = (xtmpvar_7.w * xtmpvar_4.w); - print(xtmpvar_11); - float xspec_10 = xtmpvar_11; - print(xspec_10); - vec3 xtmpvar_12 = ((xtmpvar_5 * xlight_3.xyz) + ((xlight_3.xyz * x_SpecColor.xyz) * xspec_10)); - print(xtmpvar_12); - vec4 xc_9; - xc_9 = vec4(xtmpvar_12.x, xtmpvar_12.y, xtmpvar_12.z, xc_9.w); - print(xc_9); - xc_9.w = ((xtmpvar_4.w * x_Color.w) + (xspec_10 * x_SpecColor.w)); - print(3u); - print(xc_9.w); - vec4 xc_2 = xc_9; - print(xc_2); - vec4 xtmpvar_1 = xc_2; - print(xtmpvar_1); - xgl_FragData[0] = xtmpvar_1; - print(0); - print(xgl_FragData[0]); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/31970cd999553c708364771961a1f61d5dd59c40.vert.out3 b/gapis/shadertools/cc/tests/shaders/31970cd999553c708364771961a1f61d5dd59c40.vert.out3 deleted file mode 100644 index 3c7351e1d9..0000000000 --- a/gapis/shadertools/cc/tests/shaders/31970cd999553c708364771961a1f61d5dd59c40.vert.out3 +++ /dev/null @@ -1,204 +0,0 @@ -Vertex mode -compiled -linked -label 5 -action type: 1, words: 212, 213, 0, 1, -action type: 1, words: 215, 216, 0, 1, -action type: 1, words: 218, 219, 0, 1, -action type: 1, words: 221, 222, 0, 1, -action type: 1, words: 224, 225, 0, 1, -action type: 1, words: 227, 228, 0, 1, -action type: 1, words: 230, 231, 0, 1, -action type: 0, words: 56, -action type: 1, words: 82, 25, 0, 1, -action type: 0, words: 57, -action type: 1, words: 86, 25, 0, 1, -action type: 0, words: 59, -action type: 1, words: 90, 25, 0, 1, -action type: 0, words: 62, -action type: 1, words: 103, 102, 1, 1, -action type: 0, words: 67, -action type: 1, words: 112, 13, 0, 1, -action type: 0, words: 69, -action type: 1, words: 116, 110, 0, 1, -action type: 0, words: 70, -action type: 1, words: 116, 110, 0, 1, -action type: 0, words: 73, -action type: 1, words: 124, 123, 0, 1, -action type: 0, words: 77, -action type: 1, words: 135, 13, 0, 1, -action type: 0, words: 78, -action type: 1, words: 138, 123, 0, 1, -action type: 0, words: 80, -action type: 1, words: 149, 19, 0, 1, -action type: 0, words: 81, -action type: 1, words: 155, 19, 0, 1, -action type: 0, words: 82, -action type: 1, words: 158, 110, 0, 1, -action type: 0, words: 83, -action type: 1, words: 160, 7, 0, 1, -action type: 0, words: 84, -action type: 1, words: 166, 7, 0, 1, -action type: 0, words: 85, -action type: 1, words: 181, 110, 0, 1, -action type: 0, words: 86, -action type: 1, words: 181, 110, 1, 1, -label 11 -action type: 0, words: 4, -label 17 -action type: 0, words: 8, -label 23 -action type: 0, words: 12, -label 29 -action type: 0, words: 16, -label 32 -action type: 0, words: 20, -label 35 -action type: 0, words: 24, -label 38 -action type: 0, words: 49, -action type: 1, words: 68, 7, 0, 1, -action type: 0, words: 50, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform mat4 xLocalToWorld; -uniform mat4 xLocalToProjection; -uniform vec4 xLightmapCoordinateScaleBias; -uniform mat3 xTextureTransform; -uniform vec4 xFogColor; -uniform float xFogStartSquared; -uniform float xFogOneOverSquaredRange; -uniform vec4 xFadeColorAndAmount; -uniform mat3 xLocalToWorldRotation; -uniform mat4 xViewProjection; -uniform usampler2D gapid_sampler; - -in vec4 xPosition; -in vec4 xVertexColor; -in vec2 xTexCoords1; -out vec4 xUVBase; -out vec2 xUVLightmap; -in vec2 xLightMapCoordinate; -in vec2 xTexCoords0; -out vec2 xUVDetail; -out vec4 xTextureBlendFactor; -out vec4 xGlobalEffectColorAndAmount; -out vec4 x_oVertexColor; -out vec4 x_oPosition; -out int x_ogl_VertexID; -out vec2 x_oLightMapCoordinate; -out int x_ogl_InstanceID; -out vec2 x_oTexCoords1; -out vec2 x_oTexCoords0; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(vec3 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), 0u)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_oVertexColor = xVertexColor; - print(x_oVertexColor); - x_oPosition = xPosition; - print(x_oPosition); - x_ogl_VertexID = gl_VertexID; - print(x_ogl_VertexID); - x_oLightMapCoordinate = xLightMapCoordinate; - print(x_oLightMapCoordinate); - x_ogl_InstanceID = gl_InstanceID; - print(x_ogl_InstanceID); - x_oTexCoords1 = xTexCoords1; - print(x_oTexCoords1); - x_oTexCoords0 = xTexCoords0; - print(x_oTexCoords0); - vec4 xInputPosition = xPosition; - print(xInputPosition); - vec4 xVertexColorRGBA = xVertexColor.zyxw; - print(xVertexColorRGBA); - vec4 xWorldPosition = (xLocalToWorld * xInputPosition); - print(xWorldPosition); - gl_Position = (xInputPosition * xLocalToProjection); - gl_Position.z = 2.0 * gl_Position.z - gl_Position.w; - print(0); - print(gl_Position); - vec2 xBaseTexCoords = xTexCoords1; - print(xBaseTexCoords); - xUVBase = vec4(xBaseTexCoords.x, xBaseTexCoords.y, xUVBase.z, xUVBase.w); - print(xUVBase); - xUVBase = vec4(xUVBase.x, xUVBase.y, xBaseTexCoords.x, xBaseTexCoords.y); - print(xUVBase); - xUVLightmap = ((xLightMapCoordinate * xLightmapCoordinateScaleBias.xy) + xLightmapCoordinateScaleBias.wz); - print(xUVLightmap); - vec2 xDetailTexCoords = xTexCoords0; - print(xDetailTexCoords); - xUVDetail = (xTextureTransform * vec3(xDetailTexCoords, 1.0)).xy; - print(xUVDetail); - vec3 xEyeToVertexVector = (vec3(0.0) - xWorldPosition.xyz); - print(xEyeToVertexVector); - vec3 xEyeToVertexDirection = normalize(xEyeToVertexVector); - print(xEyeToVertexDirection); - xTextureBlendFactor = xVertexColorRGBA; - print(xTextureBlendFactor); - float xVertDistSquared = dot(xWorldPosition.xyz, xWorldPosition.xyz); - print(xVertDistSquared); - float xFogColorAmount = (xFogColor.w * clamp(((xVertDistSquared - xFogStartSquared) * xFogOneOverSquaredRange), 0.0, 1.0)); - print(xFogColorAmount); - vec3 _192 = mix((xFogColor.xyz * xFogColorAmount), xFadeColorAndAmount.xyz, vec3(xFadeColorAndAmount.w)); - xGlobalEffectColorAndAmount = vec4(_192.x, _192.y, _192.z, xGlobalEffectColorAndAmount.w); - print(xGlobalEffectColorAndAmount); - xGlobalEffectColorAndAmount.w = (1.0 - ((xFogColorAmount + xFadeColorAndAmount.w) - (xFogColorAmount * xFadeColorAndAmount.w))); - print(3u); - print(xGlobalEffectColorAndAmount.w); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert b/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert deleted file mode 100644 index c8416f7476..0000000000 --- a/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -precision lowp float; -attribute highp vec4 a_position; -attribute lowp vec4 a_color; -attribute mediump vec2 a_texCoord; -uniform highp mat4 u_modelViewProjectionMatrix; - -uniform lowp vec4 u_materialAmbient; - -varying lowp vec4 v_color; -varying mediump vec2 v_texCoord; - -void main() { - gl_Position = u_modelViewProjectionMatrix * a_position; - v_color = a_color * vec4(u_materialAmbient.a, u_materialAmbient.a, u_materialAmbient.a, 1.0); - v_texCoord = a_texCoord; -} diff --git a/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert.out3 b/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert.out3 deleted file mode 100644 index 1425d47d4e..0000000000 --- a/gapis/shadertools/cc/tests/shaders/34bb6e0642a25204a333b495d2bc9fd20014f8a6.vert.out3 +++ /dev/null @@ -1,99 +0,0 @@ -Vertex mode -compiled -linked -label 5 -action type: 1, words: 53, 54, 0, 1, -action type: 1, words: 56, 57, 0, 1, -action type: 1, words: 59, 60, 0, 1, -action type: 1, words: 62, 63, 0, 1, -action type: 1, words: 65, 66, 0, 1, -action type: 0, words: 13, -action type: 1, words: 15, 14, 1, 1, -action type: 0, words: 14, -action type: 1, words: 28, 26, 0, 1, -action type: 0, words: 15, -action type: 1, words: 46, 45, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform mat4 xu_modelViewProjectionMatrix; -uniform vec4 xu_materialAmbient; -uniform usampler2D gapid_sampler; - -in vec4 xa_position; -out vec4 xv_color; -in vec4 xa_color; -out vec2 xv_texCoord; -in vec2 xa_texCoord; -out vec2 x_oa_texCoord; -out vec4 x_oa_position; -out int x_ogl_VertexID; -out int x_ogl_InstanceID; -out vec4 x_oa_color; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_oa_texCoord = xa_texCoord; - print(x_oa_texCoord); - x_oa_position = xa_position; - print(x_oa_position); - x_ogl_VertexID = gl_VertexID; - print(x_ogl_VertexID); - x_ogl_InstanceID = gl_InstanceID; - print(x_ogl_InstanceID); - x_oa_color = xa_color; - print(x_oa_color); - gl_Position = (xu_modelViewProjectionMatrix * xa_position); - gl_Position.z = 2.0 * gl_Position.z - gl_Position.w; - print(0); - print(gl_Position); - xv_color = (xa_color * vec4(xu_materialAmbient.w, xu_materialAmbient.w, xu_materialAmbient.w, 1.0)); - print(xv_color); - xv_texCoord = xa_texCoord; - print(xv_texCoord); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag b/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag deleted file mode 100644 index 468bbbcde2..0000000000 --- a/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define MT_GL_ES_3 -#define ANDROID - -// Mipmapping stuff -#define texture2DWithBias( X, Y ) texture2D( X, Y ) -#define ENABLE_SHADER_FEATURES - -#ifndef BAKE_DECAL_BACKFACE_TEST -#define BAKE_DECAL_BACKFACE_TEST -#endif -#ifndef USE_STEP_FUNCTION -#define USE_STEP_FUNCTION -#endif -#ifndef USE_LIVERY_TEXTURE_RGB -#define USE_LIVERY_TEXTURE_RGB -#endif - - -#define MT_FRAGMENT_SHADER - -#if defined(BAKE_COLOUR) - -uniform lowp sampler2D s_Texture0; // base texture -uniform lowp sampler2D s_Texture1; // mask texture -uniform lowp sampler2D s_Texture2; // decal texture -uniform lowp vec4 u_LiveryColour; // custom colours - -varying highp vec2 v_TexCoord0; - -void main() -{ - lowp vec4 baseTexture = texture2D( s_Texture0, v_TexCoord0 ); - lowp vec4 maskTexture = texture2D( s_Texture1, v_TexCoord0 ); - lowp vec4 decalTexture = texture2D( s_Texture2, v_TexCoord0 ); - - // mix the custom colour with the base texture using the mask - lowp float mask = maskTexture.r; - lowp vec3 bg = u_LiveryColour.rgb * mask + baseTexture.rgb * (1.0 - mask); - - // mix the premultipied decal layer with the background using Porter-Duff OVER and the mask (assuming dest alpha is 1) - gl_FragColor = vec4( decalTexture.rgb * mask + bg.rgb * (1.0 - decalTexture.a * mask), 1.0 ); -} - -#endif - -#if defined(BAKE_COPY) - -uniform lowp sampler2D s_Texture0; // decal texture -varying highp vec2 v_TexCoord0; - -void main() -{ - lowp vec4 decalTexture = texture2D( s_Texture0, v_TexCoord0 ); - gl_FragColor = decalTexture; -} - -#endif - -#if defined(BAKE_EDGES) - -uniform lowp sampler2D s_Texture0; // decal texture -varying highp vec2 v_TexCoord0; -varying highp vec2 v_TexCoord1; -varying highp vec2 v_TexCoord2; -varying highp vec2 v_TexCoord3; - -void sampleTexture(highp vec2 texCoord, inout highp vec4 colourSum, inout highp float weightSum) -{ - lowp vec4 texel = texture2D( s_Texture0, texCoord ); - colourSum += texel * texel.a; - weightSum += texel.a; -} - -void main() -{ - highp vec4 colourSum = vec4(0.0); - highp float weightSum = 0.0; - - sampleTexture( v_TexCoord0, colourSum, weightSum); - sampleTexture( v_TexCoord1, colourSum, weightSum); - sampleTexture( v_TexCoord2, colourSum, weightSum); - sampleTexture( v_TexCoord3, colourSum, weightSum); - - gl_FragColor = colourSum / weightSum; -} - -#endif - -#if defined (BAKE_SPEC) - -uniform lowp sampler2D s_Texture0; // mask texture -uniform lowp sampler2D s_Texture1; // decal texture - -varying highp vec2 v_TexCoord0; - -void main() -{ - lowp vec4 maskTexture = texture2D( s_Texture0, v_TexCoord0 ); - lowp vec4 decalTexture = texture2D( s_Texture1, v_TexCoord0 ); - - lowp float spec = maskTexture.r * (1.0 - decalTexture.a); - lowp float decal = maskTexture.r * decalTexture.a; - gl_FragColor = vec4(spec, decal, maskTexture.b, 1.0); -} - -#endif - -#if defined(BAKE_STENCIL) - -void main() -{ - // just write geometry into stencil buffer - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); -} - -#endif - -#if defined(BAKE_DECAL_NO_OCCLUSION) || defined(BAKE_DECAL_DEPTH_TEST) || defined(BAKE_DECAL_BACKFACE_TEST) || defined(USE_LIVERY_TEXTURE_RGB) - -uniform lowp sampler2D s_Texture0; // decal texture -uniform highp sampler2D s_Texture1; // depth texture - -varying highp vec2 v_TexCoordDecal; -varying highp vec4 v_Normal; -varying highp float v_Depth; - -uniform lowp vec4 u_LiveryColour; - -void main() -{ - lowp vec4 decalTexture = texture2D( s_Texture0, v_TexCoordDecal ); - -#if defined(BAKE_DECAL_DEPTH_TEST) - highp vec4 depthTexture = texture2D( s_Texture1, v_TexCoordDecal ); - highp float d = v_Depth; - highp float dt = (depthTexture.r + depthTexture.g + depthTexture.b + depthTexture.a) * 0.25; -#endif - -#if defined(USE_STEP_FUNCTION) - - -#if defined(USE_LIVERY_TEXTURE_RGB) - lowp float decalAlpha = decalTexture.a; -#else - // premultiply colour and assume the blend mode is (1, 1-srcA) - lowp float decalAlpha = decalTexture.r * u_LiveryColour.a; -#endif - -#if defined(USE_FLAT_ALPHA) - decalAlpha = step( 0.01, decalAlpha ); -#endif -#if defined(BAKE_DECAL_DEPTH_TEST) - decalAlpha *= step( d - 0.005, dt ); // d - 0.005 > dt || -#endif -#if defined(BAKE_DECAL_DEPTH_TEST) || defined(BAKE_DECAL_BACKFACE_TEST) - decalAlpha *= step( v_Normal.z, 0.0 ); // v_Normal.z > 0.0 || -#endif - decalAlpha *= step( 0.0, v_TexCoordDecal.s ); // v_TexCoordDecal.s < 0.0 || - decalAlpha *= step( v_TexCoordDecal.s, 1.0 ); // v_TexCoordDecal.s > 1.0 || - decalAlpha *= step( 0.0, v_TexCoordDecal.t ); // v_TexCoordDecal.t < 0.0 || - decalAlpha *= step( v_TexCoordDecal.t, 1.0 ); // v_TexCoordDecal.t > 1.0) - -#if defined(USE_LIVERY_TEXTURE_RGB) - gl_FragColor = vec4( decalTexture.rgb, decalAlpha); -#else - gl_FragColor = vec4( u_LiveryColour.rgb * decalAlpha, decalAlpha ); -#endif - -#else // USE_STEP_FUNCTION - - if ( -#if defined(BAKE_DECAL_DEPTH_TEST) - d - 0.005 > dt || -#endif -#if defined(BAKE_DECAL_DEPTH_TEST) || defined(BAKE_DECAL_BACKFACE_TEST) - v_Normal.z > 0.0 || -#endif - v_TexCoordDecal.s < 0.0 || - v_TexCoordDecal.s > 1.0 || - v_TexCoordDecal.t < 0.0 || - v_TexCoordDecal.t > 1.0) - { - gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); - } - else - { - // premultiply colour and assume the blend mode is (1, 1-srcA) -#if defined(USE_LIVERY_TEXTURE_RGB) - lowp float decalAlpha = decalTexture.a; -#else - lowp float decalAlpha = decalTexture.r * u_LiveryColour.a; -#endif - -#if defined(USE_FLAT_ALPHA) - decalAlpha = ceil( decalAlpha - 0.01 ); -#endif - -#if defined(USE_LIVERY_TEXTURE_RGB) - gl_FragColor = vec4( decalTexture.rgb, decalAlpha); -#else - gl_FragColor = vec4( u_LiveryColour.rgb * decalAlpha, decalAlpha ); -#endif - } - -#endif // USE_STEP_FUNCTION -} - -#endif - -#if defined(BAKE_DEPTH) - -void main() -{ - // write depth to texture - highp float z = gl_FragCoord.z; - - highp float r = clamp((z - 0.00) * 4.0, 0.0, 1.0); - highp float g = clamp((z - 0.25) * 4.0, 0.0, 1.0); - highp float b = clamp((z - 0.50) * 4.0, 0.0, 1.0); - highp float a = clamp((z - 0.75) * 4.0, 0.0, 1.0); - - gl_FragColor = vec4(r, g, b, a); -} - -#endif diff --git a/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag.out3 b/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag.out3 deleted file mode 100644 index ab0133fa01..0000000000 --- a/gapis/shadertools/cc/tests/shaders/41cb18c3bc5d39d4a6b353f00112bf820ec66f2e.frag.out3 +++ /dev/null @@ -1,109 +0,0 @@ -Fragment mode -compiled -linked -label 5 -action type: 1, words: 74, 75, 0, 1, -action type: 1, words: 77, 78, 0, 1, -action type: 1, words: 80, 81, 0, 1, -action type: 0, words: 131, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 143, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 156, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 158, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 159, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 160, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 161, -action type: 1, words: 22, 21, 0, 1, -action type: 0, words: 164, -action type: 1, words: 61, 60, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform sampler2D xs_Texture0; -uniform sampler2D xs_Texture1; -uniform vec4 xu_LiveryColour; -uniform usampler2D gapid_sampler; - -in vec2 xv_TexCoordDecal; -in vec4 xv_Normal; -out vec4 xgl_FragColor; -in float xv_Depth; -out float x_ov_Depth; -out vec4 x_ov_Normal; -out vec2 x_ov_TexCoordDecal; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_ov_Depth = xv_Depth; - print(x_ov_Depth); - x_ov_Normal = xv_Normal; - print(x_ov_Normal); - x_ov_TexCoordDecal = xv_TexCoordDecal; - print(x_ov_TexCoordDecal); - vec4 xdecalTexture = texture(xs_Texture0, xv_TexCoordDecal); - print(xdecalTexture); - float xdecalAlpha = xdecalTexture.w; - print(xdecalAlpha); - xdecalAlpha = (xdecalAlpha * step(xv_Normal.z, 0.0)); - print(xdecalAlpha); - xdecalAlpha = (xdecalAlpha * step(0.0, xv_TexCoordDecal.x)); - print(xdecalAlpha); - xdecalAlpha = (xdecalAlpha * step(xv_TexCoordDecal.x, 1.0)); - print(xdecalAlpha); - xdecalAlpha = (xdecalAlpha * step(0.0, xv_TexCoordDecal.y)); - print(xdecalAlpha); - xdecalAlpha = (xdecalAlpha * step(xv_TexCoordDecal.y, 1.0)); - print(xdecalAlpha); - xgl_FragColor = vec4(xdecalTexture.xyz, xdecalAlpha); - print(xgl_FragColor); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag b/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag deleted file mode 100644 index 4e2c8d30e1..0000000000 --- a/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -precision highp float; -uniform lowp vec4 _WorldSpaceLightPos0; -uniform lowp vec4 _LightColor0; -uniform sampler2D _MainTex; -uniform lowp vec4 _Color; -uniform lowp vec4 _AddColor; -varying highp vec2 xlv_TEXCOORD0; -varying lowp vec3 xlv_TEXCOORD1; -varying lowp vec3 xlv_TEXCOORD2; -void main () -{ - lowp vec4 c_1; - lowp vec3 tmpvar_2; - tmpvar_2 = (texture2D (_MainTex, xlv_TEXCOORD0).xyz * _Color.xyz); - lowp vec4 c_3; - lowp float tmpvar_4; - tmpvar_4 = max (0.0, dot (xlv_TEXCOORD1, _WorldSpaceLightPos0.xyz)); - highp vec3 tmpvar_5; - tmpvar_5 = (((tmpvar_2 * _LightColor0.xyz) * tmpvar_4) * 2.0); - c_3.xyz = tmpvar_5; - c_3.w = 0.0; - c_1.w = c_3.w; - c_1.xyz = (c_3.xyz + (tmpvar_2 * xlv_TEXCOORD2)); - c_1.xyz = (c_1.xyz + _AddColor.xyz); - gl_FragData[0] = c_1; -} - - - diff --git a/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag.out3 b/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag.out3 deleted file mode 100644 index 8b6fc1fc62..0000000000 --- a/gapis/shadertools/cc/tests/shaders/434060f1baa60016a23927c97c8a29d9478458c2.frag.out3 +++ /dev/null @@ -1,132 +0,0 @@ -Fragment mode -compiled -linked -label 5 -action type: 1, words: 87, 88, 0, 1, -action type: 1, words: 90, 91, 0, 1, -action type: 1, words: 93, 94, 0, 1, -action type: 0, words: 19, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 22, -action type: 1, words: 29, 28, 0, 1, -action type: 0, words: 24, -action type: 1, words: 39, 9, 0, 1, -action type: 0, words: 25, -action type: 1, words: 50, 49, 0, 1, -action type: 0, words: 26, -action type: 1, words: 50, 49, 1, 1, -action type: 0, words: 27, -action type: 1, words: 57, 49, 1, 1, -action type: 0, words: 28, -action type: 1, words: 57, 49, 0, 1, -action type: 0, words: 29, -action type: 1, words: 57, 49, 0, 1, -action type: 0, words: 30, -action type: 1, words: 81, 80, 1, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform sampler2D x_MainTex; -uniform vec4 x_Color; -uniform vec4 x_WorldSpaceLightPos0; -uniform vec4 x_LightColor0; -uniform vec4 x_AddColor; -uniform usampler2D gapid_sampler; - -in vec2 xxlv_TEXCOORD0; -in vec3 xxlv_TEXCOORD1; -in vec3 xxlv_TEXCOORD2; -out vec4 xgl_FragData[32]; -out vec3 x_oxlv_TEXCOORD1; -out vec3 x_oxlv_TEXCOORD2; -out vec2 x_oxlv_TEXCOORD0; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(vec3 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), 0u)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(int value) -{ - print(uint(value)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_oxlv_TEXCOORD1 = xxlv_TEXCOORD1; - print(x_oxlv_TEXCOORD1); - x_oxlv_TEXCOORD2 = xxlv_TEXCOORD2; - print(x_oxlv_TEXCOORD2); - x_oxlv_TEXCOORD0 = xxlv_TEXCOORD0; - print(x_oxlv_TEXCOORD0); - vec3 xtmpvar_2 = (texture(x_MainTex, xxlv_TEXCOORD0).xyz * x_Color.xyz); - print(xtmpvar_2); - float xtmpvar_4 = max(0.0, dot(xxlv_TEXCOORD1, x_WorldSpaceLightPos0.xyz)); - print(xtmpvar_4); - vec3 xtmpvar_5 = (((xtmpvar_2 * x_LightColor0.xyz) * xtmpvar_4) * 2.0); - print(xtmpvar_5); - vec4 xc_3; - xc_3 = vec4(xtmpvar_5.x, xtmpvar_5.y, xtmpvar_5.z, xc_3.w); - print(xc_3); - xc_3.w = 0.0; - print(3u); - print(xc_3.w); - vec4 xc_1; - xc_1.w = xc_3.w; - print(3u); - print(xc_1.w); - vec3 _67 = xc_3.xyz + (xtmpvar_2 * xxlv_TEXCOORD2); - xc_1 = vec4(_67.x, _67.y, _67.z, xc_1.w); - print(xc_1); - vec3 _75 = xc_1.xyz + x_AddColor.xyz; - xc_1 = vec4(_75.x, _75.y, _75.z, xc_1.w); - print(xc_1); - xgl_FragData[0] = xc_1; - print(0); - print(xgl_FragData[0]); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert b/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert deleted file mode 100644 index dbb60fa954..0000000000 --- a/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert +++ /dev/null @@ -1,164 +0,0 @@ -#version 300 es - -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// __multiversion__ -#define ATLAS_TEXTURE -#define FANCY -#define LOW_PRECISION -#define SEASONS -#define TEXEL_AA -#define MAT4 lowp mat4 -#define POS4 lowp vec4 -#define POS3 lowp vec3 -precision lowp float; -// This signals the loading code to prepend either #version 100 or #version 300 es as apropriate. - -// To use centroid sampling we need to have version 300 es shaders, which requires changing: -// attribute to in -// varying to out when in vertex shaders or in when in fragment shaders -// defining an out vec4 FragColor and replacing uses of gl_FragColor with FragColor -// texture2D to texture -#if __VERSION__ >= 300 -#define attribute in -#define varying out - -#ifdef MSAA_FRAMEBUFFER_ENABLED -#define _centroid centroid -#else -#define _centroid -#endif - -_centroid out vec2 uv0; -_centroid out vec2 uv1; - -#else - -varying vec2 uv0; -varying vec2 uv1; - -#endif - - -varying vec4 color; -#ifdef FOG - varying vec4 fogColor; -#endif - -#ifdef NEAR_WATER - varying float cameraDist; -#endif - -#ifdef AS_ENTITY_RENDERER -uniform MAT4 WORLDVIEWPROJ; -#else -uniform MAT4 WORLDVIEW; -uniform MAT4 PROJ; -#endif -uniform vec4 FOG_COLOR; -uniform vec2 FOG_CONTROL; -uniform float RENDER_DISTANCE; -uniform vec2 VIEWPORT_DIMENSION; -uniform vec4 CURRENT_COLOR; //current color r contains the offset to apply to the fog for the "fade in" -uniform POS4 CHUNK_ORIGIN_AND_SCALE; -uniform POS3 VIEW_POS; -uniform float FAR_CHUNKS_DISTANCE; - -attribute POS4 POSITION; -attribute vec4 COLOR; -attribute vec2 TEXCOORD_0; -attribute vec2 TEXCOORD_1; - -const float rA = 1.0; -const float rB = 1.0; -const vec3 UNIT_Y = vec3(0,1,0); -const float DIST_DESATURATION = 56.0 / 255.0; //WARNING this value is also hardcoded in the water color, don'tchange - -void main() -{ - POS4 worldPos; -#ifdef AS_ENTITY_RENDERER - POS4 pos = WORLDVIEWPROJ * POSITION; - worldPos = pos; -#else - worldPos.xyz = (POSITION.xyz * CHUNK_ORIGIN_AND_SCALE.w) + CHUNK_ORIGIN_AND_SCALE.xyz; - worldPos.w = 1.0; - - // Transform to view space before projection instead of all at once to avoid floating point errors - // Not required for entities because they are already offset by camera translation before rendering - // World position here is calculated above and can get huge - POS4 pos = WORLDVIEW * worldPos; - pos = PROJ * pos; -#endif - gl_Position = pos; - - uv0 = TEXCOORD_0; - uv1 = TEXCOORD_1; - color = COLOR; - -///// find distance from the camera - -#if defined(FOG) || defined(NEAR_WATER) - #ifdef FANCY - vec3 relPos = -worldPos.xyz; - float cameraDepth = length(relPos); - #ifdef NEAR_WATER - cameraDist = cameraDepth / FAR_CHUNKS_DISTANCE; - #endif - #else - float cameraDepth = pos.z; - #ifdef NEAR_WATER - vec3 relPos = -worldPos.xyz; - float camDist = length(relPos); - cameraDist = camDist / FAR_CHUNKS_DISTANCE; - #endif - #endif -#endif - -///// apply fog - -#ifdef FOG - float len = cameraDepth / RENDER_DISTANCE; - #ifdef ALLOW_FADE - len += CURRENT_COLOR.r; - #endif - - fogColor.rgb = FOG_COLOR.rgb; - fogColor.a = clamp((len - FOG_CONTROL.x) / (FOG_CONTROL.y - FOG_CONTROL.x), 0.0, 1.0); -#endif - -///// water magic -#ifdef NEAR_WATER - #ifdef FANCY /////enhance water - float F = dot(normalize(relPos), UNIT_Y); - F = 1.0 - max(F, 0.1); - F = 1.0 - mix(F*F*F*F, 1.0, min(1.0, cameraDepth / FAR_CHUNKS_DISTANCE)); - - color.rg -= vec2(F * DIST_DESATURATION); - - vec4 depthColor = vec4(color.rgb * 0.5, 1.0); - vec4 traspColor = vec4(color.rgb * 0.45, 0.8); - vec4 surfColor = vec4(color.rgb, 1.0); - - vec4 nearColor = mix(traspColor, depthColor, color.a); - color = mix(surfColor, nearColor, F); - #else - // Completely insane, but if I don't have these two lines in here, the water doesn't render on a Nexus 6 - vec4 surfColor = vec4(color.rgb, 1.0); - color = surfColor; - color.a = pos.z / FAR_CHUNKS_DISTANCE + 0.5; - #endif //FANCY -#endif -} diff --git a/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert.out3 b/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert.out3 deleted file mode 100644 index bcbe282b01..0000000000 --- a/gapis/shadertools/cc/tests/shaders/6390be7dea7d9bcdef8ea7cedda537700125020e.vert.out3 +++ /dev/null @@ -1,140 +0,0 @@ -Vertex mode -compiled -linked -label 5 -action type: 1, words: 74, 75, 0, 1, -action type: 1, words: 77, 78, 0, 1, -action type: 1, words: 80, 81, 0, 1, -action type: 1, words: 83, 84, 0, 1, -action type: 1, words: 86, 87, 0, 1, -action type: 1, words: 89, 90, 0, 1, -action type: 0, words: 81, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 82, -action type: 1, words: 10, 9, 1, 1, -action type: 0, words: 87, -action type: 1, words: 32, 9, 0, 1, -action type: 0, words: 88, -action type: 1, words: 32, 9, 0, 1, -action type: 0, words: 90, -action type: 1, words: 44, 43, 0, 1, -action type: 0, words: 92, -action type: 1, words: 48, 47, 0, 1, -action type: 0, words: 93, -action type: 1, words: 52, 47, 0, 1, -action type: 0, words: 94, -action type: 1, words: 55, 43, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform vec4 xCHUNK_ORIGIN_AND_SCALE; -uniform mat4 xWORLDVIEW; -uniform mat4 xPROJ; -uniform vec4 xFOG_COLOR; -uniform vec2 xFOG_CONTROL; -uniform float xRENDER_DISTANCE; -uniform vec2 xVIEWPORT_DIMENSION; -uniform vec4 xCURRENT_COLOR; -uniform vec3 xVIEW_POS; -uniform float xFAR_CHUNKS_DISTANCE; -uniform usampler2D gapid_sampler; - -in vec4 xPOSITION; -out vec2 xuv0; -in vec2 xTEXCOORD_0; -out vec2 xuv1; -in vec2 xTEXCOORD_1; -out vec4 xcolor; -in vec4 xCOLOR; -out int x_ogl_InstanceID; -out vec4 x_oPOSITION; -out vec2 x_oTEXCOORD_0; -out vec4 x_oCOLOR; -out vec2 x_oTEXCOORD_1; -out int x_ogl_VertexID; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_ogl_InstanceID = gl_InstanceID; - print(x_ogl_InstanceID); - x_oPOSITION = xPOSITION; - print(x_oPOSITION); - x_oTEXCOORD_0 = xTEXCOORD_0; - print(x_oTEXCOORD_0); - x_oCOLOR = xCOLOR; - print(x_oCOLOR); - x_oTEXCOORD_1 = xTEXCOORD_1; - print(x_oTEXCOORD_1); - x_ogl_VertexID = gl_VertexID; - print(x_ogl_VertexID); - vec3 _26 = (xPOSITION.xyz * xCHUNK_ORIGIN_AND_SCALE.w) + xCHUNK_ORIGIN_AND_SCALE.xyz; - vec4 xworldPos; - xworldPos = vec4(_26.x, _26.y, _26.z, xworldPos.w); - print(xworldPos); - xworldPos.w = 1.0; - print(3u); - print(xworldPos.w); - vec4 xpos = (xWORLDVIEW * xworldPos); - print(xpos); - xpos = (xPROJ * xpos); - print(xpos); - gl_Position = xpos; - gl_Position.z = 2.0 * gl_Position.z - gl_Position.w; - print(gl_Position); - xuv0 = xTEXCOORD_0; - print(xuv0); - xuv1 = xTEXCOORD_1; - print(xuv1); - xcolor = xCOLOR; - print(xcolor); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert b/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert deleted file mode 100644 index 759b2f3686..0000000000 --- a/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define SHADER_API_GLES 1 -#define tex2D texture2D - - - -#define gl_ModelViewProjectionMatrix glstate_matrix_mvp -uniform mat4 glstate_matrix_mvp; - -varying highp vec2 xlv_TEXCOORD2; -varying mediump vec3 xlv_TEXCOORD1; -varying highp vec4 xlv_TEXCOORD0; - -uniform lowp vec4 _WorldSpaceLightPos0; -uniform highp mat4 _World2Object; -uniform highp mat4 _Object2World; -uniform highp vec4 _MainTex_ST; -uniform highp mat4 _LightMatrix0; -uniform highp vec4 _BumpMap_ST; -attribute vec4 _glesTANGENT; -attribute vec4 _glesMultiTexCoord0; -attribute vec3 _glesNormal; -attribute vec4 _glesVertex; -void main () -{ - vec4 tmpvar_1; - tmpvar_1.xyz = normalize (_glesTANGENT.xyz); - tmpvar_1.w = _glesTANGENT.w; - vec3 tmpvar_2; - tmpvar_2 = normalize (_glesNormal); - highp vec4 tmpvar_3; - mediump vec3 tmpvar_4; - tmpvar_3.xy = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - tmpvar_3.zw = ((_glesMultiTexCoord0.xy * _BumpMap_ST.xy) + _BumpMap_ST.zw); - highp mat3 tmpvar_5; - tmpvar_5[0] = tmpvar_1.xyz; - tmpvar_5[1] = (cross (tmpvar_2, tmpvar_1.xyz) * _glesTANGENT.w); - tmpvar_5[2] = tmpvar_2; - mat3 tmpvar_6; - tmpvar_6[0].x = tmpvar_5[0].x; - tmpvar_6[0].y = tmpvar_5[1].x; - tmpvar_6[0].z = tmpvar_5[2].x; - tmpvar_6[1].x = tmpvar_5[0].y; - tmpvar_6[1].y = tmpvar_5[1].y; - tmpvar_6[1].z = tmpvar_5[2].y; - tmpvar_6[2].x = tmpvar_5[0].z; - tmpvar_6[2].y = tmpvar_5[1].z; - tmpvar_6[2].z = tmpvar_5[2].z; - highp vec3 tmpvar_7; - tmpvar_7 = (tmpvar_6 * (_World2Object * _WorldSpaceLightPos0).xyz); - tmpvar_4 = tmpvar_7; - gl_Position = (gl_ModelViewProjectionMatrix * _glesVertex); - xlv_TEXCOORD0 = tmpvar_3; - xlv_TEXCOORD1 = tmpvar_4; - xlv_TEXCOORD2 = (_LightMatrix0 * (_Object2World * _glesVertex)).xy; -} - - - diff --git a/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert.out3 b/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert.out3 deleted file mode 100644 index 0559aacfdb..0000000000 --- a/gapis/shadertools/cc/tests/shaders/97b7e64fe6c5c0016c5a1c1d94f2f26df319a113.vert.out3 +++ /dev/null @@ -1,229 +0,0 @@ -Vertex mode -compiled -linked -label 5 -action type: 1, words: 152, 153, 0, 1, -action type: 1, words: 155, 156, 0, 1, -action type: 1, words: 158, 159, 0, 1, -action type: 1, words: 161, 162, 0, 1, -action type: 1, words: 164, 165, 0, 1, -action type: 1, words: 167, 168, 0, 1, -action type: 0, words: 27, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 28, -action type: 1, words: 10, 9, 1, 1, -action type: 0, words: 30, -action type: 1, words: 27, 26, 0, 1, -action type: 0, words: 33, -action type: 1, words: 32, 9, 0, 1, -action type: 0, words: 34, -action type: 1, words: 32, 9, 0, 1, -action type: 0, words: 36, -action type: 1, words: 60, 59, 1, 1, -action type: 0, words: 37, -action type: 1, words: 60, 59, 1, 1, -action type: 0, words: 38, -action type: 1, words: 60, 59, 1, 1, -action type: 0, words: 40, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 41, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 42, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 43, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 44, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 45, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 46, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 47, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 48, -action type: 1, words: 78, 59, 2, 1, -action type: 0, words: 50, -action type: 1, words: 109, 26, 0, 1, -action type: 0, words: 51, -action type: 1, words: 120, 26, 0, 1, -action type: 0, words: 52, -action type: 1, words: 126, 125, 1, 1, -action type: 0, words: 53, -action type: 1, words: 134, 132, 0, 1, -action type: 0, words: 54, -action type: 1, words: 137, 136, 0, 1, -action type: 0, words: 55, -action type: 1, words: 140, 139, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform vec4 x_MainTex_ST; -uniform vec4 x_BumpMap_ST; -uniform mat4 x_World2Object; -uniform vec4 x_WorldSpaceLightPos0; -uniform mat4 xglstate_matrix_mvp; -uniform mat4 x_LightMatrix0; -uniform mat4 x_Object2World; -uniform usampler2D gapid_sampler; - -in vec4 x_glesTANGENT; -in vec3 x_glesNormal; -in vec4 x_glesMultiTexCoord0; -in vec4 x_glesVertex; -out vec4 xxlv_TEXCOORD0; -out vec3 xxlv_TEXCOORD1; -out vec2 xxlv_TEXCOORD2; -out int x_ogl_VertexID; -out int x_ogl_InstanceID; -out vec3 x_o_glesNormal; -out vec4 x_o_glesVertex; -out vec4 x_o_glesTANGENT; -out vec4 x_o_glesMultiTexCoord0; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void print(vec3 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), 0u)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_ogl_VertexID = gl_VertexID; - print(x_ogl_VertexID); - x_ogl_InstanceID = gl_InstanceID; - print(x_ogl_InstanceID); - x_o_glesNormal = x_glesNormal; - print(x_o_glesNormal); - x_o_glesVertex = x_glesVertex; - print(x_o_glesVertex); - x_o_glesTANGENT = x_glesTANGENT; - print(x_o_glesTANGENT); - x_o_glesMultiTexCoord0 = x_glesMultiTexCoord0; - print(x_o_glesMultiTexCoord0); - vec3 _16 = normalize(x_glesTANGENT.xyz); - vec4 xtmpvar_1; - xtmpvar_1 = vec4(_16.x, _16.y, _16.z, xtmpvar_1.w); - print(xtmpvar_1); - xtmpvar_1.w = x_glesTANGENT.w; - print(3u); - print(xtmpvar_1.w); - vec3 xtmpvar_2 = normalize(x_glesNormal); - print(xtmpvar_2); - vec2 _44 = (x_glesMultiTexCoord0.xy * x_MainTex_ST.xy) + x_MainTex_ST.zw; - vec4 xtmpvar_3; - xtmpvar_3 = vec4(_44.x, _44.y, xtmpvar_3.z, xtmpvar_3.w); - print(xtmpvar_3); - vec2 _55 = (x_glesMultiTexCoord0.xy * x_BumpMap_ST.xy) + x_BumpMap_ST.zw; - xtmpvar_3 = vec4(xtmpvar_3.x, xtmpvar_3.y, _55.x, _55.y); - print(xtmpvar_3); - mat3 xtmpvar_5; - xtmpvar_5[0] = xtmpvar_1.xyz; - print(0); - print(xtmpvar_5[0]); - xtmpvar_5[1] = (cross(xtmpvar_2, xtmpvar_1.xyz) * x_glesTANGENT.w); - print(1); - print(xtmpvar_5[1]); - xtmpvar_5[2] = xtmpvar_2; - print(2); - print(xtmpvar_5[2]); - mat3 xtmpvar_6; - xtmpvar_6[0].x = xtmpvar_5[0].x; - print(0); - print(0u); - print(xtmpvar_6[0].x); - xtmpvar_6[0].y = xtmpvar_5[1].x; - print(0); - print(1u); - print(xtmpvar_6[0].y); - xtmpvar_6[0].z = xtmpvar_5[2].x; - print(0); - print(2u); - print(xtmpvar_6[0].z); - xtmpvar_6[1].x = xtmpvar_5[0].y; - print(1); - print(0u); - print(xtmpvar_6[1].x); - xtmpvar_6[1].y = xtmpvar_5[1].y; - print(1); - print(1u); - print(xtmpvar_6[1].y); - xtmpvar_6[1].z = xtmpvar_5[2].y; - print(1); - print(2u); - print(xtmpvar_6[1].z); - xtmpvar_6[2].x = xtmpvar_5[0].z; - print(2); - print(0u); - print(xtmpvar_6[2].x); - xtmpvar_6[2].y = xtmpvar_5[1].z; - print(2); - print(1u); - print(xtmpvar_6[2].y); - xtmpvar_6[2].z = xtmpvar_5[2].z; - print(2); - print(2u); - print(xtmpvar_6[2].z); - vec3 xtmpvar_7 = (xtmpvar_6 * (x_World2Object * x_WorldSpaceLightPos0).xyz); - print(xtmpvar_7); - vec3 xtmpvar_4 = xtmpvar_7; - print(xtmpvar_4); - gl_Position = (xglstate_matrix_mvp * x_glesVertex); - gl_Position.z = 2.0 * gl_Position.z - gl_Position.w; - print(0); - print(gl_Position); - xxlv_TEXCOORD0 = xtmpvar_3; - print(xxlv_TEXCOORD0); - xxlv_TEXCOORD1 = xtmpvar_4; - print(xxlv_TEXCOORD1); - xxlv_TEXCOORD2 = (x_LightMatrix0 * (x_Object2World * x_glesVertex)).xy; - print(xxlv_TEXCOORD2); -} - - -spirv-cross OK diff --git a/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert b/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert deleted file mode 100644 index b782f0e8a3..0000000000 --- a/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#define SHADER_API_GLES 1 -#define tex2D texture2D - - - -#define gl_ModelViewProjectionMatrix glstate_matrix_mvp -uniform mat4 glstate_matrix_mvp; - -varying highp vec4 xlv_TEXCOORD2; -varying highp vec2 xlv_TEXCOORD1; -varying highp vec2 xlv_TEXCOORD0; -uniform highp vec4 unity_LightmapST; - -uniform highp vec4 _ProjectionParams; -uniform highp vec4 _MainTex_ST; -attribute vec4 _glesMultiTexCoord1; -attribute vec4 _glesMultiTexCoord0; -attribute vec4 _glesVertex; -void main () -{ - highp vec4 tmpvar_1; - tmpvar_1 = (gl_ModelViewProjectionMatrix * _glesVertex); - highp vec4 o_i0; - highp vec4 tmpvar_2; - tmpvar_2 = (tmpvar_1 * 0.5); - o_i0 = tmpvar_2; - highp vec2 tmpvar_3; - tmpvar_3.x = tmpvar_2.x; - tmpvar_3.y = (tmpvar_2.y * _ProjectionParams.x); - o_i0.xy = (tmpvar_3 + tmpvar_2.w); - o_i0.zw = tmpvar_1.zw; - gl_Position = tmpvar_1; - xlv_TEXCOORD0 = ((_glesMultiTexCoord0.xy * _MainTex_ST.xy) + _MainTex_ST.zw); - xlv_TEXCOORD1 = ((_glesMultiTexCoord1.xy * unity_LightmapST.xy) + unity_LightmapST.zw); - xlv_TEXCOORD2 = o_i0; -} - - - diff --git a/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert.out3 b/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert.out3 deleted file mode 100644 index 749af2c49b..0000000000 --- a/gapis/shadertools/cc/tests/shaders/9911db668374bd88249acd0600179fb0ce42c93d.vert.out3 +++ /dev/null @@ -1,143 +0,0 @@ -Vertex mode -compiled -linked -label 5 -action type: 1, words: 94, 95, 0, 1, -action type: 1, words: 97, 98, 0, 1, -action type: 1, words: 100, 101, 0, 1, -action type: 1, words: 103, 104, 0, 1, -action type: 1, words: 106, 107, 0, 1, -action type: 0, words: 23, -action type: 1, words: 10, 9, 0, 1, -action type: 0, words: 26, -action type: 1, words: 19, 9, 0, 1, -action type: 0, words: 27, -action type: 1, words: 23, 9, 0, 1, -action type: 0, words: 29, -action type: 1, words: 27, 26, 1, 1, -action type: 0, words: 30, -action type: 1, words: 27, 26, 1, 1, -action type: 0, words: 31, -action type: 1, words: 23, 9, 0, 1, -action type: 0, words: 32, -action type: 1, words: 23, 9, 0, 1, -action type: 0, words: 33, -action type: 1, words: 60, 59, 1, 1, -action type: 0, words: 34, -action type: 1, words: 67, 66, 0, 1, -action type: 0, words: 35, -action type: 1, words: 78, 66, 0, 1, -action type: 0, words: 36, -action type: 1, words: 89, 64, 0, 1, -Decompiled: -#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -uniform mat4 xglstate_matrix_mvp; -uniform vec4 x_ProjectionParams; -uniform vec4 x_MainTex_ST; -uniform vec4 xunity_LightmapST; -uniform usampler2D gapid_sampler; - -in vec4 x_glesVertex; -out vec2 xxlv_TEXCOORD0; -in vec4 x_glesMultiTexCoord0; -out vec2 xxlv_TEXCOORD1; -in vec4 x_glesMultiTexCoord1; -out vec4 xxlv_TEXCOORD2; -out int x_ogl_InstanceID; -out vec4 x_o_glesMultiTexCoord0; -out vec4 x_o_glesMultiTexCoord1; -out vec4 x_o_glesVertex; -out int x_ogl_VertexID; -out uvec4 gapid_result; -in vec2 gapid_coor; -uint gapid_curr_step; - -void print(uvec4 value) -{ - gapid_curr_step = (gapid_curr_step - 1u); - if ((gapid_curr_step == 0u)) - { - gapid_result = value; - } -} - -void label(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(uint value) -{ - print(uvec4(value, 0u, 0u, 0u)); -} - -void print(int value) -{ - print(uint(value)); -} - -void print(vec4 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), floatBitsToUint(value.z), floatBitsToUint(value.w))); -} - -void print(float value) -{ - print(floatBitsToUint(value)); -} - -void print(vec2 value) -{ - print(uvec4(floatBitsToUint(value.x), floatBitsToUint(value.y), 0u, 0u)); -} - -void main() -{ - gapid_curr_step = texture(gapid_sampler, gapid_coor).x; - label(5u); - x_ogl_InstanceID = gl_InstanceID; - print(x_ogl_InstanceID); - x_o_glesMultiTexCoord0 = x_glesMultiTexCoord0; - print(x_o_glesMultiTexCoord0); - x_o_glesMultiTexCoord1 = x_glesMultiTexCoord1; - print(x_o_glesMultiTexCoord1); - x_o_glesVertex = x_glesVertex; - print(x_o_glesVertex); - x_ogl_VertexID = gl_VertexID; - print(x_ogl_VertexID); - vec4 xtmpvar_1 = (xglstate_matrix_mvp * x_glesVertex); - print(xtmpvar_1); - vec4 xtmpvar_2 = (xtmpvar_1 * 0.5); - print(xtmpvar_2); - vec4 xo_i0 = xtmpvar_2; - print(xo_i0); - vec2 xtmpvar_3; - xtmpvar_3.x = xtmpvar_2.x; - print(0u); - print(xtmpvar_3.x); - xtmpvar_3.y = (xtmpvar_2.y * x_ProjectionParams.x); - print(1u); - print(xtmpvar_3.y); - vec2 _49 = xtmpvar_3 + vec2(xtmpvar_2.w); - xo_i0 = vec4(_49.x, _49.y, xo_i0.z, xo_i0.w); - print(xo_i0); - xo_i0 = vec4(xo_i0.x, xo_i0.y, xtmpvar_1.zw.x, xtmpvar_1.zw.y); - print(xo_i0); - gl_Position = xtmpvar_1; - gl_Position.z = 2.0 * gl_Position.z - gl_Position.w; - print(0); - print(gl_Position); - xxlv_TEXCOORD0 = ((x_glesMultiTexCoord0.xy * x_MainTex_ST.xy) + x_MainTex_ST.zw); - print(xxlv_TEXCOORD0); - xxlv_TEXCOORD1 = ((x_glesMultiTexCoord1.xy * xunity_LightmapST.xy) + xunity_LightmapST.zw); - print(xxlv_TEXCOORD1); - xxlv_TEXCOORD2 = xo_i0; - print(xxlv_TEXCOORD2); -} - - -spirv-cross OK diff --git a/gapis/shadertools/shadertools.go b/gapis/shadertools/shadertools.go index 1cf597613b..fbb502bfde 100644 --- a/gapis/shadertools/shadertools.go +++ b/gapis/shadertools/shadertools.go @@ -21,7 +21,6 @@ package shadertools import "C" import ( - "bytes" "fmt" "sort" "strings" @@ -34,44 +33,6 @@ import ( var mutex sync.Mutex -// Instruction represents a SPIR-V instruction. -type Instruction struct { - ID uint32 // Result identifer. - Opcode uint32 // Opcode. - Words []uint32 // Operands. - Name string // Optional symbol name. -} - -// CodeWithDebugInfo is the result returned by ConvertGlsl. -type CodeWithDebugInfo struct { - SourceCode string // Modified GLSL. - DisassemblyString string // Diassembly of modified GLSL. - Info []Instruction // A set of SPIR-V debug instructions. -} - -// FormatDebugInfo returns the instructions as a string. -func FormatDebugInfo(insts []Instruction, linePrefix string) string { - var buffer bytes.Buffer - for _, inst := range insts { - buffer.WriteString(linePrefix) - if inst.ID != 0 { - buffer.WriteString(fmt.Sprintf("%%%-5v = ", inst.ID)) - } else { - buffer.WriteString(fmt.Sprintf(" = ")) - } - buffer.WriteString("Op") - buffer.WriteString(OpcodeToString(inst.Opcode)) - for _, word := range inst.Words { - buffer.WriteString(fmt.Sprintf(" %v", word)) - } - if inst.Name != "" { - buffer.WriteString(fmt.Sprintf(" \"%v\"", inst.Name)) - } - buffer.WriteString("\n") - } - return buffer.String() -} - // ShaderType is the enumerator of shader types. type ShaderType int @@ -112,113 +73,6 @@ func (t ShaderType) String() string { } } -// ConvertOptions controls how ConvertGlsl converts its passed-in GLSL source code. -type ConvertOptions struct { - // The type of shader. - ShaderType ShaderType - // The target GLSL version (default 330). - TargetGLSLVersion int - // Shader source preamble. - Preamble string - // Whether to add prefix to all non-builtin symbols. - PrefixNames bool - // The name prefix to be added to all non-builtin symbols. - NamesPrefix string /* optional */ - // Whether to create a corresponding output variable for each input variable. - AddOutputsForInputs bool - // The name prefix of added output variables. - OutputPrefix string /* optional */ - // Whether to make the generated GLSL code debuggable. - MakeDebuggable bool - // Whether to check the generated GLSL code compiles again. - CheckAfterChanges bool - // Whether to disassemble the generated GLSL code. - Disassemble bool - // If true, let some minor invalid statements compile. - Relaxed bool - // If true, optimizations that require high-end GL versions, or extensions - // will be stripped. These optimizations should have no impact on the end - // result of the shader, but may impact performance. - // Example: Early Fragment Test. - StripOptimizations bool -} - -// ConvertGlsl modifies the given GLSL according to the options specified via -// o and returns the modification status and result. Possible modifications -// includes creating output variables for input variables, prefixing all -// non-builtin symbols with a given prefix, etc. -func ConvertGlsl(source string, o *ConvertOptions) (CodeWithDebugInfo, error) { - toFree := []unsafe.Pointer{} - defer func() { - for _, ptr := range toFree { - C.free(ptr) - } - }() - - mutex.Lock() - defer mutex.Unlock() - - cstr := func(s string) *C.char { - out := C.CString(s) - toFree = append(toFree, unsafe.Pointer(out)) - return out - } - - opts := C.struct_convert_options_t{ - shader_type: C.shader_type(o.ShaderType), - preamble: cstr(o.Preamble), - prefix_names: C.bool(o.PrefixNames), - names_prefix: cstr(o.NamesPrefix), - add_outputs_for_inputs: C.bool(o.AddOutputsForInputs), - output_prefix: cstr(o.OutputPrefix), - make_debuggable: C.bool(o.MakeDebuggable), - check_after_changes: C.bool(o.CheckAfterChanges), - disassemble: C.bool(o.Disassemble), - relaxed: C.bool(o.Relaxed), - strip_optimizations: C.bool(o.StripOptimizations), - target_glsl_version: C.int(o.TargetGLSLVersion), - } - result := C.convertGlsl(cstr(source), C.size_t(len(source)), &opts) - defer C.deleteGlslCodeWithDebug(result) - - ret := CodeWithDebugInfo{ - SourceCode: C.GoString(result.source_code), - DisassemblyString: C.GoString(result.disassembly_string), - } - - if result.info != nil { - cInsts := (*[1 << 30]C.struct_instruction_t)(unsafe.Pointer(result.info.insts)) - for i := 0; i < int(result.info.insts_num); i++ { - cInst := cInsts[i] - inst := Instruction{ - ID: uint32(cInst.id), - Opcode: uint32(cInst.opcode), - Words: make([]uint32, 0, cInst.words_num), - Name: C.GoString(cInst.name), - } - cWords := (*[1 << 30]C.uint32_t)(unsafe.Pointer(cInst.words)) - for j := 0; j < int(cInst.words_num); j++ { - inst.Words = append(inst.Words, uint32(cWords[j])) - } - ret.Info = append(ret.Info, inst) - } - } - - if !result.ok { - msg := []string{ - fmt.Sprintf("Failed to convert %v shader.", o.ShaderType), - } - if m := C.GoString(result.message); len(m) > 0 { - msg = append(msg, m) - } - msg = append(msg, "Translated source:", text.LineNumber(C.GoString(result.source_code))) - msg = append(msg, "Original source:", text.LineNumber(source)) - return ret, fault.Const(strings.Join(msg, "\n")) - } - - return ret, nil -} - // DisassembleSpirvBinary disassembles the given SPIR-V binary words by calling // SPIRV-Tools and returns the disassembly. Returns an empty string if // diassembling fails. @@ -255,11 +109,6 @@ func AssembleSpirvText(chars string) []uint32 { return words } -// OpcodeToString converts opcode number to human readable string. -func OpcodeToString(opcode uint32) string { - return C.GoString(C.opcodeToString(C.uint32_t(opcode))) -} - // CompileOptions controls how CompileGlsl compile its passed-in GLSL source code. type CompileOptions struct { // The type of shader. diff --git a/gapis/shadertools/shadertools_test.go b/gapis/shadertools/shadertools_test.go index 6af8e5e9b3..bc8b557ce7 100644 --- a/gapis/shadertools/shadertools_test.go +++ b/gapis/shadertools/shadertools_test.go @@ -22,73 +22,6 @@ import ( "github.com/google/gapid/gapis/shadertools" ) -func TestConvertGlsl(t *testing.T) { - for _, test := range []struct { - desc string - opts shadertools.ConvertOptions - src string - expected string - }{ - { - "Test shadertools propagates early_fragment_tests", - shadertools.ConvertOptions{ - ShaderType: shadertools.TypeFragment, - CheckAfterChanges: true, - }, - `#version 310 es -layout(early_fragment_tests) in; -out highp vec4 color; -void main() { color = vec4(1., 1., 1., 1.); }`, - `#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif -#extension GL_ARB_shader_image_load_store : require -layout(early_fragment_tests) in; - -out vec4 color; - -void main() -{ - color = vec4(1.0); -} - -`}, { - "Test shadertools strips early_fragment_tests", - shadertools.ConvertOptions{ - ShaderType: shadertools.TypeFragment, - CheckAfterChanges: true, - StripOptimizations: true, - TargetGLSLVersion: 330, - }, - `#version 310 es -layout(early_fragment_tests) in; -out highp vec4 color; -void main() { color = vec4(1., 1., 1., 1.); }`, - `#version 330 -#ifdef GL_ARB_shading_language_420pack -#extension GL_ARB_shading_language_420pack : require -#endif - -out vec4 color; - -void main() -{ - color = vec4(1.0); -} - -`}, - } { - t.Run(test.desc, func(t *testing.T) { - ctx := log.Testing(t) - out, err := shadertools.ConvertGlsl(test.src, &test.opts) - if assert.For(ctx, "err").ThatError(err).Succeeded() { - assert.For(ctx, "src").ThatString(out.SourceCode).Equals(test.expected) - } - }) - } -} - func TestCompileGlsl(t *testing.T) { for _, test := range []struct { desc string From ab8fc912b2eed7f2836d0cfa0e74d49ccd4aaaaf Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 23 Mar 2020 15:16:50 -0700 Subject: [PATCH 0180/1218] Update the main README for AGI. Removes the outdated GAPID stuff and points people to the shiny new website. --- README.md | 59 +++---------------------------------------------------- 1 file changed, 3 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 66f8113b8b..edf514f80b 100644 --- a/README.md +++ b/README.md @@ -15,74 +15,21 @@ -## Documentation +## About -**[User documentation can be found at gpuinspector.dev](https://gpuinspector.dev)** +Visit [gpuinspector.dev](https://gpuinspector.dev) for information about Android GPU Inspector. The [developer documentation](DEVDOC.md) contains some hints for AGI developers. See also the README files under some source directories. -## About - -Android GPU Inspector is a collection of tools that allows you to inspect, tweak and replay calls from an application to a graphics driver. - -Android GPU Inspector can trace any Android [debuggable application](https://developer.android.com/guide/topics/manifest/application-element.html#debug), or if you have root access to the device any application can be traced. -AGI can also trace any desktop Vulkan application. - -

- - Screenshot 1 + + Screenshot 1 - - Screenshot 2 + + Screenshot 2
- - Screenshot 3 + + Screenshot 3 - - Screenshot 4 + + Screenshot 4
- - - - - - - - -
- - Screenshot 1 - - - - Screenshot 2 - -
- - Screenshot 3 - - - - Screenshot 4 - -
- ## Building **See [Building Android GPU Inspector](BUILDING.md).** ## Running the client -After building AGI, you can run the client from `/bazel-bin/pkg/gapid`. +After building AGI, you can run the client from `/bazel-bin/pkg/agi`. ## Command-Line Interface AGI exposes most of its functionality via a CLI *gapit*. You can find auto-generated documentation [here](https://gpuinspector.dev/cli/). - -## Project Structure - -Android GPU Inspector consists of the following sub-components: - -### [`gapii`](gapii): Graphics API Interceptor -A layer that sits between the application / game and the GPU driver, recording all the calls and memory accesses. - -### [`gapis`](gapis): Graphics API Server -A process that analyses capture streams reporting incorrect API usage, processes the data for replay on various target devices, and provides an RPC interface to the client. - -### [`gapir`](gapir): Graphics API Replay daemon -A stack-based VM used to playback capture files, imitating the original application’s / game's calls to the GPU driver. Supports read-back of any buffer / framebuffer, and provides profiling functionality. - -### [`gapic`](gapic): Graphics API Client -The frontend user interface application. Provides visual inspection of the capture data, memory, resources, and frame-buffer content. - -### [`gapil`](gapil): Graphics API Language -A new domain specific language to describe a graphics API in its entirety. Combined with our template system to generate huge parts of the interceptor, server and replay systems. From fde332f3f56e83f6c9c0a34b52dc4d3c9e0f5841 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 23 Mar 2020 20:22:44 -0700 Subject: [PATCH 0181/1218] Reserve mapped memory at state initialization Previously, if device memory was mapped prior to MEC start, the allocator was not informed that the memory range was in use. This led to other memory allocations and/or mappings being placed over the top. This would lead to quiet memory corruption in the common case, or if we got unlucky and placed another memory mapping over the same range, bizarre explosions when eventually trying to unmap & delete pre-MEC-start device memory object. Fixes Swiftshader 'UnmapMemory' crash on Swarming. Bug: b/151297033 --- gapis/api/state.go | 2 +- gapis/api/test/test.go | 2 +- gapis/api/transform/transforms.go | 2 +- gapis/api/vulkan/frame_loop.go | 2 +- gapis/api/vulkan/vulkan.go | 11 ++++++++++- gapis/capture/graphics.go | 2 +- gapis/replay/batch.go | 4 ++-- .../resolve/dependencygraph2/dependency_graph_test.go | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/gapis/api/state.go b/gapis/api/state.go index 353b5d78e0..ccefeb5ecf 100644 --- a/gapis/api/state.go +++ b/gapis/api/state.go @@ -87,7 +87,7 @@ type State interface { // SetupInitialState sanitizes deserialized state to make it valid. // It can fill in any derived data which we choose not to serialize, // or it can apply backward-compatibility fixes for older traces. - SetupInitialState(ctx context.Context) + SetupInitialState(ctx context.Context, state *GlobalState) } // NewStateWithEmptyAllocator returns a new, default-initialized State object, diff --git a/gapis/api/test/test.go b/gapis/api/test/test.go index 246186e850..b4e6b4637c 100644 --- a/gapis/api/test/test.go +++ b/gapis/api/test/test.go @@ -50,7 +50,7 @@ func (s *State) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) // SetupInitialState sanitizes deserialized state to make it valid. // It can fill in any derived data which we choose not to serialize, // or it can apply backward-compatibility fixes for older traces. -func (*State) SetupInitialState(ctx context.Context) {} +func (*State) SetupInitialState(ctx context.Context, state *api.GlobalState) {} func (i Remapped) remap(cmd api.Cmd, s *api.GlobalState) (interface{}, bool) { return i, true diff --git a/gapis/api/transform/transforms.go b/gapis/api/transform/transforms.go index bd0ba4821d..54169353fe 100644 --- a/gapis/api/transform/transforms.go +++ b/gapis/api/transform/transforms.go @@ -35,7 +35,7 @@ func (l Transforms) TransformAll(ctx context.Context, cmds []api.Cmd, numberOfIn newState.Memory = s.Memory.Clone() for k, v := range s.APIs { clonedState := v.Clone(newState.Arena) - clonedState.SetupInitialState(ctx) + clonedState.SetupInitialState(ctx, newState) newState.APIs[k] = clonedState } s = newState diff --git a/gapis/api/vulkan/frame_loop.go b/gapis/api/vulkan/frame_loop.go index 1b6afc0eba..437efaadb7 100644 --- a/gapis/api/vulkan/frame_loop.go +++ b/gapis/api/vulkan/frame_loop.go @@ -533,7 +533,7 @@ func (f *frameLoop) cloneState(ctx context.Context, startState *api.GlobalState) for apiState, graphicsApi := range startState.APIs { clonedState := graphicsApi.Clone(clone.Arena) - clonedState.SetupInitialState(ctx) + clonedState.SetupInitialState(ctx, clone) clone.APIs[apiState] = clonedState } diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index 5abc3f0da4..e139c65bf8 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -20,6 +20,7 @@ import ( "github.com/google/gapid/core/app/status" "github.com/google/gapid/core/log" + "github.com/google/gapid/core/math/interval" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/api/sync" "github.com/google/gapid/gapis/api/transform" @@ -66,8 +67,16 @@ func (*State) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) (p // SetupInitialState recreates the command lamdas from the state block. // These are not encoded so we have to set them up here. -func (s *State) SetupInitialState(ctx context.Context) { +func (s *State) SetupInitialState(ctx context.Context, state *api.GlobalState) { s.customState.init(s) + + // Reserve memory for mapped ranges + for _, dm := range s.DeviceMemories().All() { + if uint64(dm.MappedLocation()) != uint64(0) { + state.ReserveMemory([]interval.U64Range{ + interval.U64Range{First: uint64(dm.MappedLocation()), Count: uint64(dm.MappedSize())}}) + } + } } func (API) GetFramebufferAttachmentInfo( diff --git a/gapis/capture/graphics.go b/gapis/capture/graphics.go index 40fb69f666..d6db562b10 100644 --- a/gapis/capture/graphics.go +++ b/gapis/capture/graphics.go @@ -150,7 +150,7 @@ func (c *GraphicsCapture) NewState(ctx context.Context) *api.GlobalState { // Clone serialized state, and initialize it for use. for k, v := range c.InitialState.APIs { s := v.Clone(out.Arena) - s.SetupInitialState(ctx) + s.SetupInitialState(ctx, out) out.APIs[k.ID()] = s } } diff --git a/gapis/replay/batch.go b/gapis/replay/batch.go index af8453402c..e913d65904 100644 --- a/gapis/replay/batch.go +++ b/gapis/replay/batch.go @@ -178,7 +178,7 @@ func (r *InitialPayloadResolvable) Resolve( // Clone serialized state, and initialize it for use. for k, v := range out.state.APIs { s := v.Clone(generatedState.Arena) - s.SetupInitialState(ctx) + s.SetupInitialState(ctx, out.state) generatedState.APIs[k] = s } @@ -313,7 +313,7 @@ func (m *manager) execute( // Clone serialized state, and initialize it for use. for k, v := range depState.APIs { s := v.Clone(initState.Arena) - s.SetupInitialState(ctx) + s.SetupInitialState(ctx, initState) initState.APIs[k] = s } } diff --git a/gapis/resolve/dependencygraph2/dependency_graph_test.go b/gapis/resolve/dependencygraph2/dependency_graph_test.go index e21474ff8f..92d372ed59 100644 --- a/gapis/resolve/dependencygraph2/dependency_graph_test.go +++ b/gapis/resolve/dependencygraph2/dependency_graph_test.go @@ -78,7 +78,7 @@ func (TestRef) Root(ctx context.Context, p *path.State, r *path.ResolveConfig) ( return nil, nil } -func (TestRef) SetupInitialState(ctx context.Context) {} +func (TestRef) SetupInitialState(ctx context.Context, state *api.GlobalState) {} func newTestRef() TestRef { return TestRef{api.NewRefID()} From 856d04c43e6ee86c7834693f3c6e9d7624869c0e Mon Sep 17 00:00:00 2001 From: purvisa-at-google-com <51710753+purvisa-at-google-com@users.noreply.github.com> Date: Tue, 24 Mar 2020 16:46:54 +0000 Subject: [PATCH 0182/1218] New fast debug validity check for dispatching API calls (#151) --- gapis/api/templates/specific_gfx_api.cpp.tmpl | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/gapis/api/templates/specific_gfx_api.cpp.tmpl b/gapis/api/templates/specific_gfx_api.cpp.tmpl index 3e803966a3..a84f01a102 100644 --- a/gapis/api/templates/specific_gfx_api.cpp.tmpl +++ b/gapis/api/templates/specific_gfx_api.cpp.tmpl @@ -145,7 +145,13 @@ {{$args := (GetAnnotation $ "indirect").Arguments}} {{$elem := (index $.CallParameters 0).Name}} {{$func := Macro "CmdName" $}} - if ({{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}}) { + if ( + #ifndef NDEBUG + {{Template "GetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}} + #else + {{Template "FastGetIndirectedFunction" "Annotations" $args "Element" $elem "Function" $func}} + #endif + ) { {{else}} if (mFunctionStubs.{{$name}} != nullptr) { {{end}} @@ -246,6 +252,28 @@ {{end}} +{{/* +------------------------------------------------------------------------------- + Emits a *reduced* validity check for an indirected function pointer. + Only check if element is not "null" handle. +------------------------------------------------------------------------------- +*/}} +{{define "FastGetIndirectedFunction"}} + {{AssertType $.Element "string"}} + {{$annotation := index $.Annotations 0}} + {{if eq (len $.Annotations) 1}} + {{$.Element}} != 0 + {{else}} + {{$next_annotation := index $.Annotations 1}} + {{$from_class := Title $annotation}} + {{$to_class := Title $next_annotation}} + {{$.Element}} != 0 && + {{$next_elements := Macro "ComposeIndirectMap" "FromClass" (print $from_class) "ToClass" (print $to_class) "Element" $.Element}} + {{Template "FastGetIndirectedFunction" "Annotations" (Tail 1 $.Annotations) "Element" (print $next_elements) "Function" $.Function}} + {{end}} +{{end}} + + {{/* ------------------------------------------------------------------------------- Emits a reference to a function pointer to an indirected function. From 4e61d1348b09721f6da0ea1d36da94c621d4b243 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 24 Mar 2020 22:20:01 +0000 Subject: [PATCH 0183/1218] Trigger a swarming test from Kokoro (#56) Bug: b/140545579 --- kokoro/linux/build.sh | 46 ++++++++++++++++ kokoro/linux/common.cfg | 15 ++++++ test/swarming/task-files/task.sh | 90 ++++++++++++++++++++++++++++++++ test/swarming/task.isolate | 11 ++++ 4 files changed, 162 insertions(+) create mode 100755 test/swarming/task-files/task.sh create mode 100644 test/swarming/task.isolate diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index b441580d76..8acda4b2a6 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -85,6 +85,52 @@ set -e mkdir $BUILD_ROOT/out $SRC/kokoro/linux/package.sh $BUILD_ROOT/out +############################################################################### +## Build is done, run some tests + +## +## Test on a real device using swarming. APKs are stoed on x20, under: +## teams/android-graphics-tools/agi/kokoro/swarming/apk/*.apk +## + +# Install LUCI +curl -fsSL -o luci-py.tar.gz https://chromium.googlesource.com/infra/luci/luci-py.git/+archive/0b027452e658080df1f174c403946914443d2aa6.tar.gz +mkdir luci-py +tar xzvf luci-py.tar.gz --directory luci-py +LUCI_CLIENT_ROOT="$PWD/luci-py/client" + +# Credentials come from Keystore +SWARMING_AUTH_TOKEN_FILE=${KOKORO_KEYSTORE_DIR}/74894_kokoro_swarming_access_key + +# Prepare task files +TASK_FILES_DIR=${SRC}/test/swarming/task-files +cp -r bazel-bin/pkg ${TASK_FILES_DIR}/agi +cp -r ${KOKORO_GFILE_DIR}/apk ${TASK_FILES_DIR}/ + +# Trigger task +AUTH_FLAG="--auth-service-account-json=$SWARMING_AUTH_TOKEN_FILE" +TASK_NAME="Kokoro_PR${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" +ISOLATE_SERVER='https://chrome-isolated.appspot.com' +SWARMING_SERVER='https://chrome-swarming.appspot.com' +SWARMING_POOL='SkiaInternal' +DEVICE_TYPE="flame" # pixel4 + +$LUCI_CLIENT_ROOT/isolate.py archive $AUTH_FLAG --isolate-server $ISOLATE_SERVER --isolate ${SRC}/test/swarming/task.isolate --isolated task.isolated +ISOLATED_SHA=`sha1sum task.isolated | awk '{ print $1 }' ` + +# Priority: lower is more priority, defaults to 200: PR short test tasks should be of higher priority than the default +PRIORITY=100 +# Hard timeout: maximum number of seconds for the task to terminate +HARD_TIMEOUT=300 +# Expiration: number of seconds to wait for a bot to be available +EXPIRATION=600 + +$LUCI_CLIENT_ROOT/swarming.py trigger $AUTH_FLAG --swarming $SWARMING_SERVER --isolate-server $ISOLATE_SERVER --isolated $ISOLATED_SHA --task-name ${TASK_NAME} --dump-json task.json --dimension pool $SWARMING_POOL --dimension device_type "$DEVICE_TYPE" --priority=$PRIORITY --expiration=$EXPIRATION --hard-timeout=$HARD_TIMEOUT + +# Collect task results: if the task failed, then the 'swarming.py collect' +# command returns non-zero, making the build fail. +$LUCI_CLIENT_ROOT/swarming.py collect $AUTH_FLAG --swarming $SWARMING_SERVER --json task.json --task-summary-json summary.json + ## ## Test capture and replay of the Vulkan Sample App. ## diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index 8d5b475456..028eb61e89 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -13,6 +13,21 @@ # limitations under the License. build_file: "agi/kokoro/linux/build.sh" + +# Contents of this x20 directory will be under ${KOKORO_GFILE_DIR} +# in the build script. +gfile_resources: "/x20/teams/android-graphics-tools/agi/kokoro/swarming" + +before_action { + fetch_keystore { + keystore_resource { + keystore_config_id: 74894 + # Credentials for Swarming and Isolate + keyname: "kokoro_swarming_access_key" + } + } +} + action { define_artifacts { regex: "out/dist/agi*.deb" diff --git a/test/swarming/task-files/task.sh b/test/swarming/task-files/task.sh new file mode 100755 index 0000000000..daa755ee59 --- /dev/null +++ b/test/swarming/task-files/task.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# Copyright (C) 2020 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Swarming task script: this is what runs on the swarming bot + +# The only argument is the path to the isolate output directory +OUTDIR=$1 +# The script is launched in a directory above the task-files, start by cd'ing in +cd task-files + +# Clean-up on exit +cleanup() { + STATUS=$? + if [ -z "$EXIT_STATUS" ] ; then + EXIT_STATUS=${STATUS} + fi + # Key "power" (26) toggle between screen off and on, so first make sure to + # have the screen on with key "wake up" (224), then press "power" (26) + adb shell input keyevent 224 + sleep 1 # wake-up animation can take some time + adb shell input keyevent 26 + exit ${EXIT_STATUS} +} + +trap cleanup EXIT + +set -x + +############################################################################## +# Swarming test + +GAPIT=./agi/gapit + +# Prepare device +# launch adb deamon, this is a good thing to do when starting a swarming task +adb devices +# remove any implicit vulkan layers +adb shell settings delete global enable_gpu_debug_layers +adb shell settings delete global gpu_debug_app +adb shell settings delete global gpu_debug_layers +adb shell settings delete global gpu_debug_layer_app + +# NOTE: This script uses the APKs under the apk/ directory, and it assumes that +# all APKs are named as .apk, e.g. com.example.mygame.apk + +for apk in apk/*.apk +do + + # Install APK + package=`basename ${apk} .apk` + adb install -g -t ${apk} + + # Capture + adb logcat -c + $GAPIT -log-level Verbose trace -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan --start-at-frame 20 -capture-frames 5 -observe-frames 1 -out ${OUTDIR}/$package.gfxtrace $package > ${OUTDIR}/trace.out 2> ${OUTDIR}/trace.err + adb logcat -d > ${OUTDIR}/$package.trace.logcat + + # Stop the app + adb shell force-stop $package + + # Replay + adb logcat -c + $GAPIT video -gapir-nofallback -type sxs -frames-minimum 5 -out ${OUTDIR}/$package.mp4 ${OUTDIR}/$package.gfxtrace > ${OUTDIR}/video.out 2> ${OUTDIR}/video.err + adb logcat -d > ${OUTDIR}/$package.video.logcat + + if grep 'FramebufferObservation did not match replayed framebuffer' ${OUTDIR}/video.err > /dev/null ; then + echo "ERROR: replay leads to different image" + EXIT_STATUS=1 + cleanup + # cleanup should never return, but be safe and exit anyway + exit 1 + fi + +done + +EXIT_STATUS=0 +cleanup +exit 0 diff --git a/test/swarming/task.isolate b/test/swarming/task.isolate new file mode 100644 index 0000000000..fc47aab717 --- /dev/null +++ b/test/swarming/task.isolate @@ -0,0 +1,11 @@ +{ + 'variables': { + 'files': [ + './task-files/', + ], + 'command': [ + './task-files/task.sh', + '${ISOLATED_OUTDIR}', + ], + }, +} From c0f6efd974c16b7f67052e890b11c0f367652808 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 24 Mar 2020 15:31:21 -0700 Subject: [PATCH 0184/1218] Fixes a "Widgets is disposed" error when switching trace types. When opening, say, a graphics trace and then a system profile, a lot of the UI components are disposed in order to replace the graphics trace UI with the system profile UI. Any of these UI components that listen to capture load events will unregister themselves when being disposed. However, since we are in the middle of handling such an event, it is possible for such components to then still receive the current event. Instead of checking in each component whether they have since been disposed when handling the event, let's just schedule the disposing to happen after the event has been fully processed. --- gapic/src/main/com/google/gapid/MainWindow.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/gapic/src/main/com/google/gapid/MainWindow.java b/gapic/src/main/com/google/gapid/MainWindow.java index 094fa80b2f..35e65b42d3 100644 --- a/gapic/src/main/com/google/gapid/MainWindow.java +++ b/gapic/src/main/com/google/gapid/MainWindow.java @@ -126,11 +126,15 @@ public void onCaptureLoaded(Message error) { if (error != null) { mainUi.showMessage(error); } else { - MainView view = mainUi.getContents().updateAndGet( - models.capture.getData().capture.getType()); - view.updateViewMenu(findMenu(MenuItems.VIEW_ID)); - getMenuBarManager().updateAll(true); - mainUi.stopLoading(); + // Let all other handlers of this event get a chance to process before we start disposing + // UI components underneath everybody. + scheduleIfNotDisposed(mainUi, () -> { + MainView view = mainUi.getContents().updateAndGet( + models.capture.getData().capture.getType()); + view.updateViewMenu(findMenu(MenuItems.VIEW_ID)); + getMenuBarManager().updateAll(true); + mainUi.stopLoading(); + }); } } }); From 674c77e4f8860124c79ab6608a295d770c3b0614 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 24 Mar 2020 17:48:28 -0700 Subject: [PATCH 0185/1218] Trivial: fix spelling of domain origin enum type --- gapis/api/vulkan/resources.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go index 47c777985f..1f95da9e91 100644 --- a/gapis/api/vulkan/resources.go +++ b/gapis/api/vulkan/resources.go @@ -1400,7 +1400,7 @@ func (p GraphicsPipelineObjectʳ) tessellationControlShader(ctx context.Context, originState := tessState.TessellationDomainOriginState() if !originState.IsNil() { - tessStateList = tessStateList.AppendKeyValuePair("Domain Origin", api.CreateEnumDataValue("VkTessellationDomianOrigin", originState.DomainOrigin()), false) + tessStateList = tessStateList.AppendKeyValuePair("Domain Origin", api.CreateEnumDataValue("VkTessellationDomainOrigin", originState.DomainOrigin()), false) } dataGroups = append(dataGroups, &api.DataGroup{ From 5ee13cd973523fece3245859d432fe4c948ffcc1 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 24 Mar 2020 17:50:10 -0700 Subject: [PATCH 0186/1218] Tidy struct UI view further - Make PSEUDONYM nodes be leaves. Anything inside them is either more PSEUDONYM nodes, or eventually a POD value for the underlying type. We don't really care about any of that. - Simplify pointees to be consistent with toplevel objects Bug: b/143594054 --- gapic/src/main/com/google/gapid/models/Memory.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gapic/src/main/com/google/gapid/models/Memory.java b/gapic/src/main/com/google/gapid/models/Memory.java index 96174a6458..c85cd8a423 100644 --- a/gapic/src/main/com/google/gapid/models/Memory.java +++ b/gapic/src/main/com/google/gapid/models/Memory.java @@ -683,12 +683,11 @@ private static StructNode removeExtraLayers(StructNode root) { // Remove the outer layer for SLICE type. E.g. {[()]} -> [()]. if ((tyCase == TyCase.SLICE) && root.hasChildren() && root.children.size() == 1 && root.children.get(0).hasChildren()) { - root = root.children.get(0); + root = removeExtraLayers(root.children.get(0)); } - // Remove the inner layer for PSEUDONYM type. E.g. {[()]} -> {()}. - if (tyCase == TyCase.PSEUDONYM && root.hasChildren() && root.children.size() == 1 - && root.children.get(0).hasChildren()) { - root.children = root.children.get(0).children; + // Treat PSEUDONYM types as leaves, and remove any children they may have had. + if (tyCase == TyCase.PSEUDONYM) { + root.children.clear(); } for (int i = 0; i < root.children.size(); i++) { root.children.set(i, removeExtraLayers(root.children.get(i))); From e3a8ceec60697af96b92c6360992bcdce4374a35 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 25 Mar 2020 14:23:37 -0700 Subject: [PATCH 0187/1218] Share the browser initialization code. Adds logging of when we fail to create the browser widget. --- .../views/KeyboardMouseHelpDialog.java | 32 ++---------- .../main/com/google/gapid/views/Licenses.java | 51 ++++--------------- .../com/google/gapid/widgets/Widgets.java | 29 +++++++++++ 3 files changed, 42 insertions(+), 70 deletions(-) diff --git a/gapic/src/main/com/google/gapid/perfetto/views/KeyboardMouseHelpDialog.java b/gapic/src/main/com/google/gapid/perfetto/views/KeyboardMouseHelpDialog.java index 255cc581e2..6084627892 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/KeyboardMouseHelpDialog.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/KeyboardMouseHelpDialog.java @@ -26,18 +26,14 @@ import com.google.gapid.util.Messages; import com.google.gapid.widgets.DialogBase; import com.google.gapid.widgets.Theme; +import com.google.gapid.widgets.Widgets; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTError; -import org.eclipse.swt.browser.Browser; -import org.eclipse.swt.browser.LocationAdapter; -import org.eclipse.swt.browser.LocationEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; import java.io.IOException; import java.util.logging.Logger; @@ -60,29 +56,9 @@ public String getTitle() { @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite)super.createDialogArea(parent); - - Browser browser; - try { - browser = new Browser(area, SWT.NONE); - } catch (SWTError e) { - // Failed to initialize the browser. Show it as a plain text widget. - Text text = new Text( - area, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - text.setText(readKeyboardMouseHelp()); - return text; - } - - browser.setLayoutData(withSizeHints(new GridData(SWT.FILL, SWT.FILL, true, true), 1024, 768)); - browser.setText(readKeyboardMouseHelp()); - browser.addLocationListener(new LocationAdapter() { - @Override - public void changing(LocationEvent event) { - if ("about:blank".equals(event.location)) { - browser.setText(readKeyboardMouseHelp()); - } - } - }); + Control browser = Widgets.createBrowser(area, readKeyboardMouseHelp()); + browser.setLayoutData( + withSizeHints(new GridData(SWT.FILL, SWT.FILL, true, true), 1024, 768)); return area; } diff --git a/gapic/src/main/com/google/gapid/views/Licenses.java b/gapic/src/main/com/google/gapid/views/Licenses.java index 26752244aa..4192fddfe3 100644 --- a/gapic/src/main/com/google/gapid/views/Licenses.java +++ b/gapic/src/main/com/google/gapid/views/Licenses.java @@ -15,6 +15,7 @@ */ package com.google.gapid.views; +import static com.google.gapid.widgets.Widgets.withSizeHints; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.logging.Level.SEVERE; @@ -25,18 +26,14 @@ import com.google.gapid.util.Messages; import com.google.gapid.widgets.DialogBase; import com.google.gapid.widgets.Theme; +import com.google.gapid.widgets.Widgets; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.swt.SWT; -import org.eclipse.swt.SWTError; -import org.eclipse.swt.browser.Browser; -import org.eclipse.swt.browser.LocationAdapter; -import org.eclipse.swt.browser.LocationEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; import java.io.IOException; import java.util.logging.Logger; @@ -45,7 +42,7 @@ * Dialog to display the licenses used by the application in an HTML browser window. */ public class Licenses { - private static final Logger LOG = Logger.getLogger(Licenses.class.getName()); + protected static final Logger LOG = Logger.getLogger(Licenses.class.getName()); private Licenses() { } @@ -61,33 +58,9 @@ public String getTitle() { @Override protected Control createDialogArea(Composite parent) { Composite area = (Composite)super.createDialogArea(parent); - - Browser browser; - try { - browser = new Browser(area, SWT.NONE); - } catch (SWTError e) { - // Failed to initialize the browser. Show it as a plain text widget. - Text text = new Text( - area, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); - text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - text.setText(readLicenses(false)); - return text; - } - - GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); - data.widthHint = 600; - data.heightHint = 400; - browser.setLayoutData(data); - browser.setText(readLicenses(true)); - browser.addLocationListener(new LocationAdapter() { - @Override - public void changing(LocationEvent event) { - if ("about:blank".equals(event.location)) { - browser.setText(readLicenses(true)); - } - } - }); - + Control browser = Widgets.createBrowser(area, readLicenses()); + browser.setLayoutData( + withSizeHints(new GridData(SWT.FILL, SWT.FILL, true, true), 700, 768)); return area; } @@ -98,17 +71,11 @@ protected void createButtonsForButtonBar(Composite parent) { }.open(); } - protected static String readLicenses(boolean html) { + protected static String readLicenses() { try { String result = Resources.toString(Resources.getResource("text/licenses.html"), UTF_8); - if (html) { - // Linkify links. - result = result.replaceAll( - "(https?://[^\\s]+(?:[^\\s.,;:!?'\"()\\[\\]{}]))", "$1"); - } else { - // De-HTML the text. - result = result.replaceAll("<[^>]+>", ""); - } + result = result.replaceAll( + "(https?://[^\\s]+(?:[^\\s.,;:!?'\"()\\[\\]{}]))", "$1"); return result; } catch (IOException | IllegalArgumentException e) { LOG.log(SEVERE, "Failed to load the licenses", e); diff --git a/gapic/src/main/com/google/gapid/widgets/Widgets.java b/gapic/src/main/com/google/gapid/widgets/Widgets.java index e3e756d1ed..0923aa95dd 100644 --- a/gapic/src/main/com/google/gapid/widgets/Widgets.java +++ b/gapic/src/main/com/google/gapid/widgets/Widgets.java @@ -17,6 +17,7 @@ import static com.google.gapid.util.GeoUtils.right; import static com.google.gapid.util.GeoUtils.top; +import static java.util.logging.Level.WARNING; import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; @@ -44,6 +45,10 @@ import org.eclipse.jface.viewers.ViewerColumn; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTError; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.browser.LocationAdapter; +import org.eclipse.swt.browser.LocationEvent; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.custom.ScrolledComposite; @@ -819,6 +824,30 @@ public static ScrolledComposite createScrolledComposite(Composite parent, Layout return composite; } + public static Control createBrowser(Composite parent, String html) { + try { + Browser browser = new Browser(parent, SWT.NONE); + browser.setText(html); + browser.addLocationListener(new LocationAdapter() { + @Override + public void changing(LocationEvent event) { + if ("about:blank".equals(event.location)) { + browser.setText(html); + } + } + }); + return browser; + } catch (SWTError e) { + LOG.log(WARNING, "Failed to create browser widget", e); + } + + // Failed to create browser, show as de-HTMLed text. + Text text = new Text( + parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); + text.setText(html.replaceAll("<[^>]+>", "")); + return text; + } + /** * Recursively adds the given listener to the composite and all its children. */ From f0b261014c7bfc454f21c49b90e0d97f64e6816e Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 25 Mar 2020 14:27:58 -0700 Subject: [PATCH 0188/1218] Depend on the libwebkitgtk package. This package contains the WebKit GTK library required by SWT to show an inline browser widget. --- kokoro/linux/package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/linux/package.sh b/kokoro/linux/package.sh index fe853391c1..2865d7517e 100755 --- a/kokoro/linux/package.sh +++ b/kokoro/linux/package.sh @@ -58,7 +58,7 @@ Version: $VERSION Section: development Priority: optional Architecture: amd64 -Depends: openjdk-8-jre +Depends: openjdk-8-jre, libwebkitgtk-1.0-0 Maintainer: Google, Inc Description: Android Graphics Inspector is a collection of tools that allows you to inspect, tweak and replay calls from an application to a graphics driver. From c8fb59f3f034f9d0950d0809c2b6339a276fd05d Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 25 Mar 2020 15:26:15 -0700 Subject: [PATCH 0189/1218] Fix the validation URL in the UI. --- gapic/src/main/com/google/gapid/util/URLs.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gapic/src/main/com/google/gapid/util/URLs.java b/gapic/src/main/com/google/gapid/util/URLs.java index 68c88124d1..696d6ac248 100644 --- a/gapic/src/main/com/google/gapid/util/URLs.java +++ b/gapic/src/main/com/google/gapid/util/URLs.java @@ -18,7 +18,5 @@ public interface URLs { public static final String FILE_BUG_URL = "https://github.com/google/agi/issues/new?template=standard-bug-report-for-gapid.md"; - // TODO(b/148700785): Create the device compatibility doc and update here - public static final String DEVICE_COMPATIBILITY_URL = - "https://github.com/google/agi"; -} \ No newline at end of file + public static final String DEVICE_COMPATIBILITY_URL = "https://gpuinspector.dev/validation"; +} From b3f57af5fac957eb8f78c8a3c9ed5cbccc1f1207 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Thu, 26 Mar 2020 15:54:59 +0000 Subject: [PATCH 0190/1218] Be robust to Swarming failures not due to our test (#176) Also, run the swiftshader test in parallel with the Swarming test --- kokoro/linux/build.sh | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 8acda4b2a6..258b36b081 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -127,9 +127,8 @@ EXPIRATION=600 $LUCI_CLIENT_ROOT/swarming.py trigger $AUTH_FLAG --swarming $SWARMING_SERVER --isolate-server $ISOLATE_SERVER --isolated $ISOLATED_SHA --task-name ${TASK_NAME} --dump-json task.json --dimension pool $SWARMING_POOL --dimension device_type "$DEVICE_TYPE" --priority=$PRIORITY --expiration=$EXPIRATION --hard-timeout=$HARD_TIMEOUT -# Collect task results: if the task failed, then the 'swarming.py collect' -# command returns non-zero, making the build fail. -$LUCI_CLIENT_ROOT/swarming.py collect $AUTH_FLAG --swarming $SWARMING_SERVER --json task.json --task-summary-json summary.json +# Collect the Swarming test results after the swiftshader tests, as swarming +# will take a few minutes to schedule+run the task anyway. ## ## Test capture and replay of the Vulkan Sample App. @@ -172,3 +171,27 @@ test "${APP_EXIT_STATUS}" -eq 130 xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace + +## +## Collect swarming test result +## + +# The "swarming.py collect" call returns the task's exit code, which is non-zero +# if the task has expired (it was never scheduled). Allow for non-zero return +# code, and manually check the task status afterward +set +e +$LUCI_CLIENT_ROOT/swarming.py collect $AUTH_FLAG --swarming $SWARMING_SERVER --json task.json --task-summary-json summary.json +SWARMING_COLLECT_EXIT_CODE=$? +set -e + +# Ignore failures that are not due to the test itself +if [ "$SWARMING_COLLECT_EXIT_CODE" -ne "0" ] ; then + if grep '"state": "EXPIRED"' summary.json > /dev/null ; then + echo "Swarming test was never scheduled, ignoring it" + elif grep '"internal_failure": true' summary.json > /dev/null ; then + echo "Swarming internal failure, ignore the swarming test" + else + echo "Swarming test failed" + exit 1 + fi +fi From d5e352c6176c30f2a608815f34b37f6b259515c8 Mon Sep 17 00:00:00 2001 From: hliatis <47799839+hliatis@users.noreply.github.com> Date: Thu, 26 Mar 2020 09:41:57 -0700 Subject: [PATCH 0191/1218] Have ImageView links in PV go to Texture View (#92) * Have ImageView links in PV go to Texture View * Use Path.ResourceData and Service.Resource for resource links In order to use the generic ResourceData path but still use Api.ResourceType, this change adds to the models side of the UI to allow Follower to get the resource type via a Service.Resource. --- .../com/google/gapid/GraphicsTraceView.java | 6 + .../com/google/gapid/models/Follower.java | 26 ++- .../main/com/google/gapid/models/Models.java | 2 +- .../com/google/gapid/models/Resources.java | 20 +++ .../com/google/gapid/views/PipelineView.java | 13 +- .../com/google/gapid/views/TextureView.java | 19 +- gapis/api/data_group.go | 4 +- gapis/api/resource.go | 2 +- gapis/api/service.proto | 2 +- gapis/api/vulkan/resources.go | 164 +++++++++++------- gapis/resolve/resource_data.go | 6 +- gapis/resolve/resources.go | 23 +-- gapis/service/service.proto | 2 + 13 files changed, 205 insertions(+), 84 deletions(-) diff --git a/gapic/src/main/com/google/gapid/GraphicsTraceView.java b/gapic/src/main/com/google/gapid/GraphicsTraceView.java index 1d6b03a5cb..0ff5a4db93 100644 --- a/gapic/src/main/com/google/gapid/GraphicsTraceView.java +++ b/gapic/src/main/com/google/gapid/GraphicsTraceView.java @@ -25,6 +25,7 @@ import com.google.gapid.models.Models; import com.google.gapid.models.Settings; import com.google.gapid.proto.SettingsProto; +import com.google.gapid.proto.service.Service; import com.google.gapid.proto.service.Service.ClientAction; import com.google.gapid.proto.service.path.Path; import com.google.gapid.views.CommandTree; @@ -108,6 +109,11 @@ public void onMemoryFollowed(Path.Memory path) { public void onStateFollowed(Path.Any path) { tabs.showTab(MainTab.Type.ApiState); } + + @Override + public void onTextureFollowed(Service.Resource resource) { + tabs.showTab(MainTab.Type.Textures); + } }); } diff --git a/gapic/src/main/com/google/gapid/models/Follower.java b/gapic/src/main/com/google/gapid/models/Follower.java index 4d2e1ab561..65afb7d1b5 100644 --- a/gapic/src/main/com/google/gapid/models/Follower.java +++ b/gapic/src/main/com/google/gapid/models/Follower.java @@ -25,6 +25,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.proto.service.api.API; import com.google.gapid.proto.service.path.Path; +import com.google.gapid.proto.service.Service; import com.google.gapid.rpc.Rpc; import com.google.gapid.rpc.RpcException; import com.google.gapid.rpc.UiCallback; @@ -61,11 +62,13 @@ public class Follower { private final Shell shell; private final Client client; + private final Resources resources; private final ListenerCollection listeners = Events.listeners(Listener.class); - public Follower(Shell shell, Client client) { + public Follower(Shell shell, Client client, Resources resources) { this.shell = shell; this.client = client; + this.resources = resources; } /** @@ -231,11 +234,30 @@ public void onFollow(Path.Any path) { case STATE: listeners.fire().onStateFollowed(path); break; + case RESOURCE_DATA: + onFollowResource(path.getResourceData()); + break; default: LOG.log(WARNING, "Unknown follow path result: " + path); } } + private void onFollowResource(Path.ResourceData path) { + Resources.Resource r = resources.getResource(path); + + if (r != null) { + switch (r.resource.getType()) { + case TextureResource: + listeners.fire().onTextureFollowed(r.resource); + break; + default: + LOG.log(WARNING, "Unknown follow path result: " + path); + } + } else { + LOG.log(WARNING, "Path resolved to null resource: " + path); + } + } + public void gotoMemory(Path.Memory memoryPath) { listeners.fire().onMemoryFollowed(memoryPath); } @@ -259,6 +281,8 @@ public default void onStateFollowed(Path.Any path) { /* empty */ } * Event indicating that a link with the given path to a memory region was followed. */ public default void onMemoryFollowed(Path.Memory path) { /* empty */ } + + public default void onTextureFollowed(Service.Resource resource) {} } public static interface Prefetcher { diff --git a/gapic/src/main/com/google/gapid/models/Models.java b/gapic/src/main/com/google/gapid/models/Models.java index f82898ae17..65bd1516c1 100644 --- a/gapic/src/main/com/google/gapid/models/Models.java +++ b/gapic/src/main/com/google/gapid/models/Models.java @@ -68,7 +68,6 @@ public Models(Settings settings, Analytics analytics, Follower follower, Capture public static Models create( Shell shell, Settings settings, ExceptionHandler handler, Client client, StatusBar status) { Analytics analytics = new Analytics(client, settings, handler); - Follower follower = new Follower(shell, client); Capture capture = new Capture(shell, analytics, client, settings); Devices devices = new Devices(shell, analytics, client, capture, settings); ConstantSets constants = new ConstantSets(client, devices); @@ -76,6 +75,7 @@ public static Models create( CommandStream commands = new CommandStream( shell, analytics, client, capture, devices, constants); Resources resources = new Resources(shell, analytics, client, capture, devices, commands); + Follower follower = new Follower(shell, client, resources); ApiState state = new ApiState( shell, analytics, client, devices, follower, commands, constants); Reports reports = new Reports(shell, analytics, client, capture, devices); diff --git a/gapic/src/main/com/google/gapid/models/Resources.java b/gapic/src/main/com/google/gapid/models/Resources.java index b2c98fab7b..1995a7f456 100644 --- a/gapic/src/main/com/google/gapid/models/Resources.java +++ b/gapic/src/main/com/google/gapid/models/Resources.java @@ -98,6 +98,13 @@ public ResourceList getResources(API.ResourceType type) { return getData().getResources(commands.getSelectedCommands().getCommand(), type); } + public Resource getResource(Path.ResourceData path) { + if (!isLoaded() || commands.getSelectedCommands() == null) { + return null; + } + return getData().getResource(path); + } + public Path.ResourceData getResourcePath(Service.Resource resource) { CommandIndex after = commands.getSelectedCommands(); return (after == null) ? null : Path.ResourceData.newBuilder() @@ -184,6 +191,19 @@ public ResourceList getResources(Path.Command after, API.ResourceType type) { return new ResourceList(type, list, complete); } + public Resource getResource(Path.ResourceData path) { + for (Service.ResourcesByType rs : resources.getTypesList()) { + for (Service.Resource r : rs.getResourcesList()) { + if (path.getID().equals(r.getID())) { + Path.Command deleted = r.getDeleted(); + return new Resource(r, !isNull(deleted) && compare(deleted, path.getAfter()) <= 0); + } + } + } + + return null; + } + private static Path.Command firstAccess(Service.Resource info) { return (info.getAccessesCount() == 0) ? null : info.getAccesses(0); } diff --git a/gapic/src/main/com/google/gapid/views/PipelineView.java b/gapic/src/main/com/google/gapid/views/PipelineView.java index 5143c43c1b..a8b173b02c 100644 --- a/gapic/src/main/com/google/gapid/views/PipelineView.java +++ b/gapic/src/main/com/google/gapid/views/PipelineView.java @@ -397,7 +397,10 @@ private Composite createStage(Composite parent, API.Stage currentStage) { DataValue dv = convertDataValue(kvp.getValue()); if (dv.link != null) { - withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> models.follower.onFollow(dv.link)), + withLayoutData( createLink(valueComposite,"" + dv.displayValue + "", e -> { + for (Path.Any p : dv.link) { + models.follower.onFollow(p); + }}), new GridData(SWT.LEFT, SWT.CENTER, true, true)); } else { Label valueLabel = withLayoutData( createLabel(valueComposite, dv.displayValue), @@ -513,7 +516,9 @@ public String getToolTipText(Object element) { DataValue dv = convertDataValue(((API.Row)cell.getElement()).getRowValues(cell.getColumnIndex())); if (dv.link != null) { - models.follower.onFollow(dv.link); + for (Path.Any p : dv.link) { + models.follower.onFollow(p); + } return; } } @@ -701,7 +706,7 @@ protected static DataValue convertDataValue(API.DataValue val) { case LINK: DataValue dv = convertDataValue(val.getLink().getDisplayVal()); - dv.link = val.getLink().getLink(); + dv.link = val.getLink().getLinkList(); return dv; @@ -713,7 +718,7 @@ protected static DataValue convertDataValue(API.DataValue val) { private static class DataValue { public String displayValue; public String tooltipValue; - public Path.Any link; + public List link; public DataValue(String displayValue) { this.link = null; diff --git a/gapic/src/main/com/google/gapid/views/TextureView.java b/gapic/src/main/com/google/gapid/views/TextureView.java index a8b0d86387..3f0efdc7f0 100644 --- a/gapic/src/main/com/google/gapid/views/TextureView.java +++ b/gapic/src/main/com/google/gapid/views/TextureView.java @@ -41,6 +41,7 @@ import com.google.gapid.models.Capture; import com.google.gapid.models.CommandStream; import com.google.gapid.models.CommandStream.CommandIndex; +import com.google.gapid.models.Follower; import com.google.gapid.models.Models; import com.google.gapid.models.Resources; import com.google.gapid.models.Settings; @@ -101,7 +102,7 @@ * View that displays the texture resources of the current capture. */ public class TextureView extends Composite - implements Tab, Capture.Listener, Resources.Listener, CommandStream.Listener { + implements Tab, Capture.Listener, Resources.Listener, CommandStream.Listener, Follower.Listener { protected static final Logger LOG = Logger.getLogger(TextureView.class.getName()); private final Models models; @@ -146,10 +147,12 @@ public TextureView(Composite parent, Models models, Widgets widgets) { models.capture.addListener(this); models.commands.addListener(this); models.resources.addListener(this); + models.follower.addListener(this); addListener(SWT.Dispose, e -> { models.capture.removeListener(this); models.commands.removeListener(this); models.resources.removeListener(this); + models.follower.removeListener(this); gotoAction.dispose(); imageProvider.reset(); }); @@ -235,6 +238,20 @@ public void onCommandsSelected(CommandIndex path) { updateTextures(false); } + @Override + public void onTextureFollowed(Service.Resource resource) { + TableItem[] items = textureTable.getTable().getItems(); + for (int i = 0; i < items.length; i++) { + Data d = (Data)(items[i].getData()); + + if (d.info.getID().equals(resource.getID())) { + textureTable.getTable().setSelection(items[i]); + updateSelection(); + break; + } + } + } + private void updateTextures(boolean resourcesChanged) { if (models.resources.isLoaded() && models.commands.getSelectedCommands() != null) { // Memorize selection index before disposing image resource. diff --git a/gapis/api/data_group.go b/gapis/api/data_group.go index 64f6a16beb..22179651a2 100644 --- a/gapis/api/data_group.go +++ b/gapis/api/data_group.go @@ -156,12 +156,12 @@ func CreateBitfieldDataValue(typeName string, val interface{}, index int32, a AP } } -func CreateLinkedDataValue(typeName string, p path.Node, val *DataValue) *DataValue { +func CreateLinkedDataValue(typeName string, p []*path.Any, val *DataValue) *DataValue { return &DataValue{ TypeName: typeName, Val: &DataValue_Link{ &LinkedValue{ - Link: p.Path(), + Link: p, DisplayVal: val, }, }, diff --git a/gapis/api/resource.go b/gapis/api/resource.go index 0c72bc5c2f..09f988bd7a 100644 --- a/gapis/api/resource.go +++ b/gapis/api/resource.go @@ -45,7 +45,7 @@ type Resource interface { ResourceType(ctx context.Context) ResourceType // ResourceData returns the resource data given the current state. - ResourceData(ctx context.Context, s *GlobalState, cmd *path.Command) (*ResourceData, error) + ResourceData(ctx context.Context, s *GlobalState, cmd *path.Command, r *path.ResolveConfig) (*ResourceData, error) // SetResourceData sets resource data in a new capture. SetResourceData( diff --git a/gapis/api/service.proto b/gapis/api/service.proto index d0e448ce9d..7a5e5da6c0 100644 --- a/gapis/api/service.proto +++ b/gapis/api/service.proto @@ -294,7 +294,7 @@ message BitfieldValue { } message LinkedValue { - path.Any link = 1; + repeated path.Any link = 1; DataValue display_val = 2; } diff --git a/gapis/api/vulkan/resources.go b/gapis/api/vulkan/resources.go index 1f95da9e91..9273cba507 100644 --- a/gapis/api/vulkan/resources.go +++ b/gapis/api/vulkan/resources.go @@ -676,7 +676,7 @@ func (t ImageObjectʳ) imageInfo(ctx context.Context, s *api.GlobalState, vkFmt } // ResourceData returns the resource data given the current state. -func (t ImageObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { +func (t ImageObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command, r *path.ResolveConfig) (*api.ResourceData, error) { ctx = log.Enter(ctx, "ImageObject.ResourceData()") vkFmt := t.Info().Fmt() _, err := getImageFormatFromVulkanFormat(vkFmt) @@ -825,7 +825,7 @@ func (s ShaderModuleObjectʳ) ResourceType(ctx context.Context) api.ResourceType } // ResourceData returns the resource data given the current state. -func (s ShaderModuleObjectʳ) ResourceData(ctx context.Context, t *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { +func (s ShaderModuleObjectʳ) ResourceData(ctx context.Context, t *api.GlobalState, cmd *path.Command, r *path.ResolveConfig) (*api.ResourceData, error) { ctx = log.Enter(ctx, "ShaderModuleObject.ResourceData()") words, err := s.Words().Read(ctx, nil, t, nil) if err != nil { @@ -997,7 +997,7 @@ func (p GraphicsPipelineObjectʳ) ResourceType(ctx context.Context) api.Resource } // ResourceData returns the resource data given the current state. -func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { +func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command, r *path.ResolveConfig) (*api.ResourceData, error) { vkState := GetState(s) isBound := false var drawCallInfo DrawParameters = NilDrawParameters @@ -1030,14 +1030,17 @@ func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.Globa } } + resourceMeta, _ := resolve.ResourceMeta(ctx, nil, cmd, r) + resources := resourceMeta.IDMap + stages := []*api.Stage{ p.inputAssembly(cmd, drawCallInfo), - p.vertexShader(ctx, s, cmd, boundDsets), - p.tessellationControlShader(ctx, s, cmd, boundDsets), - p.tessellationEvulationShader(ctx, s, cmd, boundDsets), - p.geometryShader(ctx, s, cmd, boundDsets), + p.vertexShader(ctx, s, cmd, resources, boundDsets), + p.tessellationControlShader(ctx, s, cmd, resources, boundDsets), + p.tessellationEvulationShader(ctx, s, cmd, resources, boundDsets), + p.geometryShader(ctx, s, cmd, resources, boundDsets), p.rasterizer(s, dynamicStates), - p.fragmentShader(ctx, s, cmd, boundDsets), + p.fragmentShader(ctx, s, cmd, resources, boundDsets), p.colorBlending(ctx, s, cmd, dynamicStates, framebuffer, renderpass), } @@ -1057,11 +1060,14 @@ func (p GraphicsPipelineObjectʳ) ResourceData(ctx context.Context, s *api.Globa func commonShaderDataGroups(ctx context.Context, s *api.GlobalState, cmd *path.Command, + resources api.ResourceMap, boundDsets map[uint32]DescriptorSetObjectʳ, usedSets map[uint32]DescriptorUsage, vkStage VkShaderStageFlagBits, stages map[uint32]StageData, ) []*api.DataGroup { + vkState := GetState(s) + for _, stage := range stages { if stage.Stage() == vkStage { module := stage.Module() @@ -1078,7 +1084,7 @@ func commonShaderDataGroups(ctx context.Context, } setHandle := setInfo.VulkanHandle() - setPath := path.NewField("DescriptorSets", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(setHandle) + setPath := path.NewField("DescriptorSets", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(setHandle).Path() layoutBinding, ok := setInfo.Layout().Bindings().Lookup(usedSet.Binding()) if !ok || layoutBinding.Stages()&VkShaderStageFlags(vkStage) == 0 { @@ -1090,7 +1096,7 @@ func commonShaderDataGroups(ctx context.Context, for i := uint32(0); i < usedSet.DescriptorCount(); i++ { currentSetData := []*api.DataValue{ - api.CreateLinkedDataValue("url", setPath, api.CreatePoDDataValue("u32", usedSet.Set())), + api.CreateLinkedDataValue("url", []*path.Any{setPath}, api.CreatePoDDataValue("u32", usedSet.Set())), api.CreatePoDDataValue("u32", usedSet.Binding()), api.CreatePoDDataValue("u32", i), api.CreateEnumDataValue("VkDescriptorType", bindingType), @@ -1109,8 +1115,8 @@ func commonShaderDataGroups(ctx context.Context, descInfo := bindingInfo.ImageBinding().Get(i) samplerHandle := descInfo.Sampler() - samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle))) + samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{samplerPath}, api.CreatePoDDataValue("VkSampler", samplerHandle))) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) @@ -1124,8 +1130,11 @@ func commonShaderDataGroups(ctx context.Context, currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) viewHandle := descInfo.ImageView() - viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", viewPath, api.CreatePoDDataValue("VkImageView", viewHandle))) + viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle).Path() + + imageView, _ := vkState.ImageViews().Lookup(viewHandle) + imageViewPath := cmd.ResourceAfter(path.NewID(resources[imageView.Image().ResourceHandle()])).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{viewPath, imageViewPath}, api.CreatePoDDataValue("VkImageView", viewHandle))) currentSetData = append(currentSetData, api.CreateEnumDataValue("VkImageLayout", descInfo.ImageLayout())) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) @@ -1135,12 +1144,15 @@ func commonShaderDataGroups(ctx context.Context, descInfo := bindingInfo.ImageBinding().Get(i) samplerHandle := descInfo.Sampler() - samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", samplerPath, api.CreatePoDDataValue("VkSampler", samplerHandle))) + samplerPath := path.NewField("Samplers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(samplerHandle).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{samplerPath}, api.CreatePoDDataValue("VkSampler", samplerHandle))) viewHandle := descInfo.ImageView() - viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", viewPath, api.CreatePoDDataValue("VkImageView", viewHandle))) + viewPath := path.NewField("ImageViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(viewHandle).Path() + + imageView, _ := vkState.ImageViews().Lookup(viewHandle) + imageViewPath := cmd.ResourceAfter(path.NewID(resources[imageView.Image().ResourceHandle()])).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{viewPath, imageViewPath}, api.CreatePoDDataValue("VkImageView", viewHandle))) currentSetData = append(currentSetData, api.CreateEnumDataValue("VkImageLayout", descInfo.ImageLayout())) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) @@ -1151,8 +1163,8 @@ func commonShaderDataGroups(ctx context.Context, descInfo := bindingInfo.BufferViewBindings().Get(i) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) - bufferViewPath := path.NewField("BufferViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferViewPath, api.CreatePoDDataValue("VkBufferView", descInfo))) + bufferViewPath := path.NewField("BufferViews", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{bufferViewPath}, api.CreatePoDDataValue("VkBufferView", descInfo))) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) @@ -1164,8 +1176,8 @@ func commonShaderDataGroups(ctx context.Context, descInfo := bindingInfo.BufferBinding().Get(i) bufferHandle := descInfo.Buffer() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo.Buffer()) - currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", bufferHandle))) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(descInfo.Buffer()).Path() + currentSetData = append(currentSetData, api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", bufferHandle))) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) currentSetData = append(currentSetData, api.CreatePoDDataValue("", "-")) @@ -1285,55 +1297,55 @@ func (p GraphicsPipelineObjectʳ) inputAssembly(cmd *path.Command, drawCallInfo drawCallList = drawCallList.AppendKeyValuePair("First Instance", api.CreatePoDDataValue("u32", callArgs.FirstInstance()), false) } else if !drawCallInfo.DrawIndirect().IsNil() { callArgs := drawCallInfo.DrawIndirect() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) drawCallList = drawCallList.AppendKeyValuePair("Draw Count", api.CreatePoDDataValue("u32", callArgs.DrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) } else if !drawCallInfo.DrawIndexedIndirect().IsNil() { callArgs := drawCallInfo.DrawIndexedIndirect() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) drawCallList = drawCallList.AppendKeyValuePair("Draw Count", api.CreatePoDDataValue("u32", callArgs.DrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) } else if !drawCallInfo.DrawIndirectCountKHR().IsNil() { callArgs := drawCallInfo.DrawIndirectCountKHR() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) - countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", countBufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) + countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", []*path.Any{countBufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Count Buffer Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.CountBufferOffset()), false) drawCallList = drawCallList.AppendKeyValuePair("Max Draw Count", api.CreatePoDDataValue("u32", callArgs.MaxDrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) } else if !drawCallInfo.DrawIndexedIndirectCountKHR().IsNil() { callArgs := drawCallInfo.DrawIndexedIndirectCountKHR() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) - countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", countBufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) + countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", []*path.Any{countBufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Count Buffer Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.CountBufferOffset()), false) drawCallList = drawCallList.AppendKeyValuePair("Max Draw Count", api.CreatePoDDataValue("u32", callArgs.MaxDrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) } else if !drawCallInfo.DrawIndirectCountAMD().IsNil() { callArgs := drawCallInfo.DrawIndirectCountAMD() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) - countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", countBufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) + countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", []*path.Any{countBufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Count Buffer Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.CountBufferOffset()), false) drawCallList = drawCallList.AppendKeyValuePair("Max Draw Count", api.CreatePoDDataValue("u32", callArgs.MaxDrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) } else if !drawCallInfo.DrawIndexedIndirectCountAMD().IsNil() { callArgs := drawCallInfo.DrawIndexedIndirectCountAMD() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.Buffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.Offset()), false) - countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()) - drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", countBufferPath, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) + countBufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(callArgs.Buffer()).Path() + drawCallList = drawCallList.AppendKeyValuePair("Count Buffer", api.CreateLinkedDataValue("url", []*path.Any{countBufferPath}, api.CreatePoDDataValue("VkBuffer", callArgs.CountBuffer())), false) drawCallList = drawCallList.AppendKeyValuePair("Count Buffer Offset", api.CreatePoDDataValue("VkDeviceSize", callArgs.CountBufferOffset()), false) drawCallList = drawCallList.AppendKeyValuePair("Max Draw Count", api.CreatePoDDataValue("u32", callArgs.MaxDrawCount()), false) drawCallList = drawCallList.AppendKeyValuePair("Stride", api.CreatePoDDataValue("u32", callArgs.Stride()), false) @@ -1369,8 +1381,14 @@ func (p GraphicsPipelineObjectʳ) inputAssembly(cmd *path.Command, drawCallInfo } } -func (p GraphicsPipelineObjectʳ) vertexShader(ctx context.Context, s *api.GlobalState, cmd *path.Command, boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), +func (p GraphicsPipelineObjectʳ) vertexShader( + ctx context.Context, + s *api.GlobalState, + cmd *path.Command, + resources api.ResourceMap, + boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resources, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_VERTEX_BIT, p.Stages().All()) if dataGroups != nil { return &api.Stage{ @@ -1389,8 +1407,14 @@ func (p GraphicsPipelineObjectʳ) vertexShader(ctx context.Context, s *api.Globa } } -func (p GraphicsPipelineObjectʳ) tessellationControlShader(ctx context.Context, s *api.GlobalState, cmd *path.Command, boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), +func (p GraphicsPipelineObjectʳ) tessellationControlShader( + ctx context.Context, + s *api.GlobalState, + cmd *path.Command, + resources api.ResourceMap, + boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resources, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, p.Stages().All()) if dataGroups != nil { tessState := p.TessellationState() @@ -1424,8 +1448,14 @@ func (p GraphicsPipelineObjectʳ) tessellationControlShader(ctx context.Context, } } -func (p GraphicsPipelineObjectʳ) tessellationEvulationShader(ctx context.Context, s *api.GlobalState, cmd *path.Command, boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), +func (p GraphicsPipelineObjectʳ) tessellationEvulationShader( + ctx context.Context, + s *api.GlobalState, + cmd *path.Command, + resources api.ResourceMap, + boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resources, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, p.Stages().All()) if dataGroups != nil { return &api.Stage{ @@ -1443,8 +1473,14 @@ func (p GraphicsPipelineObjectʳ) tessellationEvulationShader(ctx context.Contex } } -func (p GraphicsPipelineObjectʳ) geometryShader(ctx context.Context, s *api.GlobalState, cmd *path.Command, boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), +func (p GraphicsPipelineObjectʳ) geometryShader( + ctx context.Context, + s *api.GlobalState, + cmd *path.Command, + resources api.ResourceMap, + boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resources, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_GEOMETRY_BIT, p.Stages().All()) if dataGroups != nil { return &api.Stage{ @@ -1613,8 +1649,14 @@ func (p GraphicsPipelineObjectʳ) rasterizer(s *api.GlobalState, dynamicStates m } } -func (p GraphicsPipelineObjectʳ) fragmentShader(ctx context.Context, s *api.GlobalState, cmd *path.Command, boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), +func (p GraphicsPipelineObjectʳ) fragmentShader( + ctx context.Context, + s *api.GlobalState, + cmd *path.Command, + resources api.ResourceMap, + boundDsets map[uint32]DescriptorSetObjectʳ) *api.Stage { + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resources, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_FRAGMENT_BIT, p.Stages().All()) if dataGroups != nil { return &api.Stage{ @@ -1808,14 +1850,14 @@ func (p GraphicsPipelineObjectʳ) colorBlending(ctx context.Context, s *api.Glob renderPassList := &api.KeyValuePairList{} if !rp.IsNil() { renderPassHandle := rp.VulkanHandle() - renderPassPath := path.NewField("RenderPasses", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(renderPassHandle) - renderPassList = renderPassList.AppendKeyValuePair("Render Pass", api.CreateLinkedDataValue("url", renderPassPath, api.CreatePoDDataValue("VkRenderPass", renderPassHandle)), false) + renderPassPath := path.NewField("RenderPasses", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(renderPassHandle).Path() + renderPassList = renderPassList.AppendKeyValuePair("Render Pass", api.CreateLinkedDataValue("url", []*path.Any{renderPassPath}, api.CreatePoDDataValue("VkRenderPass", renderPassHandle)), false) } if !fb.IsNil() { fbHandle := fb.VulkanHandle() - fbPath := path.NewField("Framebuffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(fbHandle) - renderPassList = renderPassList.AppendKeyValuePair("Framebuffer", api.CreateLinkedDataValue("url", fbPath, api.CreatePoDDataValue("VkFramebuffer", fbHandle)), false) + fbPath := path.NewField("Framebuffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(fbHandle).Path() + renderPassList = renderPassList.AppendKeyValuePair("Framebuffer", api.CreateLinkedDataValue("url", []*path.Any{fbPath}, api.CreatePoDDataValue("VkFramebuffer", fbHandle)), false) } dataGroups := []*api.DataGroup{ @@ -1898,7 +1940,7 @@ func (p ComputePipelineObjectʳ) ResourceType(ctx context.Context) api.ResourceT } // ResourceData returns the resource data given the current state. -func (p ComputePipelineObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command) (*api.ResourceData, error) { +func (p ComputePipelineObjectʳ) ResourceData(ctx context.Context, s *api.GlobalState, cmd *path.Command, r *path.ResolveConfig) (*api.ResourceData, error) { vkState := GetState(s) isBound := false var dispatchInfo DispatchParameters = NilDispatchParameters @@ -1918,7 +1960,9 @@ func (p ComputePipelineObjectʳ) ResourceData(ctx context.Context, s *api.Global } } - dataGroups := commonShaderDataGroups(ctx, s, cmd, boundDsets, p.UsedDescriptors().All(), + resourceMeta, _ := resolve.ResourceMeta(ctx, nil, cmd, r) + + dataGroups := commonShaderDataGroups(ctx, s, cmd, resourceMeta.IDMap, boundDsets, p.UsedDescriptors().All(), VkShaderStageFlagBits_VK_SHADER_STAGE_COMPUTE_BIT, map[uint32]StageData{0: p.Stage()}) dispatchList := &api.KeyValuePairList{} @@ -1930,8 +1974,8 @@ func (p ComputePipelineObjectʳ) ResourceData(ctx context.Context, s *api.Global dispatchList = dispatchList.AppendKeyValuePair("Group Count Z", api.CreatePoDDataValue("u32", dispatchParams.GroupCountZ()), false) } else if !dispatchInfo.DispatchIndirect().IsNil() { dispatchParams := dispatchInfo.DispatchIndirect() - bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(dispatchParams.Buffer()) - dispatchList = dispatchList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", bufferPath, api.CreatePoDDataValue("VkBuffer", dispatchParams.Buffer())), false) + bufferPath := path.NewField("Buffers", resolve.APIStateAfter(path.FindCommand(cmd), ID)).MapIndex(dispatchParams.Buffer()).Path() + dispatchList = dispatchList.AppendKeyValuePair("Buffer", api.CreateLinkedDataValue("url", []*path.Any{bufferPath}, api.CreatePoDDataValue("VkBuffer", dispatchParams.Buffer())), false) dispatchList = dispatchList.AppendKeyValuePair("Offset", api.CreatePoDDataValue("VkDeviceSize", dispatchParams.Offset()), false) } diff --git a/gapis/resolve/resource_data.go b/gapis/resolve/resource_data.go index 870d1ed47f..9723be24a1 100644 --- a/gapis/resolve/resource_data.go +++ b/gapis/resolve/resource_data.go @@ -44,7 +44,7 @@ type ResolvedResources struct { func (r *AllResourceDataResolvable) Resolve(ctx context.Context) (interface{}, error) { ctx = SetupContext(ctx, r.After.Capture, r.Config) - resources, err := buildResources(ctx, r.After, r.Type) + resources, err := buildResources(ctx, r.After, r.Type, r.Config) if err != nil { return nil, err @@ -52,7 +52,7 @@ func (r *AllResourceDataResolvable) Resolve(ctx context.Context) (interface{}, e return resources, nil } -func buildResources(ctx context.Context, p *path.Command, t api.ResourceType) (*ResolvedResources, error) { +func buildResources(ctx context.Context, p *path.Command, t api.ResourceType, r *path.ResolveConfig) (*ResolvedResources, error) { cmdIdx := p.Indices[0] capture, err := capture.ResolveGraphics(ctx) @@ -124,7 +124,7 @@ func buildResources(ctx context.Context, p *path.Command, t api.ResourceType) (* } i++ - res, err := v.ResourceData(ctx, state, p) + res, err := v.ResourceData(ctx, state, p, r) if err != nil { resourceData[k] = err } else { diff --git a/gapis/resolve/resources.go b/gapis/resolve/resources.go index c6edecd0e7..09d5b06ac6 100644 --- a/gapis/resolve/resources.go +++ b/gapis/resolve/resources.go @@ -63,10 +63,11 @@ func (r *ResourcesResolvable) Resolve(ctx context.Context) (interface{}, error) state.OnResourceCreated = func(res api.Resource) { currentCmdResourceCount++ tr := trackedResource{ - resource: res, - id: genResourceID(currentCmdIndex, currentCmdResourceCount), - accesses: []uint64{currentCmdIndex}, - created: currentCmdIndex, + resource: res, + id: genResourceID(currentCmdIndex, currentCmdResourceCount), + accesses: []uint64{currentCmdIndex}, + created: currentCmdIndex, + resourceType: res.ResourceType(ctx), } resources = append(resources, tr) seen[res] = len(resources) - 1 @@ -144,12 +145,13 @@ func (r *ResourcesResolvable) Resolve(ctx context.Context) (interface{}, error) } type trackedResource struct { - resource api.Resource - id id.ID - name string - accesses []uint64 - deleted uint64 - created uint64 + resource api.Resource + id id.ID + name string + accesses []uint64 + deleted uint64 + created uint64 + resourceType api.ResourceType } func (r trackedResource) asService(p *path.Capture) *service.Resource { @@ -159,6 +161,7 @@ func (r trackedResource) asService(p *path.Capture) *service.Resource { Label: r.resource.ResourceLabel(), Order: r.resource.Order(), Accesses: make([]*path.Command, len(r.accesses)), + Type: r.resourceType, } for i, a := range r.accesses { out.Accesses[i] = p.Command(a) diff --git a/gapis/service/service.proto b/gapis/service/service.proto index f168fb1ada..9645f6babe 100644 --- a/gapis/service/service.proto +++ b/gapis/service/service.proto @@ -1008,6 +1008,8 @@ message Resource { path.Command deleted = 6; // The command at which this resource was created. path.Command created = 7; + // The type of the resource + api.ResourceType type = 9; } // CommandTree represents a command tree hierarchy. From 6a83854c3427dbf3f63f3769c1ed232c119915d4 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 24 Mar 2020 23:05:26 -0700 Subject: [PATCH 0192/1218] Implement linking to Vulkan objects in the struct UI - Have the server produce paths when boxing linkable handle types. This requires a bit of ugliness to recover the actual type of the handle and call through its Link() implementation if present. - In the client, convert the value column of the struct UI to use custom drawing. Move the existing ad-hoc linking for "large arrays" to be linked from the value column, and add link following for server-provided links as well. Bug: b/143594054 --- .../com/google/gapid/views/MemoryView.java | 53 +++++++++++++------ gapis/resolve/memory.go | 2 +- gapis/service/memory_box/BUILD.bazel | 11 +++- gapis/service/memory_box/box.go | 43 +++++++++++++-- gapis/service/memory_box/box.proto | 2 + 5 files changed, 87 insertions(+), 24 deletions(-) diff --git a/gapic/src/main/com/google/gapid/views/MemoryView.java b/gapic/src/main/com/google/gapid/views/MemoryView.java index 2c3bebf4f0..51b3299f2d 100644 --- a/gapic/src/main/com/google/gapid/views/MemoryView.java +++ b/gapic/src/main/com/google/gapid/views/MemoryView.java @@ -81,11 +81,15 @@ import org.eclipse.jface.viewers.ITreeViewerListener; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.TreeExpansionEvent; import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; @@ -807,11 +811,6 @@ protected void onUiThread(List result) { } } for (TreeItem item : treeViewer.getTree().getItems()) { - // Give visual hint to the clickable large array. - if (item.getData() instanceof StructNode && - ((StructNode)item.getData()).isLargeArray()) { - item.setForeground(0, widgets.theme.memoryLinkColor()); - } // Give visual hint to the elements of level 1. item.setBackground(widgets.theme.memoryFirstLevelBackground()); } @@ -868,17 +867,23 @@ public void treeCollapsed(TreeExpansionEvent event) { }); tree.addDoubleClickListener(e -> Display.getDefault().asyncExec(() -> packColumns(tree.getTree()))); - // Add link action for the nodes with hidden large array. + // Add link action tree.getTree().addListener(SWT.MouseUp, e -> { - if (isOnLargeArray(tree, new Point(e.x, e.y))) { + if (isOnLink(tree, new Point(e.x, e.y))) { StructNode node = ((StructNode)tree.getTree().getItem(new Point(e.x, e.y)).getData()); - long address = node.getRootAddress(); - blockPanel.goToObservation(address); - folder.setSelection(0); + if (node.isLargeArray()) { + // Large array links are synthetic on the client side + long address = node.getRootAddress(); + blockPanel.goToObservation(address); + folder.setSelection(0); + } else if (node.getValue().hasLink()) { + // Other links come from the server, and are paths to arbitrary places + models.follower.onFollow(node.getValue().getLink()); + } } }); tree.getTree().addListener(SWT.MouseMove, e -> { - if (isOnLargeArray(tree, new Point(e.x, e.y))) { + if (isOnLink(tree, new Point(e.x, e.y))) { setCursor(getDisplay().getSystemCursor(SWT.CURSOR_HAND)); } else { setCursor(null); @@ -887,16 +892,32 @@ public void treeCollapsed(TreeExpansionEvent event) { createTreeColumn(tree, "Type", e -> ((StructNode)e).getTypeFormatted()); createTreeColumn(tree, "Name", e -> ((StructNode)e).getStructName()); - createTreeColumn(tree, "Value", e -> ((StructNode) e).getValueFormatted()); + TreeViewerColumn valueColumn = createTreeColumn(tree, "Value"); + valueColumn.setLabelProvider(new StyledCellLabelProvider(){ + @Override + public void update(ViewerCell cell) { + StructNode e = (StructNode)cell.getElement(); + cell.setText(e.getValueFormatted()); + if (e.getValue().hasLink() || e.isLargeArray()) { + StyleRange style = new StyleRange(); + widgets.theme.linkStyler().applyStyles(style); + style.length = cell.getText().length(); + cell.setStyleRanges(new StyleRange[] { style }); + } + + super.update(cell); + } + }); + return tree; } - // Return true if the cursor is on the first column of a large array. - private boolean isOnLargeArray(TreeViewer tree, Point point) { + // Return true if the cursor is on the value column of a link (either link from the server, or a large array) + private boolean isOnLink(TreeViewer tree, Point point) { TreeItem item = tree.getTree().getItem(point); return item != null && item.getData() instanceof StructNode - && ((StructNode)item.getData()).isLargeArray() - && item.getBounds(0).contains(point); + && (((StructNode)item.getData()).isLargeArray() || ((StructNode)item.getData()).getValue().hasLink()) + && item.getBounds(2).contains(point); } } diff --git a/gapis/resolve/memory.go b/gapis/resolve/memory.go index 6f605c7c74..ca26a32a06 100644 --- a/gapis/resolve/memory.go +++ b/gapis/resolve/memory.go @@ -292,7 +292,7 @@ func MemoryAsType(ctx context.Context, p *path.MemoryAsType, rc *path.ResolveCon } vals := []*memory_box.Value{} for i := 0; i < nElems; i++ { - v, err := memory_box.Box(ctx, dec, ty) + v, err := memory_box.Box(ctx, dec, ty, p, rc) if err != nil { return nil, err } diff --git a/gapis/service/memory_box/BUILD.bazel b/gapis/service/memory_box/BUILD.bazel index b16dae9a31..b3e2f5b7ca 100644 --- a/gapis/service/memory_box/BUILD.bazel +++ b/gapis/service/memory_box/BUILD.bazel @@ -28,6 +28,7 @@ go_library( "//core/data/pod:go_default_library", "//core/log:go_default_library", "//gapis/memory:go_default_library", + "//gapis/service/path:go_default_library", "//gapis/service/types:go_default_library", ], ) @@ -36,7 +37,10 @@ proto_library( name = "memory_box_proto", srcs = ["box.proto"], visibility = ["//visibility:public"], - deps = ["//core/data/pod:pod_proto"], + deps = [ + "//core/data/pod:pod_proto", + "//gapis/service/path:path_proto", + ], ) go_proto_library( @@ -44,7 +48,10 @@ go_proto_library( importpath = "github.com/google/gapid/gapis/service/memory_box", proto = ":memory_box_proto", visibility = ["//visibility:public"], - deps = ["//core/data/pod:go_default_library"], + deps = [ + "//core/data/pod:go_default_library", + "//gapis/service/path:go_default_library", + ], ) java_proto_library( diff --git a/gapis/service/memory_box/box.go b/gapis/service/memory_box/box.go index b6202db648..c703330dad 100644 --- a/gapis/service/memory_box/box.go +++ b/gapis/service/memory_box/box.go @@ -16,19 +16,26 @@ package memory_box import ( "context" + "reflect" "github.com/google/gapid/core/data/pod" "github.com/google/gapid/core/log" "github.com/google/gapid/gapis/memory" + "github.com/google/gapid/gapis/service/path" "github.com/google/gapid/gapis/service/types" ) -func Box(ctx context.Context, d *memory.Decoder, t *types.Type) (*Value, error) { +var ( + tyLinkable = reflect.TypeOf((*path.Linker)(nil)).Elem() +) + +func Box(ctx context.Context, d *memory.Decoder, t *types.Type, p path.Node, rc *path.ResolveConfig) (*Value, error) { a, err := t.Alignment(ctx, d.MemoryLayout()) if err != nil { return nil, err } d.Align(uint64(a)) + typeId := t.TypeId switch t := t.Ty.(type) { case *types.Type_Pod: switch t.Pod { @@ -192,7 +199,7 @@ func Box(ctx context.Context, d *memory.Decoder, t *types.Type) (*Value, error) return nil, log.Err(ctx, nil, "Incomplete type in struct box") } - v, err := Box(ctx, d, elem) + v, err := Box(ctx, d, elem, p, rc) if err != nil { return nil, err } @@ -248,7 +255,33 @@ func Box(ctx context.Context, d *memory.Decoder, t *types.Type) (*Value, error) } case *types.Type_Pseudonym: if elem, ok := types.TryGetType(t.Pseudonym.Underlying); ok { - return Box(ctx, d, elem) + b, err := Box(ctx, d, elem, p, rc) + if err != nil { + return nil, err + } + + reflType, err := types.GetReflectedType(typeId) + if err != nil { + return nil, err + } + + if reflType.Implements(tyLinkable) { + // reflectively convert the underlying value back to what its + // api type should have been, then attempt to link through it. + v := reflect.New(reflType) + switch vv := b.Val.(*Value_Pod).Pod.Val.(type) { + case (*pod.Value_Uint64): + v.Elem().SetUint(vv.Uint64) + case (*pod.Value_Uint32): + v.Elem().SetUint(uint64(vv.Uint32)) + } + + if res, err := v.Interface().(path.Linker).Link(ctx, p, rc); err == nil { + b.Link = res.Path() + } + } + + return b, nil } case *types.Type_Array: if elem, ok := types.TryGetType(t.Array.ElementType); ok { @@ -256,7 +289,7 @@ func Box(ctx context.Context, d *memory.Decoder, t *types.Type) (*Value, error) Entries: []*Value{}, } for i := uint64(0); i < t.Array.Size; i++ { - v, err := Box(ctx, d, elem) + v, err := Box(ctx, d, elem, p, rc) if err != nil { return nil, err } @@ -270,7 +303,7 @@ func Box(ctx context.Context, d *memory.Decoder, t *types.Type) (*Value, error) } case *types.Type_Enum: if elem, ok := types.TryGetType(t.Enum.Underlying); ok { - return Box(ctx, d, elem) + return Box(ctx, d, elem, p, rc) } case *types.Type_Map: return nil, log.Err(ctx, nil, "Cannot decode map from memory") diff --git a/gapis/service/memory_box/box.proto b/gapis/service/memory_box/box.proto index 21387771c2..5fb70252d5 100644 --- a/gapis/service/memory_box/box.proto +++ b/gapis/service/memory_box/box.proto @@ -15,6 +15,7 @@ syntax = "proto3"; import "core/data/pod/pod.proto"; +import "gapis/service/path/path.proto"; package memory_box; option java_package = "com.google.gapid.proto.service.memory_box"; @@ -30,6 +31,7 @@ message Value { Array array = 6; Null null = 7; } + path.Any link = 8; } message Pointer { From 285fe6d7a985e90a7e08e12d9ecf8e6d7866c28f Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 18 Mar 2020 16:08:42 -0700 Subject: [PATCH 0193/1218] Upgrade go and all our go dependencies. Gets us to go1.14, from go1.12. --- tools/build/workspace.bzl | 8 ++--- tools/build/workspace_go.bzl | 65 +++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 8ef0c3cc79..74596d8aa1 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -38,8 +38,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "bazelbuild", project = "rules_go", - commit = "6fc21c78143ff1d4ea98100e8fd7a928d45abd00", # 0.18.6 - sha256 = "6356b0c591659b2da6f8149dfe7207a23d2cc41d3ed3932f0be3aa5dad7a4d2f", + commit = "a94abcb35d08aac590dac3a1ac5961cfb16caf05", # 0.22.1 + sha256 = "9b9cadda86ba1769cd944f17ccc2f5445de771b2d7322930929a106246cb0125", ) maybe_repository( @@ -48,8 +48,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "bazelbuild", project = "bazel-gazelle", - commit = "e443c54b396a236e0d3823f46c6a931e1c9939f2", # 0.17.0 - sha256 = "ca6dcacc34c159784f01f557dbb0dc5d1772d3b28f1145b51f888ecb3694af1a", + commit = "9b9f0226e01d10a70cbf268f9967cb715c8ff067", # 0.20.0 + sha256 = "def44e3a1af0f1ea63910e99f8ad5bd7760416abe165c1511b6b93f65ad10a97", ) maybe_repository( diff --git a/tools/build/workspace_go.bzl b/tools/build/workspace_go.bzl index b0da417d89..7366f4c491 100644 --- a/tools/build/workspace_go.bzl +++ b/tools/build/workspace_go.bzl @@ -26,36 +26,85 @@ def gapid_go_dependencies(): name = "com_github_google_go_github", organization = "google", project = "go-github", - commit = "a89ea1cdf79929726a9416663609269ada774da0", + commit = "2e3e74fa920e7d6278b7a9737ab5c8b7b1480294", # 29.0.3 importpath = "github.com/google/go-github", - sha256 = "a7b046d3c50362738d7e535ff1315df94021fd246337101021737a708fd7449d", + sha256 = "5c72eae85dd971e31776cc97e3cac7e57acdef253d896d649d9d520f7b990ea4", ) + # Dependency of com_github_google_go_github. _maybe(_github_go_repository, name = "com_github_google_go_querystring", organization = "google", project = "go-querystring", - commit = "53e6ce116135b80d037921a7fdd5138cf32d7a8a", + commit = "c8c88dbee036db4e4808d1f2ec8c2e15e11c3f80", importpath = "github.com/google/go-querystring", - sha256 = "d600db9461f2e0ce73b9c7a40ea598e0e128a00db5bf0b731b40585a6851cb12", + sha256 = "be509de2d315358db459f40262ca34d7dceb0d59d4119addf880562b10710853", ) _maybe(_github_go_repository, name = "com_github_pkg_errors", organization = "pkg", project = "errors", - commit = "248dadf4e9068a0b3e79f02ed0a610d935de5302", + commit = "614d223910a179a466c1767a985424175c39b465", # 0.9.1 importpath = "github.com/pkg/errors", - sha256 = "d19f68fe315e0f06fa050e6b39704da9968b8cad7c6e436d1baee6c647ed7d04", + sha256 = "49c7041442cc15211ee85175c06ffa6520c298b1826ed96354c69f16b6cfd13b", + ) + + _maybe(_github_go_repository, + name = "org_golang_google_grpc", + organization = "grpc", + project = "grpc-go", + commit = "142182889d38b76209f1d9f1d8e91d7608aff542", # 1.28.0 + importpath = "google.golang.org/grpc", + sha256 = "f969e1c33b79d4c03527b8163f257f50257ac9dcb488859182a548ea39724a4d", ) _maybe(_github_go_repository, name = "org_golang_x_crypto", organization = "golang", project = "crypto", - commit = "1a580b3eff7814fc9b40602fd35256c63b50f491", + commit = "1b76d66859c6111b3d5c3ea6600ea44dc188bf12", importpath = "golang.org/x/crypto", - sha256 = "80b56f1fb9f3f03c3ebd155b6e62c77a5f1309aaa7e747a9e6ff8e560ffd904e", + sha256 = "daaec7016b1d81d05505bd50534ef62b9fe3cf367b39ad805b14cec62e3648f3", + ) + + # Dependency of org_golang_x_tools. + _maybe(_github_go_repository, + name = "org_golang_x_mod", + organization = "golang", + project = "mod", + commit = "e5e73c1b9c72835114eb6daab038373d39515006", + importpath = "golang.org/x/mod", + sha256 = "5e727c7ec77372e0a37fc535e81d6f8b9423bdcbc66ee506994d3ac2c3ce704b", + ) + + _maybe(_github_go_repository, + name = "org_golang_x_net", + organization = "golang", + project = "net", + commit = "244492dfa37ae2ce87222fd06250a03160745faa", + importpath = "golang.org/x/net", + sha256 = "d3d90167ae827ee4a2fc2db7ce23142410974da41ca2e95f8832b57facdc7190", + ) + + # Dependency of org_golang_x_net. + _maybe(_github_go_repository, + name = "org_golang_x_text", + organization = "golang", + project = "text", + commit = "06d492aade888ab8698aad35476286b7b555c961", + importpath = "golang.org/x/text", + sha256 = "d0076e2957c45a9ded9853bd398257f4d8fd8fe74d3953a7049a0474629b78a2", + ) + + # Dependency of org_golang_x_mod. + _maybe(_github_go_repository, + name = "org_golang_x_xerrors", + organization = "golang", + project = "xerrors", + commit = "9bdfabe68543c54f90421aeb9a60ef8061b5b544", + importpath = "golang.org/x/xerrors", + sha256 = "757fe99de4d23e10a3343e9790866211ecac0458c5268da43e664a5abeee27e3", ) From d887c89cf45b130cef8cc898dd7eab1fa4714dfc Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 24 Mar 2020 16:42:50 -0700 Subject: [PATCH 0194/1218] Run gazelle and fix stuff for it. --- core/data/pod/BUILD.bazel | 3 ++- core/data/protoutil/testprotos/BUILD.bazel | 3 ++- core/image/BUILD.bazel | 3 ++- core/log/log_pb/BUILD.bazel | 3 ++- core/os/android/BUILD.bazel | 3 ++- core/os/android/apk/BUILD.bazel | 3 ++- core/os/device/BUILD.bazel | 3 ++- core/os/device/bind/BUILD.bazel | 3 ++- core/os/shell/command_example_test.go | 2 +- core/os/shell/command_test.go | 2 +- core/os/shell/stub/BUILD.bazel | 23 ++++--------------- core/os/shell/stub/stub_example_test.go | 2 -- core/stream/BUILD.bazel | 3 ++- gapic/src/main/BUILD.bazel | 1 + gapidapk/pkginfo/BUILD.bazel | 3 ++- gapil/bapi/BUILD.bazel | 3 ++- .../encoder/test/encoder_pb/BUILD.bazel | 4 ++-- gapir/replay_service/BUILD.bazel | 5 ++-- gapis/api/BUILD.bazel | 3 ++- gapis/api/test/test_pb/BUILD.bazel | 3 ++- gapis/api/vulkan/BUILD.bazel | 3 ++- gapis/api/vulkan/vulkan_pb/BUILD.bazel | 3 ++- gapis/capture/BUILD.bazel | 3 ++- gapis/memory/BUILD.bazel | 3 ++- gapis/memory/memory_pb/BUILD.bazel | 3 ++- gapis/perfetto/service/BUILD.bazel | 3 ++- gapis/replay/BUILD.bazel | 4 ++-- gapis/replay/protocol/BUILD.bazel | 3 ++- gapis/resolve/BUILD.bazel | 4 ++-- gapis/resolve/dependencygraph2/BUILD.bazel | 3 ++- gapis/resolve/initialcmds/BUILD.bazel | 1 + gapis/service/BUILD.bazel | 3 ++- gapis/service/box/BUILD.bazel | 3 ++- gapis/service/memory_box/BUILD.bazel | 3 ++- gapis/service/path/BUILD.bazel | 3 ++- gapis/service/severity/BUILD.bazel | 3 ++- gapis/service/types/BUILD.bazel | 3 ++- gapis/stringtable/BUILD.bazel | 3 ++- gapis/vertex/BUILD.bazel | 3 ++- test/robot/build/BUILD.bazel | 3 ++- test/robot/job/BUILD.bazel | 3 ++- test/robot/job/worker/BUILD.bazel | 3 ++- test/robot/master/BUILD.bazel | 3 ++- test/robot/record/BUILD.bazel | 3 ++- test/robot/replay/BUILD.bazel | 3 ++- test/robot/report/BUILD.bazel | 3 ++- test/robot/search/BUILD.bazel | 3 ++- test/robot/stash/BUILD.bazel | 3 ++- test/robot/stash/grpc/BUILD.bazel | 3 ++- test/robot/subject/BUILD.bazel | 3 ++- test/robot/trace/BUILD.bazel | 3 ++- 51 files changed, 100 insertions(+), 71 deletions(-) diff --git a/core/data/pod/BUILD.bazel b/core/data/pod/BUILD.bazel index fcad94ca2e..13b817d0b9 100644 --- a/core/data/pod/BUILD.bazel +++ b/core/data/pod/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/data/protoutil/testprotos/BUILD.bazel b/core/data/protoutil/testprotos/BUILD.bazel index da97aed901..386161e77d 100644 --- a/core/data/protoutil/testprotos/BUILD.bazel +++ b/core/data/protoutil/testprotos/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/image/BUILD.bazel b/core/image/BUILD.bazel index d2f629ffde..a4e1c2f3e9 100644 --- a/core/image/BUILD.bazel +++ b/core/image/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/log/log_pb/BUILD.bazel b/core/log/log_pb/BUILD.bazel index f605410bd4..c8bead4069 100644 --- a/core/log/log_pb/BUILD.bazel +++ b/core/log/log_pb/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/os/android/BUILD.bazel b/core/os/android/BUILD.bazel index f39a641e41..038f08e07e 100644 --- a/core/os/android/BUILD.bazel +++ b/core/os/android/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/os/android/apk/BUILD.bazel b/core/os/android/apk/BUILD.bazel index 35a436f976..7891fd45c8 100644 --- a/core/os/android/apk/BUILD.bazel +++ b/core/os/android/apk/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/os/device/BUILD.bazel b/core/os/device/BUILD.bazel index 398b654f17..b6518e4df9 100644 --- a/core/os/device/BUILD.bazel +++ b/core/os/device/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/os/device/bind/BUILD.bazel b/core/os/device/bind/BUILD.bazel index 4e5386c4f8..40dfc1caeb 100644 --- a/core/os/device/bind/BUILD.bazel +++ b/core/os/device/bind/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/core/os/shell/command_example_test.go b/core/os/shell/command_example_test.go index 34a9a67c4f..6e71d6b78b 100644 --- a/core/os/shell/command_example_test.go +++ b/core/os/shell/command_example_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux darwin +// +build linux,!android darwin,!ios package shell_test diff --git a/core/os/shell/command_test.go b/core/os/shell/command_test.go index 7d8c3fc0ed..6839b55a6f 100644 --- a/core/os/shell/command_test.go +++ b/core/os/shell/command_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux darwin +// +build linux,!android darwin,!ios package shell_test diff --git a/core/os/shell/stub/BUILD.bazel b/core/os/shell/stub/BUILD.bazel index d0b204515c..6992f3bd48 100644 --- a/core/os/shell/stub/BUILD.bazel +++ b/core/os/shell/stub/BUILD.bazel @@ -38,22 +38,9 @@ go_test( size = "small", srcs = ["stub_example_test.go"], embed = [":go_default_library"], - deps = select({ - "@io_bazel_rules_go//go/platform:darwin": [ - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/os/shell:go_default_library", - ], - "@io_bazel_rules_go//go/platform:linux": [ - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/os/shell:go_default_library", - ], - "@io_bazel_rules_go//go/platform:windows": [ - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/os/shell:go_default_library", - ], - "//conditions:default": [], - }), + deps = [ + "//core/event/task:go_default_library", + "//core/log:go_default_library", + "//core/os/shell:go_default_library", + ], ) diff --git a/core/os/shell/stub/stub_example_test.go b/core/os/shell/stub/stub_example_test.go index 6a9e50f6bd..187dd028a1 100644 --- a/core/os/shell/stub/stub_example_test.go +++ b/core/os/shell/stub/stub_example_test.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// +build linux darwin windows - package stub_test import ( diff --git a/core/stream/BUILD.bazel b/core/stream/BUILD.bazel index 137bedbe10..3d461a56b8 100644 --- a/core/stream/BUILD.bazel +++ b/core/stream/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapic/src/main/BUILD.bazel b/gapic/src/main/BUILD.bazel index 6f16bccb2a..f3a3b5424d 100644 --- a/gapic/src/main/BUILD.bazel +++ b/gapic/src/main/BUILD.bazel @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +load("@rules_proto//proto:defs.bzl", "proto_library") load("//:version.bzl", "agi_version") load("//tools/build:rules.bzl", "java_grpc_library") diff --git a/gapidapk/pkginfo/BUILD.bazel b/gapidapk/pkginfo/BUILD.bazel index d9ec3310a6..88f2076d5e 100644 --- a/gapidapk/pkginfo/BUILD.bazel +++ b/gapidapk/pkginfo/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapil/bapi/BUILD.bazel b/gapil/bapi/BUILD.bazel index a4bf70ad16..32bd4a3c85 100644 --- a/gapil/bapi/BUILD.bazel +++ b/gapil/bapi/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "bapi_proto", diff --git a/gapil/compiler/plugins/encoder/test/encoder_pb/BUILD.bazel b/gapil/compiler/plugins/encoder/test/encoder_pb/BUILD.bazel index ac76eb497f..48637f8781 100644 --- a/gapil/compiler/plugins/encoder/test/encoder_pb/BUILD.bazel +++ b/gapil/compiler/plugins/encoder/test/encoder_pb/BUILD.bazel @@ -1,5 +1,3 @@ -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") - # Copyright (C) 2018 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +13,8 @@ load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") # limitations under the License. load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") load("//tools/build:rules.bzl", "apic_template") apic_template( diff --git a/gapir/replay_service/BUILD.bazel b/gapir/replay_service/BUILD.bazel index 762674a4c8..2cff8739b3 100644 --- a/gapir/replay_service/BUILD.bazel +++ b/gapir/replay_service/BUILD.bazel @@ -12,9 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@gapid//tools/build:rules.bzl", "cc_copts", "cc_grpc_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") +load("//tools/build:rules.bzl", "cc_copts", "cc_grpc_library") proto_library( name = "replay_service_proto", diff --git a/gapis/api/BUILD.bazel b/gapis/api/BUILD.bazel index 833b0739b7..c989c6c99a 100644 --- a/gapis/api/BUILD.bazel +++ b/gapis/api/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/api/test/test_pb/BUILD.bazel b/gapis/api/test/test_pb/BUILD.bazel index d666465b2b..210619cba8 100644 --- a/gapis/api/test/test_pb/BUILD.bazel +++ b/gapis/api/test/test_pb/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") load("//tools/build:rules.bzl", "apic_template") apic_template( diff --git a/gapis/api/vulkan/BUILD.bazel b/gapis/api/vulkan/BUILD.bazel index 7417454e3c..8ab998c653 100644 --- a/gapis/api/vulkan/BUILD.bazel +++ b/gapis/api/vulkan/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") load("//tools/build:rules.bzl", "api_library", "apic_template") filegroup( diff --git a/gapis/api/vulkan/vulkan_pb/BUILD.bazel b/gapis/api/vulkan/vulkan_pb/BUILD.bazel index a6fdd9a550..9d65c2a7ed 100644 --- a/gapis/api/vulkan/vulkan_pb/BUILD.bazel +++ b/gapis/api/vulkan/vulkan_pb/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") load("//tools/build:rules.bzl", "apic_template") apic_template( diff --git a/gapis/capture/BUILD.bazel b/gapis/capture/BUILD.bazel index 765bc47967..8119120cca 100644 --- a/gapis/capture/BUILD.bazel +++ b/gapis/capture/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/memory/BUILD.bazel b/gapis/memory/BUILD.bazel index 2e97755257..4ba671b987 100644 --- a/gapis/memory/BUILD.bazel +++ b/gapis/memory/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/memory/memory_pb/BUILD.bazel b/gapis/memory/memory_pb/BUILD.bazel index a934893690..6fb6741ed3 100644 --- a/gapis/memory/memory_pb/BUILD.bazel +++ b/gapis/memory/memory_pb/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/perfetto/service/BUILD.bazel b/gapis/perfetto/service/BUILD.bazel index 804c3f757d..9272d42d6f 100644 --- a/gapis/perfetto/service/BUILD.bazel +++ b/gapis/perfetto/service/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/replay/BUILD.bazel b/gapis/replay/BUILD.bazel index 3fe336d246..35982eb9b7 100644 --- a/gapis/replay/BUILD.bazel +++ b/gapis/replay/BUILD.bazel @@ -1,5 +1,3 @@ -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") - # Copyright (C) 2018 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +13,8 @@ load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") # limitations under the License. load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/replay/protocol/BUILD.bazel b/gapis/replay/protocol/BUILD.bazel index 045649102e..7ca6c06a12 100644 --- a/gapis/replay/protocol/BUILD.bazel +++ b/gapis/replay/protocol/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/resolve/BUILD.bazel b/gapis/resolve/BUILD.bazel index 0f8c0659bf..6325b7b3fe 100644 --- a/gapis/resolve/BUILD.bazel +++ b/gapis/resolve/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", @@ -137,7 +138,6 @@ proto_library( go_proto_library( name = "resolve_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], importpath = "github.com/google/gapid/gapis/resolve", proto = ":resolve_proto", visibility = ["//visibility:public"], diff --git a/gapis/resolve/dependencygraph2/BUILD.bazel b/gapis/resolve/dependencygraph2/BUILD.bazel index 412cb36d83..bb7318b35d 100644 --- a/gapis/resolve/dependencygraph2/BUILD.bazel +++ b/gapis/resolve/dependencygraph2/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/resolve/initialcmds/BUILD.bazel b/gapis/resolve/initialcmds/BUILD.bazel index d616ec8d55..f4da74b1aa 100644 --- a/gapis/resolve/initialcmds/BUILD.bazel +++ b/gapis/resolve/initialcmds/BUILD.bazel @@ -14,6 +14,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "initialcmds_proto", diff --git a/gapis/service/BUILD.bazel b/gapis/service/BUILD.bazel index 61a632ec9f..665b363417 100644 --- a/gapis/service/BUILD.bazel +++ b/gapis/service/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/service/box/BUILD.bazel b/gapis/service/box/BUILD.bazel index 8248e73d11..e432630f5f 100644 --- a/gapis/service/box/BUILD.bazel +++ b/gapis/service/box/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/service/memory_box/BUILD.bazel b/gapis/service/memory_box/BUILD.bazel index b3e2f5b7ca..5b03f45063 100644 --- a/gapis/service/memory_box/BUILD.bazel +++ b/gapis/service/memory_box/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/service/path/BUILD.bazel b/gapis/service/path/BUILD.bazel index a9e05e04f3..89cf6729b9 100644 --- a/gapis/service/path/BUILD.bazel +++ b/gapis/service/path/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/service/severity/BUILD.bazel b/gapis/service/severity/BUILD.bazel index 6abfc89faa..38ba7dd4e5 100644 --- a/gapis/service/severity/BUILD.bazel +++ b/gapis/service/severity/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") proto_library( name = "severity_proto", diff --git a/gapis/service/types/BUILD.bazel b/gapis/service/types/BUILD.bazel index 9d30311665..366bec47f1 100644 --- a/gapis/service/types/BUILD.bazel +++ b/gapis/service/types/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/stringtable/BUILD.bazel b/gapis/stringtable/BUILD.bazel index 269bbf8b1a..38856789a8 100644 --- a/gapis/stringtable/BUILD.bazel +++ b/gapis/stringtable/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/gapis/vertex/BUILD.bazel b/gapis/vertex/BUILD.bazel index 8b00bf5b9b..96a92da9a5 100644 --- a/gapis/vertex/BUILD.bazel +++ b/gapis/vertex/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/build/BUILD.bazel b/test/robot/build/BUILD.bazel index bc5ec8bc3e..1838f5c498 100644 --- a/test/robot/build/BUILD.bazel +++ b/test/robot/build/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/job/BUILD.bazel b/test/robot/job/BUILD.bazel index dc60e0926b..f455ba897d 100644 --- a/test/robot/job/BUILD.bazel +++ b/test/robot/job/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/job/worker/BUILD.bazel b/test/robot/job/worker/BUILD.bazel index 2df38d0966..085bbf44a0 100644 --- a/test/robot/job/worker/BUILD.bazel +++ b/test/robot/job/worker/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/master/BUILD.bazel b/test/robot/master/BUILD.bazel index 922c4c8a0d..cea39a2167 100644 --- a/test/robot/master/BUILD.bazel +++ b/test/robot/master/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/record/BUILD.bazel b/test/robot/record/BUILD.bazel index 00f45ecba4..2ad8cdb3cb 100644 --- a/test/robot/record/BUILD.bazel +++ b/test/robot/record/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/replay/BUILD.bazel b/test/robot/replay/BUILD.bazel index de7fc7272e..10aa18c970 100644 --- a/test/robot/replay/BUILD.bazel +++ b/test/robot/replay/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/report/BUILD.bazel b/test/robot/report/BUILD.bazel index e0e8e3c19f..7cdd809129 100644 --- a/test/robot/report/BUILD.bazel +++ b/test/robot/report/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/search/BUILD.bazel b/test/robot/search/BUILD.bazel index e123442f0f..c3c40c8b61 100644 --- a/test/robot/search/BUILD.bazel +++ b/test/robot/search/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/stash/BUILD.bazel b/test/robot/stash/BUILD.bazel index e6e81fc806..fe94020896 100644 --- a/test/robot/stash/BUILD.bazel +++ b/test/robot/stash/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/stash/grpc/BUILD.bazel b/test/robot/stash/grpc/BUILD.bazel index 31bf15e131..734f76b77e 100644 --- a/test/robot/stash/grpc/BUILD.bazel +++ b/test/robot/stash/grpc/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/subject/BUILD.bazel b/test/robot/subject/BUILD.bazel index 2d52be0b46..7f2a530cf2 100644 --- a/test/robot/subject/BUILD.bazel +++ b/test/robot/subject/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", diff --git a/test/robot/trace/BUILD.bazel b/test/robot/trace/BUILD.bazel index d00b8c1cfa..c5123ca746 100644 --- a/test/robot/trace/BUILD.bazel +++ b/test/robot/trace/BUILD.bazel @@ -12,8 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") go_library( name = "go_default_library", From a8fba5902be18419ecbe19dc2d7f4d084f830c57 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 15:05:20 -0700 Subject: [PATCH 0195/1218] Make the stacktrace test stable by disabling inlining. --- core/fault/stacktrace/stacktrace_test.go | 29 ++++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/core/fault/stacktrace/stacktrace_test.go b/core/fault/stacktrace/stacktrace_test.go index 8e379ba5b1..fd9a4c02f4 100644 --- a/core/fault/stacktrace/stacktrace_test.go +++ b/core/fault/stacktrace/stacktrace_test.go @@ -31,9 +31,16 @@ import ( // be very careful re-ordering the top of this file, the stack trace captures line numbers //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//go:noinline func nested3() stacktrace.Callstack { return nested2() } + +//go:noinline func nested2() stacktrace.Callstack { return nested1() } + +//go:noinline func nested1() stacktrace.Callstack { return stacktrace.Capture() } + +//go:noinline func init() { for i := range traces { traces[i].stack = traces[i].fun() @@ -60,30 +67,22 @@ var ( traces = []traceEntry{{ fun: stacktrace.Capture, expect: [][]string{{ - "⇒ core/fault/stacktrace/stacktrace_test.go@39:init.0", + "⇒ core/fault/stacktrace/stacktrace_test.go@46:init.0", }}, }, { fun: nested1, expect: [][]string{{ - "⇒ core/fault/stacktrace/stacktrace_test.go@36:nested1", - "⇒ core/fault/stacktrace/stacktrace_test.go@39:init.0", + "⇒ core/fault/stacktrace/stacktrace_test.go@41:nested1", + "⇒ core/fault/stacktrace/stacktrace_test.go@46:init.0", }}, }, { fun: nested3, expect: [][]string{ { - "⇒ core/fault/stacktrace/stacktrace_test.go@36:nested1", - "⇒ core/fault/stacktrace/stacktrace_test.go@35:nested2", - "⇒ core/fault/stacktrace/stacktrace_test.go@34:nested3", - "⇒ core/fault/stacktrace/stacktrace_test.go@39:init.0", - }, - // Compiling with optimisations can lead to the following - // stack trace: - { - "⇒ core/fault/stacktrace/stacktrace_test.go@36:nested1", - "⇒ core/fault/stacktrace/stacktrace_test.go@34:nested3", - "⇒ core/fault/stacktrace/stacktrace_test.go@34:nested3", - "⇒ core/fault/stacktrace/stacktrace_test.go@39:init.0", + "⇒ core/fault/stacktrace/stacktrace_test.go@41:nested1", + "⇒ core/fault/stacktrace/stacktrace_test.go@38:nested2", + "⇒ core/fault/stacktrace/stacktrace_test.go@35:nested3", + "⇒ core/fault/stacktrace/stacktrace_test.go@46:init.0", }, }, }} From 86ef174c53d520dffc5d828dd8835dbe742e62a0 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Thu, 19 Mar 2020 13:35:19 -0700 Subject: [PATCH 0196/1218] Upgrade protobuf C++. --- core/os/device/deviceinfo/cc/instance.cpp | 2 +- core/os/device/deviceinfo/cc/query.cpp | 2 +- gapis/perfetto/cc/processor.cpp | 2 +- tools/build/workspace.bzl | 14 ++++++++++++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/core/os/device/deviceinfo/cc/instance.cpp b/core/os/device/deviceinfo/cc/instance.cpp index d7aeb03996..62393cb373 100644 --- a/core/os/device/deviceinfo/cc/instance.cpp +++ b/core/os/device/deviceinfo/cc/instance.cpp @@ -31,7 +31,7 @@ device_instance get_device_instance() { } // Reserialize the instance with the ID field. - out.size = instance->ByteSize(); + out.size = instance->ByteSizeLong(); out.data = new uint8_t[out.size]; instance->SerializeToArray(out.data, out.size); diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index d84b21b369..3a37c0979f 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -52,7 +52,7 @@ void deviceInstanceID(device::Instance* instance) { auto id = instance->mutable_id(); // Serialize the instance so we can hash it. - auto proto_size = instance->ByteSize(); + auto proto_size = instance->ByteSizeLong(); auto proto_data = new uint8_t[proto_size]; instance->SerializeToArray(proto_data, proto_size); diff --git a/gapis/perfetto/cc/processor.cpp b/gapis/perfetto/cc/processor.cpp index 5a4e8d332d..2e61c0d45c 100644 --- a/gapis/perfetto/cc/processor.cpp +++ b/gapis/perfetto/cc/processor.cpp @@ -138,7 +138,7 @@ result execute_query(processor processor, const char* query) { } result res; - res.size = raw.ByteSize(); + res.size = raw.ByteSizeLong(); res.data = new uint8_t[res.size]; raw.SerializeWithCachedSizesToArray(res.data); return res; diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 74596d8aa1..4d957b8291 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -58,8 +58,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "google", project = "protobuf", - commit = "815ff7e1fb2d417d5aebcbf5fc46e626b18dc834", # Head of 3.8.x branch - sha256 = "083646275522dc57e145f769c2daf39d469757bafcc5b7d09b119dfaf1b873b8", + commit = "d0bfd5221182da1a7cc280f3337b5e41a89539cf", # 3.11.4 + sha256 = "c5fd8f99f0d30c6f9f050bf008e021ccc70d7645ac1f64679c6038e07583b2f3", repo_mapping = {"@zlib": "@net_zlib"}, ) @@ -75,6 +75,16 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): ) _grpc_deps(locals) + maybe_repository( + github_repository, + name = "rules_python", + locals = locals, + organization = "bazelbuild", + project = "rules_python", + commit = "9150caa9d857e3768a4cf5ef6c3e88668b7ec84f", # 0.0.1 + sha256 = "8eece92b8e286ac60b2847f0f00d0a949b3b0192669ffcc9e8d3c8365f889d1e", + ) + ########################################### # Now get all our other non-go dependencies From 1a11211d33d92abcdc23724132df5f71637ac4bb Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 11:39:25 -0700 Subject: [PATCH 0197/1218] Upgrade gRPC. The latest version that works is 1.22.1. See https://github.com/grpc/grpc/issues/22436 --- tools/build/workspace.bzl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 4d957b8291..b88a6e3004 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -69,9 +69,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "grpc", project = "grpc", - # v1.20.1 - commit = "7741e806a213cba63c96234f16d712a8aa101a49", - sha256 = "9ed7d944d8d07deac365c9edcda10ce8159c1436119e1b0792a1e830cb20606c", + commit = "c599e6a922a80e40e24a2d3c994a6dd51046796b", # 1.22.1 + sha256 = "d17ead923510b3c8a03eec623fffe4cba64d43e10b3695f027a1c8f10c03756a", ) _grpc_deps(locals) @@ -360,7 +359,7 @@ def _grpc_deps(locals): ) native.bind( - name = "zlib", + name = "madler_zlib", actual = "@net_zlib//:z", ) From 2a6a1d9691858e38aadeecf61639de9c37a67607 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 14:14:56 -0700 Subject: [PATCH 0198/1218] Upgrade googletest. --- tools/build/workspace.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index b88a6e3004..aeb49dccbc 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -93,8 +93,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "google", project = "googletest", - commit = "62dbaa2947f7d058ea7e16703faea69b1134b024", - sha256 = "c86258bf52616f5fa52a622ba58ce700eb2dd9f6ec15ff13ad2b2a579afb9c67", + commit = "703bd9caab50b139428cea1aaff9974ebee5742e", # 1.10.0 + sha256 = "2db427be8b258ad401177c411c2a7c2f6bc78548a04f1a23576cc62616d9cd38", ) maybe_repository( From 4b050114d845365e8d842171de26bfb3cc4e8bd7 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 14:22:39 -0700 Subject: [PATCH 0199/1218] Upgrade ASTC encoder. --- core/image/astc/astc.cc | 9 +++++++-- tools/build/workspace.bzl | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/core/image/astc/astc.cc b/core/image/astc/astc.cc index ec6b04b324..571b8b668c 100644 --- a/core/image/astc/astc.cc +++ b/core/image/astc/astc.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "astc.h" #include "third_party/astc-encoder/Source/astc_codec_internals.h" @@ -25,7 +27,10 @@ int print_diagnostics = 0; // Functions that are used in compilation units we depend on, but don't actually // use. int astc_codec_unlink(const char *filename) { return 0; } -void astc_codec_internal_error(const char *filename, int linenum) {} +void astc_codec_internal_error(const char *filename, int linenum) { + printf("ASTC error: %s:%d\n", filename, linenum); + exit(1); +} astc_codec_image *load_ktx_uncompressed_image(const char *filename, int padding, int *result) { return 0; } astc_codec_image *load_dds_uncompressed_image(const char *filename, int padding, int *result) { return 0; } astc_codec_image *load_tga_image(const char *tga_filename, int padding, int *result) { return 0; } @@ -81,4 +86,4 @@ extern "C" void decompress_astc( } } } -} \ No newline at end of file +} diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index aeb49dccbc..176be3841a 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -103,9 +103,9 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "ARM-software", project = "astc-encoder", - commit = "b6bf6e7a523ddafdb8cfdc84b068d8fe70ffb45e", + commit = "de61b3511fa2c3e2e0ae87f5a7874a928e3a3111", # 1.x (March 2020) build_file = "@gapid//tools/build/third_party:astc-encoder.BUILD", - sha256 = "7877eb08c61d8b258c5d4690e924090cb7f303e8be6d74e9a9a611d3177bb5ae", + sha256 = "ac3318f1120e66d195fe4c5d3c413e20f9eeddc4c378349eeb906ca1d405d4f2", ) maybe_repository( From 4450d8c76f1d722c088d1b68aa96d17077aba980 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 15:44:00 -0700 Subject: [PATCH 0200/1218] Upgrade glslang. It now has its own bazel BUILD file. --- gapis/shadertools/cc/BUILD.bazel | 2 + gapis/shadertools/cc/libmanager.cpp | 13 +++++- tools/build/third_party/glslang.BUILD | 60 --------------------------- tools/build/workspace.bzl | 5 +-- 4 files changed, 15 insertions(+), 65 deletions(-) delete mode 100644 tools/build/third_party/glslang.BUILD diff --git a/gapis/shadertools/cc/BUILD.bazel b/gapis/shadertools/cc/BUILD.bazel index 5af7d97a18..a637bfbba3 100644 --- a/gapis/shadertools/cc/BUILD.bazel +++ b/gapis/shadertools/cc/BUILD.bazel @@ -25,6 +25,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "@glslang", + "@glslang//:SPIRV", "@spirv_cross//:spirv-cross", "@spirv_tools//:spirv-tools", ], @@ -39,6 +40,7 @@ cc_test( args = ["$(location spirv_example.spv)"], copts = cc_copts(), data = ["spirv_example.spv"], + linkstatic = 1, deps = [ ":cc", ], diff --git a/gapis/shadertools/cc/libmanager.cpp b/gapis/shadertools/cc/libmanager.cpp index 7e4775f1ad..600c7709c4 100644 --- a/gapis/shadertools/cc/libmanager.cpp +++ b/gapis/shadertools/cc/libmanager.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "third_party/SPIRV-Tools/include/spirv-tools/libspirv.hpp" -#include "third_party/glslang/SPIRV/GlslangToSpv.h" +#include "GlslangToSpv.h" +#include "spirv-tools/libspirv.hpp" #include "libmanager.h" @@ -109,6 +109,15 @@ const TBuiltInResource DefaultTBuiltInResource = { /* .MaxCullDistances = */ 8, /* .MaxCombinedClipAndCullDistances = */ 8, /* .MaxSamples = */ 4, + /* .maxMeshOutputVerticesNV = */ 256, + /* .maxMeshOutputPrimitivesNV = */ 512, + /* .maxMeshWorkGroupSizeX_NV = */ 32, + /* .maxMeshWorkGroupSizeY_NV = */ 1, + /* .maxMeshWorkGroupSizeZ_NV = */ 1, + /* .maxTaskWorkGroupSizeX_NV = */ 32, + /* .maxTaskWorkGroupSizeY_NV = */ 1, + /* .maxTaskWorkGroupSizeZ_NV = */ 1, + /* .maxMeshViewCountNV = */ 4, /* .limits = */ { /* .nonInductiveForLoops = */ 1, diff --git a/tools/build/third_party/glslang.BUILD b/tools/build/third_party/glslang.BUILD deleted file mode 100644 index c9260262ac..0000000000 --- a/tools/build/third_party/glslang.BUILD +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@gapid//tools/build:rules.bzl", "cc_copts") - -cc_library( - name = "glslang", - srcs = glob([ - "glslang/GenericCodeGen/*.h", - "glslang/GenericCodeGen/*.cpp", - "glslang/Include/*.h", - "glslang/MachineIndependent/**/*.h", - "glslang/MachineIndependent/**/*.cpp", - "glslang/OSDependent/*.h", - "glslang/OSDependent/*.cpp", - "glslang/Public/*.h", - "glslang/Public/*.cpp", - "OGLCompilersDLL/*.h", - "OGLCompilersDLL/*.cpp", - "SPIRV/*.h", - "SPIRV/*.cpp", - "SPIRV/*.hpp", - ]) + select({ - "@gapid//tools/build:windows": ["glslang/OSDependent/Windows/ossource.cpp"], - "//conditions:default": ["glslang/OSDependent/Unix/ossource.cpp"], - }), - hdrs = glob([ - "glslang/Include/*.h", - "glslang/Public/*.h", - "glslang/MachineIndependent/*.h", - "SPIRV/*.h", - ]), - copts = cc_copts() + [ - "-DNV_EXTENSIONS", - "-Wno-unused-variable", - ] + select({ - "@gapid//tools/build:linux": [ - "-Wno-error=class-memaccess", # TODO(#3100): Remove this when glslang fixes the bug - "-Wno-maybe-uninitialized", - ], - "//conditions:default": [], - }), - include_prefix = "third_party/glslang", - linkopts = select({ - "@gapid//tools/build:windows": [], - "//conditions:default": ["-lpthread"], - }), - visibility = ["//visibility:public"], -) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 176be3841a..7850c178e0 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -133,9 +133,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "KhronosGroup", project = "glslang", - commit = "97e35420a62e112de57a31b265e020662883ef8f", - build_file = "@gapid//tools/build/third_party:glslang.BUILD", - sha256 = "4d73467f35b8ac15cc06206cbd8be2802afc630bbfc4e9504b81e711457dde49", + commit = "8db9eccc0baf30c9d22c496ab28db0fe1e4e97c5", # 8.13.3559 + sha256 = "5c11a228d41ec011918b9c8beb60b6556745d30c8c856ec622beab5c5469152d", ) maybe_repository( From 0de824e401f9b5cde23d07e0597ce7584053aaa5 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 15:46:13 -0700 Subject: [PATCH 0201/1218] Upgrade stb. --- tools/build/workspace.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 7850c178e0..650474c914 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -153,9 +153,9 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): name = "stb", locals = locals, remote = "https://github.com/nothings/stb", - commit = "f67165c2bb2af3060ecae7d20d6f731173485ad0", + commit = "f54acd4e13430c5122cab4ca657705c84aa61b08", build_file = "@gapid//tools/build/third_party:stb.BUILD", - shallow_since = "1572280202 -0700", + shallow_since = "1580905940 -0800", ) maybe_repository( From 4fb027f900f9979c43d21e660b2f580d270e521e Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 15:47:44 -0700 Subject: [PATCH 0202/1218] Upgrade lss. --- tools/build/workspace.bzl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 650474c914..f1b6917b33 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -163,9 +163,9 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): name = "lss", locals = locals, remote = "https://chromium.googlesource.com/linux-syscall-support", - commit = "e6527b0cd469e3ff5764785dadcb39bf7d787154", + commit = "fd00dbbd0c06a309c657d89e9430143b179ff6db", build_file = "@gapid//tools/build/third_party:lss.BUILD", - shallow_since = "1508355462 +0000", + shallow_since = "1583885669 +0000", ) maybe_repository( From a66bdfaff851908a6c64ea74e8afed349bf95fd6 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 16:04:30 -0700 Subject: [PATCH 0203/1218] Upgrade the SPIRV utilities. Some of them now have their own bazel BUILD files. --- gapis/shadertools/BUILD.bazel | 2 +- gapis/shadertools/cc/BUILD.bazel | 2 +- gapis/shadertools/shadertools_test.go | 2 +- tools/build/third_party/spirv-cross.BUILD | 4 +- tools/build/third_party/spirv-headers.BUILD | 32 ----------- tools/build/third_party/spirv-tools.BUILD | 60 --------------------- tools/build/workspace.bzl | 18 +++---- 7 files changed, 13 insertions(+), 107 deletions(-) delete mode 100644 tools/build/third_party/spirv-headers.BUILD delete mode 100644 tools/build/third_party/spirv-tools.BUILD diff --git a/gapis/shadertools/BUILD.bazel b/gapis/shadertools/BUILD.bazel index 9f8f76a9ce..58a722bd81 100644 --- a/gapis/shadertools/BUILD.bazel +++ b/gapis/shadertools/BUILD.bazel @@ -19,7 +19,7 @@ go_library( srcs = ["shadertools.go"], cdeps = [ "//gapis/shadertools/cc:cc", - "@spirv_tools//:spirv-tools", + "@spirv_tools//:spirv_tools", "@spirv_reflect//:spirv-reflect", ], cgo = True, diff --git a/gapis/shadertools/cc/BUILD.bazel b/gapis/shadertools/cc/BUILD.bazel index a637bfbba3..742aa50cd2 100644 --- a/gapis/shadertools/cc/BUILD.bazel +++ b/gapis/shadertools/cc/BUILD.bazel @@ -27,7 +27,7 @@ cc_library( "@glslang", "@glslang//:SPIRV", "@spirv_cross//:spirv-cross", - "@spirv_tools//:spirv-tools", + "@spirv_tools", ], ) diff --git a/gapis/shadertools/shadertools_test.go b/gapis/shadertools/shadertools_test.go index bc8b557ce7..5fa84e5ce2 100644 --- a/gapis/shadertools/shadertools_test.go +++ b/gapis/shadertools/shadertools_test.go @@ -136,7 +136,7 @@ void main() { 0x0000000d, 0x0000000d, 0x00040017, 0x00000010, 0x00000009, 0x00000004, 0x0004002b, 0x00000009, 0x00000011, 0x00000000, 0x0004002b, 0x00000007, - 0x00000012, 0x4b7ffff0, 0x00050036, 0x00000005, + 0x00000012, 0x4b7fffff, 0x00050036, 0x00000005, 0x00000002, 0x00000000, 0x00000006, 0x000200f8, 0x00000013, 0x0004003d, 0x0000000a, 0x00000014, 0x00000004, 0x00050062, 0x00000010, 0x00000015, diff --git a/tools/build/third_party/spirv-cross.BUILD b/tools/build/third_party/spirv-cross.BUILD index 172c2d169a..4735840aec 100644 --- a/tools/build/third_party/spirv-cross.BUILD +++ b/tools/build/third_party/spirv-cross.BUILD @@ -25,7 +25,7 @@ cc_library( include_prefix = "third_party/SPIRV-Cross", visibility = ["//visibility:public"], deps = [ - "@spirv_headers//:spirv-headers", - "@spirv_tools//:spirv-tools", + "@spirv_headers//:spirv_c_headers", + "@spirv_tools", ], ) diff --git a/tools/build/third_party/spirv-headers.BUILD b/tools/build/third_party/spirv-headers.BUILD deleted file mode 100644 index 5e117ac71d..0000000000 --- a/tools/build/third_party/spirv-headers.BUILD +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cc_library( - name = "spirv-internal", - hdrs = glob(["include/spirv/**/*.h"]), - strip_include_prefix = "include/", - visibility = ["//visibility:private"], -) - -cc_library( - name = "spirv-headers", - hdrs = [ - "include/spirv/unified1/spirv.hpp", - ], - include_prefix = "third_party/SPIRV-Headers/", - visibility = ["//visibility:public"], - deps = [ - ":spirv-internal", - ], -) diff --git a/tools/build/third_party/spirv-tools.BUILD b/tools/build/third_party/spirv-tools.BUILD deleted file mode 100644 index e677b99130..0000000000 --- a/tools/build/third_party/spirv-tools.BUILD +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -cc_library( - name = "spirv-include", - hdrs = glob([ - "include/**/*.h", - "include/**/*.hpp", - ]), - strip_include_prefix = "include/", - visibility = ["//visibility:private"], -) - -cc_library( - name = "spirv-source", - hdrs = glob([ - "source/**/*.h", - "source/**/*.inc", - ]), - strip_include_prefix = "source/", - visibility = ["//visibility:private"], - deps = [ - "@gapid//tools/build/third_party:spirv-tools-generated", - "@spirv_headers//:spirv-headers", - ], -) - -cc_library( - name = "spirv-tools", - srcs = glob([ - "*.h", - "*.cpp", - "*.hpp", - "source/**/*.h", - "source/**/*.cpp", - "source/**/*.hpp", - ]), - hdrs = glob([ - "include/spirv-tools/*", - "source/**/*.h", - ]), - include_prefix = "third_party/SPIRV-Tools/", - visibility = ["//visibility:public"], - deps = [ - ":spirv-include", - ":spirv-source", - "@spirv_headers//:spirv-headers", - ], -) diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index f1b6917b33..75687c6558 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -211,9 +211,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "KhronosGroup", project = "SPIRV-Headers", - commit = "9f6846f973a1ef53790e75b9190820ab1557434f", - build_file = "@gapid//tools/build/third_party:spirv-headers.BUILD", - sha256 = "1980cefd605c440241f5c948eb4446412166b6df1ad133bf74c47180939477d5", + commit = "f8bf11a0253a32375c32cad92c841237b96696c0", + sha256 = "2ca7c37db06ab526c8c5c31767a0bbdbd30de74909dc1a4900302d7a8f537de7", ) maybe_repository( @@ -222,9 +221,9 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "KhronosGroup", project = "SPIRV-Cross", - commit = "ed55e0ac6d797a338e7c19dad785237f0efc4d86", + commit = "871c85d7f0edc6b613e3959bc51d13bfbc2fe2df", build_file = "@gapid//tools/build/third_party:spirv-cross.BUILD", - sha256 = "a6decf21a137e63f5e9dc01b716c7a905c54eef23fe6a7910058fd253460cec0", + sha256 = "6aba055d6a9a7c33ec2761c4883b21c9d67c7fef2550797cea677a77fd65055a", ) maybe_repository( @@ -233,9 +232,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "KhronosGroup", project = "SPIRV-Tools", - commit = "8d8a71278bf9e83dd0fb30d5474386d30870b74d", - build_file = "@gapid//tools/build/third_party:spirv-tools.BUILD", - sha256 = "8b1dfe726ea9047ef679baf2d40dfbf090e70406512358d236e54a8234e71eae", + commit = "60104cd97446877dad8ed1010a635218937a2f18", + sha256 = "6050c012fec919087ebc3b083b24f874648fc1593b55ac8e3742df760aec19fc", ) maybe_repository( @@ -244,9 +242,9 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): locals = locals, organization = "chaoticbob", project = "SPIRV-Reflect", - commit = "a861e587bdc924c49272873bbc1744928bc51aac", + commit = "3c77a11472a1da7830d055306b4299c5e2398e7c", build_file = "@gapid//tools/build/third_party:spirv-reflect.BUILD", - sha256 = "da636883f8d31fa5d1a8722374b92e76bc1f19ec7c125882c843079623f1c13a", + sha256 = "1af7c64657db1af191d7b8f12928d63159e1c1eafdbedac0b4add905d0430e8c", ) maybe_repository( From f5d06f0468b95ca7e14ec94f88c975c157bb40b9 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 16:52:57 -0700 Subject: [PATCH 0204/1218] Upgrade Java gRPC. --- .classpath | 2 + gapic/src/main/BUILD.bazel | 1 + tools/build/rules/grpc.bzl | 32 +++---- .../build/third_party/gapic_third_party.BUILD | 2 + tools/build/workspace_gapic.bzl | 86 ++++++++++++------- 5 files changed, 71 insertions(+), 52 deletions(-) diff --git a/.classpath b/.classpath index 0fe74dbda3..d89ee43093 100644 --- a/.classpath +++ b/.classpath @@ -29,6 +29,7 @@ + @@ -37,6 +38,7 @@ + diff --git a/gapic/src/main/BUILD.bazel b/gapic/src/main/BUILD.bazel index f3a3b5424d..430a70ff51 100644 --- a/gapic/src/main/BUILD.bazel +++ b/gapic/src/main/BUILD.bazel @@ -45,6 +45,7 @@ java_grpc_library( srcs = ["//gapis/service:service_proto"], deps = [ ":protos", + "@com_google_protobuf//:protobuf_java", "@gapic_third_party//:grpc", "@gapic_third_party//:guava", ], diff --git a/tools/build/rules/grpc.bzl b/tools/build/rules/grpc.bzl index 85fbc71d57..61e6280df3 100644 --- a/tools/build/rules/grpc.bzl +++ b/tools/build/rules/grpc.bzl @@ -16,29 +16,23 @@ def _gen_java_source_impl(ctx): # Use .jar since .srcjar makes protoc think output will be a directory srcdotjar = ctx.actions.declare_file(ctx.label.name + "-src.jar") protos = [f for dep in ctx.attr.srcs for f in dep[ProtoInfo].direct_sources] - includes = [f for dep in ctx.attr.srcs for f in dep[ProtoInfo].transitive_imports.to_list()] - - arguments = [ - "--plugin=protoc-gen-grpc-java=" + ctx.executable._plugin.path, - "--grpc-java_out=" + srcdotjar.path, - ] - - for include in includes: - directory = include.path - if directory.startswith("external"): - external_sep = directory.find("/") - repository_sep = directory.find("/", external_sep + 1) - arguments += ["--proto_path=" + directory[:repository_sep]] - else: - arguments += ["--proto_path=."] - arguments += [proto.path for proto in protos] + dsi = [f for dep in ctx.attr.srcs for f in dep[ProtoInfo].transitive_descriptor_sets.to_list()] + + args = ctx.actions.args() + args.add(ctx.executable._plugin, format = "--plugin=protoc-gen-rpc-plugin=%s") + args.add(srcdotjar, format = "--rpc-plugin_out=%s") + args.add_joined("--descriptor_set_in", dsi, + join_with = ctx.host_configuration.host_path_separator, + uniquify = True, + ) + args.add_all(protos) ctx.actions.run( - inputs = protos + includes, + inputs = protos + dsi, outputs = [srcdotjar], tools = [ctx.executable._protoc, ctx.executable._plugin], executable = ctx.executable._protoc, - arguments = arguments, + arguments = [args], use_default_shell_env = True, ) @@ -61,7 +55,7 @@ _gen_java_source = rule( cfg = "host", ), "_plugin": attr.label( - default = Label("@com_github_grpc_java//:protoc-gen-java"), + default = Label("@com_github_grpc_java//compiler:grpc_java_plugin"), executable = True, cfg = "host", ), diff --git a/tools/build/third_party/gapic_third_party.BUILD b/tools/build/third_party/gapic_third_party.BUILD index 021cfa66a2..86e678cc18 100644 --- a/tools/build/third_party/gapic_third_party.BUILD +++ b/tools/build/third_party/gapic_third_party.BUILD @@ -19,6 +19,7 @@ package(default_visibility = ["//visibility:public"]) java_library( name = "grpc", exports = [ + "{{io_grpc_api}}", "{{io_grpc_context}}", "{{io_grpc_core}}", "{{io_grpc_okhttp}}", @@ -27,6 +28,7 @@ java_library( "{{io_grpc_stub}}", "{{io_opencensus_api}}", "{{io_opencensus_contrib_grpc_metrics}}", + "{{io_perfmark_api}}", "{{javax_annotation_api}}", ], ) diff --git a/tools/build/workspace_gapic.bzl b/tools/build/workspace_gapic.bzl index b762e1609b..04d957268b 100644 --- a/tools/build/workspace_gapic.bzl +++ b/tools/build/workspace_gapic.bzl @@ -33,66 +33,74 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local locals = locals, organization = "grpc", project = "grpc-java", - commit = "009c51f2f793aabf516db90a14a52da2b613aa21", - build_file = "@gapid//tools/build/third_party:grpc_java.BUILD", - sha256 = "ffb06532376cfc78742d2ac5cbf244deb2885d0464ac8ab51de0dfdf408ec517" + commit = "3dbd250eae2c5e4f4e5e7046c6573805cc0dcc29", # 1.28.0 + sha256 = "988cde6fa4cbbbdad4b13c646be17d079ae961a23f4479f6520aaed3baab019b" ) if not no_maven: # gRPC and it's dependencies. ######################################################################## + maybe_repository( + maven_jar, + name = "io_grpc_api", + locals = locals, + artifact = "io.grpc:grpc-api:1.28.0", + sha256 = "10db0e02a85601d38da1b77bfcd7ae08f56b719a5e22aae9894a19c64b0fa8ce", + sha256_src = "a1ecf073671930e4883525cfa11850f04ba78b73f1e8434b81a0b2bf9b2f5927", + ) + maybe_repository( maven_jar, name = "io_grpc_context", locals = locals, - artifact = "io.grpc:grpc-context:1.16.1", - sha256 = "3a8d6548308bd100c61e1c399a1a32f601f81b4162d30f04872c05a2a5b824b9", - sha256_src = "027e241d4fd675392c957cbb4df368e4babdad52a7bef9d13c70d3e2fbe406a1", + artifact = "io.grpc:grpc-context:1.28.0", + sha256 = "cc57df006555be067af2a6ae9c6510bd7ed40a2dc1af278ceb4e491ce7f184de", + sha256_src = "d0f932244bee0f4c497646b5d94baa13877f4eddc4623ec6007dd5698253b421", ) maybe_repository( maven_jar, name = "io_grpc_core", locals = locals, - artifact = "io.grpc:grpc-core:1.16.1", - sha256 = "4b20fb3bd4b07e284ac639ce7372483f83050fd67962fa628d353c762571e964", - sha256_src = "12a6508ea698786860f9a0849caad4df85139d9c7a484eaf9bed259419f93977", + artifact = "io.grpc:grpc-core:1.28.0", + sha256 = "be7754fd1bcc58d25009e2f8aff5d5bb243ca0b8acf969b77b2ee606c2a1fcc3", + sha256_src = "6943ae4fbef30cd9192213fd220a62a60f751048ee11c78cce277f95d3a36101", ) maybe_repository( maven_jar, name = "io_grpc_okhttp", locals = locals, - artifact = "io.grpc:grpc-okhttp:1.16.1", - sha256 = "c6f804d5bdf33a19c414b2e5743d647f3daabc261813abb0f9013c60ad6ace94", - sha256_src = "9ddc86ed5a1612ee8e3cd11a5d4601a770fd231591c88270db3c8a8b59a6c39c", + artifact = "io.grpc:grpc-okhttp:1.28.0", + sha256 = "6e7a080c064b2f9b3639b576d0bdfb4c5180616ce88df7d4211cbf952691e28c", + sha256_src = "c37f1317dbc93092e38d5ad6627f80fa595be3daed4484d9c8c71de0d6dce800", ) maybe_repository( maven_jar, name = "io_grpc_protobuf", locals = locals, - artifact = "io.grpc:grpc-protobuf:1.16.1", - sha256 = "c46cd81341f002995c178687226c6174094635f13a95b7e8389c7c1d84290d82", - sha256_src = "fd723b55711d40d7e61edd92c205e708531f5fbcbf464e616ff580aef54ac5a5", + artifact = "io.grpc:grpc-protobuf:1.28.0", + sha256 = "a48ef62c55e2bd92325ce0924b60363cfb00d274ba1ab281dc8d9c568fd48fd8", + sha256_src = "52148a963d712418ed8c8378635863998c33db90e89fcbdfb75009068916f0f7", ) maybe_repository( maven_jar, name = "io_grpc_protobuf_lite", locals = locals, - artifact = "io.grpc:grpc-protobuf-lite:1.16.1", - sha256 = "4059becc5c8a25f5907c998632cd7187df6523e1317390d43a3ef7909e99956a", - sha256_src = "412dbd13c2b61c6f2f2f72f8f1426dcf4c4d4a3080a8c1b8ec282ed2e709fafd", + artifact = "io.grpc:grpc-protobuf-lite:1.28.0", + sha256 = "5dbcf11cec631fa1b99b3aa338b8f306dbf660f127126f29efc4218166c44857", + sha256_src = "844585c241a3a021a5f2e9f75881d8da118f842672f03a654d5abb7d1c24cf9f", ) maybe_repository( maven_jar, name = "io_grpc_stub", locals = locals, - artifact = "io.grpc:grpc-stub:1.16.1", - sha256 = "4a6a33253dc68805f005a945686c567e9d73a618b237caf308c48d7a54d771fc", - sha256_src = "d8a87b55ac7284e1fdafcd64df3b258e4ed78d764996620c9a70b8d1445c06b3", + artifact = "io.grpc:grpc-stub:1.28.0", + sha256 = "f10b2f46cb5142f18135dcfb163e4db7b12aab47504746a00c4a2800a791dc01", + sha256_src = "eb0ca640f9147ea9c3d94626c55d8a73696401d6e9f37cda7182a2300e8be214", ) # OKHttp used by gRPC. @@ -100,18 +108,18 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local maven_jar, name = "com_squareup_okhttp", locals = locals, - artifact = "com.squareup.okhttp:okhttp:2.5.0", - sha256 = "1cc716e29539adcda677949508162796daffedb4794cbf947a6f65e696f0381c", - sha256_src = "1bf6850f38f34036f096a9deb5cb714f3f41b529c80de9c79b33f11adcedcc1a", + artifact = "com.squareup.okhttp:okhttp:2.7.4", + sha256 = "c88be9af1509d5aeec9394a818c0fa08e26fad9d64ba134e6f977e0bb20cb114", + sha256_src = "57c3b223fb40568eabb97e2be989625746af99120a8112bbcfa49d7d9ab3c746", ) maybe_repository( maven_jar, name = "com_squareup_okio", locals = locals, - artifact = "com.squareup.okio:okio:1.6.0", - sha256 = "114bdc1f47338a68bcbc95abf2f5cdc72beeec91812f2fcd7b521c1937876266", - sha256_src = "cf31dcd63db43c48c62ef41560006a25bbe3e207b170ecbd7bfe0b675880a0ac", + artifact = "com.squareup.okio:okio:1.13.0", + sha256 = "734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850", + sha256_src = "b0305445ad4001639413951837a2248c5e9ca28386fbae2e31e1556f7710c5a8", ) # Opencensus used by gRPC. @@ -119,18 +127,28 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local maven_jar, name = "io_opencensus_api", locals = locals, - artifact = "io.opencensus:opencensus-api:0.12.3", - sha256 = "8c1de62cbdaf74b01b969d1ed46c110bca1a5dd147c50a8ab8c5112f42ced802", - sha256_src = "67e8b2120737c7dcfc61eef33f75319b1c4e5a2806d3c1a74cab810650ac7a19", + artifact = "io.opencensus:opencensus-api:0.24.0", + sha256 = "f561b1cc2673844288e596ddf5bb6596868a8472fd2cb8993953fc5c034b2352", + sha256_src = "01693c455b3748a494813ae612e1766c9e804d56561b759d8399270865427bf6", ) maybe_repository( maven_jar, name = "io_opencensus_contrib_grpc_metrics", locals = locals, - artifact = "io.opencensus:opencensus-contrib-grpc-metrics:0.12.3", - sha256 = "632c1e1463db471b580d35bc4be868facbfbf0a19aa6db4057215d4a68471746", - sha256_src = "d54f6611f75432ca0ab13636a613392ae8b7136ba67eb1588fccdb8481f4d665", + artifact = "io.opencensus:opencensus-contrib-grpc-metrics:0.24.0", + sha256 = "875582e093f11950ad3f4a50b5fee33a008023f7d1e47820a1bef05d23b9ed42", + sha256_src = "48c84a321af149c35a95b0d433a49c78e21674e10568fbc529675de0ee46fa96", + ) + + # Perfmark used by gRPC. + maybe_repository( + maven_jar, + name = "io_perfmark_api", + locals = locals, + artifact = "io.perfmark:perfmark-api:0.19.0", + sha256 = "b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a", + sha256_src = "05cfbdd34e6fc1f10181c755cec67cf1ee517dfee615e25d1007a8aabd569dba", ) maybe_repository( @@ -195,6 +213,7 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local DEFAULT_MAPPINGS = { # gRPC + "io_grpc_api": "@io_grpc_api//:jar", "io_grpc_context": "@io_grpc_context//:jar", "io_grpc_core": "@io_grpc_core//:jar", "io_grpc_okhttp": "@io_grpc_okhttp//:jar", @@ -205,6 +224,7 @@ DEFAULT_MAPPINGS = { "com_squareup_okio": "@com_squareup_okio//:jar", "io_opencensus_api": "@io_opencensus_api//:jar", "io_opencensus_contrib_grpc_metrics": "@io_opencensus_contrib_grpc_metrics//:jar", + "io_perfmark_api": "@io_perfmark_api//:jar", "javax_annotation_api": "@javax_annotation_api//:jar", # LWJGL "org_lwjgl_core": "@org_lwjgl_core//:jar", From 8dfe899a61795cd06b08fc30bf578f65120a4234 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 17:12:43 -0700 Subject: [PATCH 0205/1218] Upgrade lwjgl. --- .../com/google/gapid/glcanvas/GlCanvas.java | 2 +- .../com/google/gapid/glcanvas/GlCanvas.java | 2 +- tools/build/workspace_gapic.bzl | 24 +++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/gapic/src/platform/linux/com/google/gapid/glcanvas/GlCanvas.java b/gapic/src/platform/linux/com/google/gapid/glcanvas/GlCanvas.java index b615c00030..a28a641502 100644 --- a/gapic/src/platform/linux/com/google/gapid/glcanvas/GlCanvas.java +++ b/gapic/src/platform/linux/com/google/gapid/glcanvas/GlCanvas.java @@ -48,7 +48,7 @@ public abstract class GlCanvas extends Canvas { static { boolean loaded = false; try { - Library.loadSystem("linux_glcanvas"); + Library.loadSystem("", "linux_glcanvas"); loaded = true; } catch (UnsatisfiedLinkError e) { LOG.log(SEVERE, "Failed to load GlCanvas JNI library", e); diff --git a/gapic/src/platform/windows/com/google/gapid/glcanvas/GlCanvas.java b/gapic/src/platform/windows/com/google/gapid/glcanvas/GlCanvas.java index 13fe04b84c..8230d9f80b 100644 --- a/gapic/src/platform/windows/com/google/gapid/glcanvas/GlCanvas.java +++ b/gapic/src/platform/windows/com/google/gapid/glcanvas/GlCanvas.java @@ -204,7 +204,7 @@ public boolean createPixelFormat() { set(buf, WGLARBMultisample.WGL_SAMPLES_ARB, 4); set(buf, 0, 0); long result = MemoryStack.nstackMalloc(4, 4 * 2); - if (JNI.callPPPPPI(chooseFormat, dc, bufAddr, 0L, 1, result + 4, result) != 1 || + if (JNI.callPPPPPI(dc, bufAddr, 0L, 1, result + 4, result, chooseFormat) != 1 || MemoryUtil.memGetInt(result) == 0) { return false; } diff --git a/tools/build/workspace_gapic.bzl b/tools/build/workspace_gapic.bzl index 04d957268b..6a24419cff 100644 --- a/tools/build/workspace_gapic.bzl +++ b/tools/build/workspace_gapic.bzl @@ -166,24 +166,24 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local maven_jar, name = "org_lwjgl_core", locals = locals, - artifact = "org.lwjgl:lwjgl:3.2.0", - sha256 = "97af9a688081bbdf0cf208b93f02b58fe2db0504ee7333e54780c4b6f70694f8", - sha256_src = "1919899fbea2dcf392d0bba6161da058f7f8c4da0877a7e6258ee57305c398e7", - sha256_linux = "08ca6d394ef7ac97002bc939642dc285c7f61c94a69070fa9a916921fee637ab", - sha256_windows = "ee93b31388356835fe8fbc6155dc83c73ceec7422b777aa2e7e3187e9689b2cc", - sha256_macos = "6db0910dea5323a3b61c8b16a28e5f84ee780f2affc2cd06da34b9fe09295051", + artifact = "org.lwjgl:lwjgl:3.2.3", + sha256 = "f9928c3b4b540643a1bbd59286d3c7175e470849261a0c29a81389f52265ad8b", + sha256_src = "97b9c693337f76a596b86b07db26a0a8022e3a4e0a0360edb9bb87bc9b172cda", + sha256_linux = "002810129fc6ac4cdfcdf190e18a643a5021b6300f489c1026bbc5d00140ca2e", + sha256_windows = "bdf519b9aa90f799954113a15dfa84b273ee4781876b3ecdebf192ce4f88a26c", + sha256_macos = "5c520c465a84034b8bc23e1d7ecd621bb99c437cd254ea46b53197448d1b8128", ) maybe_repository( maven_jar, name = "org_lwjgl_opengl", locals = locals, - artifact = "org.lwjgl:lwjgl-opengl:3.2.0", - sha256 = "4cc168087708653bdbc1d700daf3fb4b8c1fc89d23d4cf6ee834c3b1208c85a6", - sha256_src = "3693081b41f4259be2df7e37c36a5a2b9ce3f8a451b7acc9d609749a1c6e7974", - sha256_linux = "1f04e87ab78cb9616447f2abbf3d8b0c3cf25c73aea7f40b2580caba2a1269f6", - sha256_windows = "4e515b2c596a7a0794f0fe855637aafe1427a1f4e331d6b5be83c03add04e0eb", - sha256_macos = "a9cc1b2de4be574261c9923027076d5ef5c9565dc2c98c074857d4455ed14848", + artifact = "org.lwjgl:lwjgl-opengl:3.2.3", + sha256 = "10bcc37506e01d1477d65f1fcf0aa672c95eb785265b28b7f321c8381093eda2", + sha256_src = "6082a81f350dfc0e390a9ceb4347fa2a28cd07dfd54dc757fb05fa6f3350314e", + sha256_linux = "466e8bae1818c4c584771ee093c8a735e26f56fb25a81dde5675160aaa2fa045", + sha256_windows = "c08e3de31632163ac5f746fa945f1924142e08520bd9c81b7dd1b5dbd1b0b8bb", + sha256_macos = "e4b4d0cd9138d52271c1d5c18e43c9ac5d36d1a727c47e5ee4031cb45ce730ca", ) # Other dependencies. From 7055e37af7f7e89ca17e9667c8a73b96cd4b167b Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 20 Mar 2020 17:25:29 -0700 Subject: [PATCH 0206/1218] Upgrade guava. --- .classpath | 1 + tools/build/third_party/gapic_third_party.BUILD | 7 +++++-- tools/build/workspace_gapic.bzl | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.classpath b/.classpath index d89ee43093..85c4039828 100644 --- a/.classpath +++ b/.classpath @@ -27,6 +27,7 @@ + diff --git a/tools/build/third_party/gapic_third_party.BUILD b/tools/build/third_party/gapic_third_party.BUILD index 86e678cc18..dfc41813ee 100644 --- a/tools/build/third_party/gapic_third_party.BUILD +++ b/tools/build/third_party/gapic_third_party.BUILD @@ -63,9 +63,12 @@ java_library( }), ) -alias( +java_library( name = "guava", - actual = "{{com_google_guava}}", + exports = [ + "{{com_google_guava-failureaccess}}", + "{{com_google_guava}}", + ], ) alias( diff --git a/tools/build/workspace_gapic.bzl b/tools/build/workspace_gapic.bzl index 6a24419cff..8227271a0c 100644 --- a/tools/build/workspace_gapic.bzl +++ b/tools/build/workspace_gapic.bzl @@ -192,9 +192,18 @@ def gapic_dependencies(no_maven = False, no_swt = False, no_jface = False, local maven_jar, name = "com_google_guava", locals = locals, - artifact = "com.google.guava:guava:27.0-jre", - sha256 = "63b09db6861011e7fb2481be7790c7fd4b03f0bb884b3de2ecba8823ad19bf3f", - sha256_src = "170dbf09858d1cffdaaa53d4d6ab15e6253c845318b0cc3bf21f8dffa9d433ab", + artifact = "com.google.guava:guava:28.2-jre", + sha256 = "fc3aa363ad87223d1fbea584eee015a862150f6d34c71f24dc74088a635f08ef", + sha256_src = "e4a71a9d1f5f5f886a1802c257d3fcb78c6c234e2e183257f3ed1474802d077b", + ) + + maybe_repository( + maven_jar, + name = "com_google_guava-failureaccess", + locals = locals, + artifact = "com.google.guava:failureaccess:1.0.1", + sha256 = "a171ee4c734dd2da837e4b16be9df4661afab72a41adaf31eb84dfdaf936ca26", + sha256_src = "092346eebbb1657b51aa7485a246bf602bb464cc0b0e2e1c7e7201fadce1e98f", ) if not no_swt: @@ -237,6 +246,7 @@ DEFAULT_MAPPINGS = { "org_lwjgl_opengl_natives_macos": "@org_lwjgl_opengl//:jar-natives-macos", # Others "com_google_guava": "@com_google_guava//:jar", + "com_google_guava-failureaccess": "@com_google_guava-failureaccess//:jar", "jface": "@jface", "swt": "@swt", } From 9f81060d636b5ef53bd7e5f98c1f587e17677248 Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Thu, 26 Mar 2020 15:18:05 -0700 Subject: [PATCH 0207/1218] Fix struct typed memory observation's appending issue. (#180) - Bug: http://b/152407425. --- .../main/com/google/gapid/models/Memory.java | 39 +++++++------------ 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/gapic/src/main/com/google/gapid/models/Memory.java b/gapic/src/main/com/google/gapid/models/Memory.java index c85cd8a423..d47928e739 100644 --- a/gapic/src/main/com/google/gapid/models/Memory.java +++ b/gapic/src/main/com/google/gapid/models/Memory.java @@ -25,6 +25,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.primitives.UnsignedLongs; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -43,6 +44,8 @@ import com.google.gapid.util.Ranges; import com.google.gapid.util.TypeInfos; +import java.util.Set; +import java.util.stream.Collectors; import org.eclipse.swt.widgets.Shell; import java.lang.ref.SoftReference; @@ -641,38 +644,21 @@ private List loadChildren() { /** * Utility method. Simplify trees, especially for vulkan structs. * 1. Remove redundant layers for all the trees. - * 2. Identify some trees to be the main trees. (Assume the main trees to be those with type - * TypeInfo.StructType, they usually contain key info like VkPresentInfoKHR, VkSubmitInfo...) - * 3. Combine trees together by appending some smaller trees to the main trees, if they are + * 2. Combine trees together by appending some smaller trees to the main trees, if they are * related through a pointer field. */ public static List simplifyTrees(List trees) { - List simplified = new ArrayList(); - + // Remove redundant layers. Map nodes = new HashMap(); for (StructNode tree : trees) { nodes.put(tree.getRootAddress(), removeExtraLayers(tree)); } - - // Find the main trees. - for (Iterator> it = nodes.entrySet().iterator(); it.hasNext(); ) { - Map.Entry entry = it.next(); - if (containsStructType(entry.getValue())) { - simplified.add(entry.getValue()); - it.remove(); - } - } - - // Append other trees to the main trees if possible. - for (StructNode mainTree : simplified) { - appendPointedNodes(mainTree, nodes); - } - - // Add the remaining unappended nodes to the returning result. + // Append pointed nodes to corresponding pointer field if possible. + Set appended = Sets.newHashSet(); for (StructNode node : nodes.values()) { - simplified.add(node); + appendPointedNodes(node, nodes, appended); } - return simplified; + return nodes.values().stream().filter(n -> !appended.contains(n)).collect(Collectors.toList()); } /** @@ -717,7 +703,8 @@ private static boolean containsStructType(StructNode root) { * Find all the nodes with type TypeInfo.PointerType in this tree, append the pointed tree to * these nodes if possible. */ - private static void appendPointedNodes(StructNode root, Map nodes) { + private static void appendPointedNodes(StructNode root, Map nodes, + Set appended) { if (root == null) { return; } @@ -725,11 +712,11 @@ private static void appendPointedNodes(StructNode root, Map no long pointedAddress = root.getValue().getPointer().getAddress(); if (nodes.containsKey(pointedAddress)) { root.getChildren().add(nodes.get(pointedAddress)); - nodes.remove(pointedAddress); + appended.add(nodes.get(pointedAddress)); } } for (StructNode child : root.getChildren()) { - appendPointedNodes(child, nodes); + appendPointedNodes(child, nodes, appended); } } } From 621013ce21b2b3fa13e8936172c7a2dd67c0bd81 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Fri, 27 Mar 2020 16:47:21 +0000 Subject: [PATCH 0208/1218] Remove swiftshader gfxtrace from build artifacts (#183) This was a temporary measure to fix b/151297033 See actual fix in #169 b/151297033 --- kokoro/linux/build.sh | 4 ++-- kokoro/linux/common.cfg | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 258b36b081..539abb91e9 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -168,9 +168,9 @@ test "${APP_EXIT_STATUS}" -eq 130 # TODO(https://github.com/google/gapid/issues/3163): The coherent memory # tracker must be disabled with SwiftShader for now. -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherentmemorytracker -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan -start-at-frame 5 -capture-frames 10 -observe-frames 1 -out vulkan_sample.gfxtrace bazel-bin/cmd/vulkan_sample/vulkan_sample -xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 $KOKORO_ARTIFACTS_DIR/vulkan_sample.gfxtrace +xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 vulkan_sample.gfxtrace ## ## Collect swarming test result diff --git a/kokoro/linux/common.cfg b/kokoro/linux/common.cfg index 028eb61e89..916993267f 100644 --- a/kokoro/linux/common.cfg +++ b/kokoro/linux/common.cfg @@ -33,8 +33,6 @@ action { regex: "out/dist/agi*.deb" regex: "out/dist/agi*.zip" regex: "out/dist/*gapir*.sym" - # b/151297033: save trace of sample on swiftshader, for debug purposes - regex: "*.gfxtrace" strip_prefix: "out/dist" } } From b73b1866721f23011ccdc063b3683f1eb6398f5d Mon Sep 17 00:00:00 2001 From: "Melih Y. Yalcin" Date: Tue, 31 Mar 2020 13:18:41 +0100 Subject: [PATCH 0209/1218] Fix the wrong memory observation (#184) --- gapis/api/vulkan/command_buffer_rebuilder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gapis/api/vulkan/command_buffer_rebuilder.go b/gapis/api/vulkan/command_buffer_rebuilder.go index 51e03dbc06..2944865430 100644 --- a/gapis/api/vulkan/command_buffer_rebuilder.go +++ b/gapis/api/vulkan/command_buffer_rebuilder.go @@ -177,7 +177,7 @@ func rebuildVkCmdBeginRenderPass( for i := range rects { rects[i] = dgbi.RenderAreas().Get(uint32(i)) } - rectMem := s.AllocDataOrPanic(ctx, clearValues) + rectMem := s.AllocDataOrPanic(ctx, rects) mem = append(mem, rectMem) pNextData := s.AllocDataOrPanic(ctx, From 82c53d540591cd8da47992336f21e847b1d93e33 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 31 Mar 2020 18:08:39 +0100 Subject: [PATCH 0210/1218] Rename to AGI in Android notifications (#190) b/152838132 --- .../main/java/com/google/android/gapid/GapidService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gapidapk/android/app/src/main/java/com/google/android/gapid/GapidService.java b/gapidapk/android/app/src/main/java/com/google/android/gapid/GapidService.java index d6a2412ca0..25e21b0ab6 100644 --- a/gapidapk/android/app/src/main/java/com/google/android/gapid/GapidService.java +++ b/gapidapk/android/app/src/main/java/com/google/android/gapid/GapidService.java @@ -29,7 +29,7 @@ * Instead, services should run in the foreground and show a notification that they are running. */ public abstract class GapidService extends IntentService { - private static final String CHANNEL_ID = "GAPID_notification_channel"; + private static final String CHANNEL_ID = "AGI_notification_channel"; private final Type type; public GapidService(String name, Type type) { @@ -43,8 +43,8 @@ public void onCreate() { // Show a notification, so Android doesn't take us down. Notification.Builder notification = new Notification.Builder(this) .setOngoing(true) - .setContentTitle("Graphics API Debugger") - .setContentText("GAPID is examining your device...") + .setContentTitle("Android GPU Inspector") + .setContentText("AGI is examining your device...") // the package name for resources "R" is derived from the "custom_package" field in // gapidapk/android/app/src/main/BUILD.bazel .setSmallIcon(com.google.android.gapid.R.drawable.logo) @@ -54,7 +54,7 @@ public void onCreate() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( CHANNEL_ID, "Service Noticiations", NotificationManager.IMPORTANCE_LOW); - channel.setDescription("Notifications from the GAPID background services"); + channel.setDescription("Notifications from the AGI background services"); getSystemService(NotificationManager.class).createNotificationChannel(channel); notification.setChannelId(CHANNEL_ID); } else { From c03ac01b45f2d10eb17d45cf4e2df4ec4366beb3 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 1 Apr 2020 10:49:18 -0700 Subject: [PATCH 0211/1218] mali: Add ID to synthetic slices we produce in the replay profiler This was previously fixed for Adreno, but Mali was missed. Bug: b/152987205 --- gapis/trace/android/mali/profiling_data.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gapis/trace/android/mali/profiling_data.go b/gapis/trace/android/mali/profiling_data.go index ff10347a11..a2eb8abb21 100644 --- a/gapis/trace/android/mali/profiling_data.go +++ b/gapis/trace/android/mali/profiling_data.go @@ -30,7 +30,7 @@ import ( var ( slicesQuery = "" + - "SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.name, depth, arg_set_id, track_id, t.name " + + "SELECT s.context_id, s.render_target, s.frame_id, s.submission_id, s.hw_queue_id, s.command_buffer, s.render_pass, s.ts, s.dur, s.id, s.name, depth, arg_set_id, track_id, t.name " + "FROM gpu_track t LEFT JOIN gpu_slice s " + "ON s.track_id = t.id WHERE t.scope = 'gpu_render_stage' ORDER BY s.ts" argsQueryFmt = "" + @@ -131,11 +131,12 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur hwQueueIds := slicesColumns[4].GetLongValues() timestamps := slicesColumns[7].GetLongValues() durations := slicesColumns[8].GetLongValues() - names := slicesColumns[9].GetStringValues() - depths := slicesColumns[10].GetLongValues() - argSetIds := slicesColumns[11].GetLongValues() - trackIds := slicesColumns[12].GetLongValues() - trackNames := slicesColumns[13].GetStringValues() + ids := slicesColumns[9].GetLongValues() + names := slicesColumns[10].GetStringValues() + depths := slicesColumns[11].GetLongValues() + argSetIds := slicesColumns[12].GetLongValues() + trackIds := slicesColumns[13].GetLongValues() + trackNames := slicesColumns[14].GetStringValues() for i, v := range submissionIds { subOrder, ok := submissionOrdering[v] @@ -216,6 +217,7 @@ func processGpuSlices(ctx context.Context, processor *perfetto.Processor, captur slices[i] = &service.ProfilingData_GpuSlices_Slice{ Ts: uint64(timestamps[i]), Dur: uint64(durations[i]), + Id: uint64(ids[i]), Label: names[i], Depth: int32(depths[i]), Extras: extras, From 6f98dab9675c5b64b9987557eb9e2f002452b91b Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Thu, 2 Apr 2020 17:15:59 -0700 Subject: [PATCH 0212/1218] Show command buffer vulkan handle for subcommand node. (#188) - Bug: http://b/143734139. --- gapis/api/cmd_id_group.go | 34 ++++++++++++++++++++-------------- gapis/api/subcmd_idx_trie.go | 4 ++++ gapis/api/sync/data.go | 14 ++++++++++---- gapis/api/vulkan/vulkan.go | 4 ++++ gapis/resolve/command_tree.go | 8 ++++---- 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/gapis/api/cmd_id_group.go b/gapis/api/cmd_id_group.go index 4e1083a720..8be6819dde 100644 --- a/gapis/api/cmd_id_group.go +++ b/gapis/api/cmd_id_group.go @@ -55,9 +55,15 @@ type CmdGroupOrRoot interface { } // NewRoot sets up a new root object. -func NewRoot(idx []uint64) *SubCmdRoot { +func NewRoot(idx []uint64, nameLookUp *SubCmdIdxTrie) *SubCmdRoot { + var name = "Subgroup" + if nameVal := nameLookUp.Value(idx); nameVal != nil { + if n, ok := nameVal.(string); ok { + name = n + } + } return &SubCmdRoot{Id: append(slice.Clone(idx).([]uint64)), - SubGroup: CmdIDGroup{Name: "Subgroup"}} + SubGroup: CmdIDGroup{Name: name}} } // Spans is a list of Span elements. Functions in this package expect the @@ -356,7 +362,7 @@ func (g *CmdIDGroup) AddGroup(start, end CmdID, name string) (*CmdIDGroup, error // AddRoot adds a new Subcommand Root for the given index. // It returns the span for this SubcommandGroup -func (g *CmdIDGroup) AddRoot(rootidx []uint64) *SubCmdRoot { +func (g *CmdIDGroup) AddRoot(rootidx []uint64, nameLookUp *SubCmdIdxTrie) *SubCmdRoot { r := CmdIDRange{Start: CmdID(rootidx[len(rootidx)-1]), End: CmdID(rootidx[len(rootidx)-1] + 1)} s, c := interval.Intersect(&g.Spans, r.Span()) if c == 0 { @@ -364,7 +370,7 @@ func (g *CmdIDGroup) AddRoot(rootidx []uint64) *SubCmdRoot { i := sort.Search(len(g.Spans), func(i int) bool { return g.Spans[i].Bounds().Start > CmdID(rootidx[0]) }) - slice.InsertBefore(&g.Spans, i, NewRoot(rootidx)) + slice.InsertBefore(&g.Spans, i, NewRoot(rootidx, nameLookUp)) return g.Spans[i].(*SubCmdRoot) } if c != 1 { @@ -374,14 +380,14 @@ func (g *CmdIDGroup) AddRoot(rootidx []uint64) *SubCmdRoot { // At least one overlap switch first := g.Spans[s].(type) { case *CmdIDGroup: - return first.AddRoot(rootidx) + return first.AddRoot(rootidx, nameLookUp) case *CmdIDRange: firstHalf := &CmdIDRange{first.Start, CmdID(rootidx[len(rootidx)-1])} if firstHalf.End > firstHalf.Start { slice.InsertBefore(&g.Spans, s, firstHalf) s++ } - slice.Replace(&g.Spans, s, 1, NewRoot(rootidx)) + slice.Replace(&g.Spans, s, 1, NewRoot(rootidx, nameLookUp)) secondHalf := &CmdIDRange{CmdID(rootidx[len(rootidx)-1] + 1), first.End} slice.InsertBefore(&g.Spans, s+1, secondHalf) return g.Spans[s].(*SubCmdRoot) @@ -393,7 +399,7 @@ func (g *CmdIDGroup) AddRoot(rootidx []uint64) *SubCmdRoot { // newChildSubCmdRoots adds child SubCmdRoots to the SubCmdRoot's subgroup. If // subcomamnds are skipped, create SubCmdRoots for them. -func (c *SubCmdRoot) newChildSubCmdRoots(r []uint64) *SubCmdRoot { +func (c *SubCmdRoot) newChildSubCmdRoots(r []uint64, nameLookUp *SubCmdIdxTrie) *SubCmdRoot { if len(r) == 0 { return c } @@ -404,14 +410,14 @@ func (c *SubCmdRoot) newChildSubCmdRoots(r []uint64) *SubCmdRoot { } if c.SubGroup.Range.End > oldEnd { for i := uint64(oldEnd); i < uint64(c.SubGroup.Range.End); i++ { - c.SubGroup.AddRoot(append(c.Id, i)) + c.SubGroup.AddRoot(append(c.Id, i), nameLookUp) } } sg := c.SubGroup.FindSubCommandRoot(CmdID(nextRootRelativeIndex)) if sg == nil { - sg = c.SubGroup.AddRoot(append(c.Id, nextRootRelativeIndex)) + sg = c.SubGroup.AddRoot(append(c.Id, nextRootRelativeIndex), nameLookUp) } - return sg.newChildSubCmdRoots(r[1:]) + return sg.newChildSubCmdRoots(r[1:], nameLookUp) } // Insert adds a new subcommand into the SubCmdRoot. The subcommand is specified @@ -419,8 +425,8 @@ func (c *SubCmdRoot) newChildSubCmdRoots(r []uint64) *SubCmdRoot { // not an immediate child of the target SubCmdRoot (i.e. len(r) > 1) , new // child SubCmdRoots will be created under the target SubCmdRoot, until the // immediate parent of the subcommand is created. -func (c *SubCmdRoot) Insert(r []uint64) { - childRoot := c.newChildSubCmdRoots(r[0 : len(r)-1]) +func (c *SubCmdRoot) Insert(r []uint64, nameLookUp *SubCmdIdxTrie) { + childRoot := c.newChildSubCmdRoots(r[0:len(r)-1], nameLookUp) // Add subcommands one-by-one to the SubCmdRoot and its subgroups/child // SubCmdRoots id := r[len(r)-1] @@ -437,8 +443,8 @@ func (c *SubCmdRoot) Insert(r []uint64) { // immediate children of the target SubCmdRoot (r is not empty), child // SubCmdRoots will be created under the target SubCmdRoot recursively until // the immediate parent SubCmdRoot is created. -func (c *SubCmdRoot) AddSubCmdMarkerGroups(r []uint64, groups []*CmdIDGroup) error { - childRoot := c.newChildSubCmdRoots(r) +func (c *SubCmdRoot) AddSubCmdMarkerGroups(r []uint64, groups []*CmdIDGroup, nameLookUp *SubCmdIdxTrie) error { + childRoot := c.newChildSubCmdRoots(r, nameLookUp) for _, g := range groups { if g.Range.Start < childRoot.SubGroup.Range.Start { childRoot.SubGroup.Range.Start = g.Range.Start diff --git a/gapis/api/subcmd_idx_trie.go b/gapis/api/subcmd_idx_trie.go index 701a83a696..1107bf406c 100644 --- a/gapis/api/subcmd_idx_trie.go +++ b/gapis/api/subcmd_idx_trie.go @@ -133,3 +133,7 @@ func (t *SubCmdIdxTrie) PostOrderSortedKeys() []SubCmdIdx { } return keys } + +func (t *SubCmdIdxTrie) GetChildren(index uint64) *SubCmdIdxTrie { + return t.children[index] +} diff --git a/gapis/api/sync/data.go b/gapis/api/sync/data.go index ffb867b11e..825414e3ce 100644 --- a/gapis/api/sync/data.go +++ b/gapis/api/sync/data.go @@ -87,10 +87,15 @@ type Data struct { SubCommandMarkerGroups *subCommandMarkerGroupTrie // SyncDependencies contains the commands that must complete // (according to their fences or semaphores) before they can be executed. - SyncDependencies map[SyncNodeIdx][]SyncNodeIdx - SyncNodes []SyncNode - CmdSyncNodes map[api.CmdID]SyncNodeIdx - SubcommandLookup *api.SubCmdIdxTrie + SyncDependencies map[SyncNodeIdx][]SyncNodeIdx + SyncNodes []SyncNode + CmdSyncNodes map[api.CmdID]SyncNodeIdx + // SubcommandLookup maps a SubCmdIdx to its corresponding SubcommandReference. + SubcommandLookup *api.SubCmdIdxTrie + // SubcommandNames maps a SubCmdIdx to its corresponding string typed name. + // The names are especially useful for the virtual SubCmdRoot nodes, which are + // created to organize psubmits, command buffers, etc. + SubcommandNames *api.SubCmdIdxTrie SubmissionIndices map[api.CmdSubmissionKey][]api.SubCmdIdx } @@ -125,6 +130,7 @@ func NewData() *Data { SyncNodes: []SyncNode{}, CmdSyncNodes: map[api.CmdID]SyncNodeIdx{}, SubcommandLookup: new(api.SubCmdIdxTrie), + SubcommandNames: new(api.SubCmdIdxTrie), SubmissionIndices: map[api.CmdSubmissionKey][]api.SubCmdIdx{}, } } diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index e139c65bf8..e84fd39d8d 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -203,6 +203,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap switch args := GetCommandArgs(ctx, cb.CommandReferences().Get(uint32(i)), st).(type) { case VkCmdExecuteCommandsArgsʳ: + d.SubcommandNames.SetValue(nv, "") // Clear the group name so that the original commnd is shown. for j := uint64(0); j < uint64(args.CommandBuffers().Len()); j++ { cbo := st.CommandBuffers().Get(args.CommandBuffers().Get(uint32(j))) subIdx := append(api.SubCmdIdx{}, idx...) @@ -212,6 +213,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap subgroups = append(subgroups, newSubgroups...) if cbo.CommandReferences().Len() > 0 { subgroups = append(subgroups, append(idx, uint64(i), uint64(j), uint64(cbo.CommandReferences().Len()-1))) + d.SubcommandNames.SetValue(append(idx, uint64(i), j), fmt.Sprintf("Command Buffer: %v", cbo.VulkanHandle())) } } case VkCmdBeginRenderPassArgsʳ: @@ -317,7 +319,9 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap for submitIdx, submit := range submits { bufferCount := submit.CommandBufferCount() buffers := submit.PCommandBuffers().Slice(uint64(0), uint64(bufferCount), l).MustRead(ctx, cmd, s, nil) + d.SubcommandNames.SetValue(api.SubCmdIdx{uint64(id), uint64(submitIdx)}, fmt.Sprintf("pSubmits[%v]: ", submitIdx)) for j, buff := range buffers { + d.SubcommandNames.SetValue(api.SubCmdIdx{uint64(id), uint64(submitIdx), uint64(j)}, fmt.Sprintf("Command Buffer: %v", buff)) cmdBuff := st.CommandBuffers().Get(buff) // If a submitted command-buffer is empty, we shouldn't show it if cmdBuff.CommandReferences().Len() > 0 { diff --git a/gapis/resolve/command_tree.go b/gapis/resolve/command_tree.go index 201e0a7886..a4f1b8b38e 100644 --- a/gapis/resolve/command_tree.go +++ b/gapis/resolve/command_tree.go @@ -150,7 +150,7 @@ func CommandTreeNode(ctx context.Context, c *path.CommandTreeNode, r *path.Resol count := uint64(1) g := "" if len(item.Id) > 1 { - g = fmt.Sprintf("%v", item.Id) + g = fmt.Sprintf("%v", item.SubGroup.Name) count = uint64(item.SubGroup.Count()) } return &service.CommandTreeNode{ @@ -310,7 +310,7 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error } if v, ok := snc.SubcommandGroups[id]; ok { - r := out.root.AddRoot([]uint64{uint64(id)}) + r := out.root.AddRoot([]uint64{uint64(id)}, snc.SubcommandNames) // subcommands are added before nesting SubCmdRoots. cv := append([]api.SubCmdIdx{}, v...) sort.SliceStable(cv, func(i, j int) bool { return len(cv[i]) < len(cv[j]) }) @@ -321,9 +321,9 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error parentIdx := append([]uint64{uint64(id)}, x[0:len(x)-1]...) if snc.SubCommandMarkerGroups.Value(parentIdx) != nil { markers := snc.SubCommandMarkerGroups.Value(parentIdx).([]*api.CmdIDGroup) - r.AddSubCmdMarkerGroups(x[0:len(x)-1], markers) + r.AddSubCmdMarkerGroups(x[0:len(x)-1], markers, snc.SubcommandNames) } - r.Insert(append([]uint64{}, x...)) + r.Insert(append([]uint64{}, x...), snc.SubcommandNames) } return nil } From 77648d1557836fcf549c4238e65fb1e35c1d296f Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Mon, 6 Apr 2020 10:30:39 +0100 Subject: [PATCH 0213/1218] Open perfetto traces as soon as they are terminated (#195) This avoids the user to have to press the "Open Trace" button. We still want to keep an "Open Trace" button for Graphics traces, for future plans of multiple graphics traces within the same app run. Bug: b/143711475 --- gapic/src/main/com/google/gapid/views/TracerDialog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index 08b51ab979..5392a27a32 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -1235,7 +1235,11 @@ private void updateButton() { button.setText("Stop"); break; case Done: - button.setText("Open Trace"); + if (request.options.getType() == Service.TraceType.Perfetto) { + okPressed(); + } else { + button.setText("Open Trace"); + } break; default: button.setText("Cancel"); From d6f5cc17bf1ba7832f08116c4eb1db2810e8e104 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 6 Apr 2020 10:36:56 -0700 Subject: [PATCH 0214/1218] Make validation more robust on Adreno. (#194) The average of 'Textures / Fragment' should be 1 for the vulkan sample while each 50 ms sample might vary a bit larger than 0.1 from 1. Minor: Move some code around to avoid duplication. Bug: b/151801290 Test: bazel run gapit -- validate_gpu_profiling --os android --- gapis/trace/android/adreno/validate.go | 14 +++--- gapis/trace/android/mali/validate.go | 12 ++--- gapis/trace/android/validate/validate.go | 62 ++++++++++++------------ 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/gapis/trace/android/adreno/validate.go b/gapis/trace/android/adreno/validate.go index ab1d57d688..59a9ed9955 100644 --- a/gapis/trace/android/adreno/validate.go +++ b/gapis/trace/android/adreno/validate.go @@ -24,14 +24,14 @@ import ( var ( // All counters must be inside this array. counters = []validate.GpuCounter{ - {1, "Clocks / Second", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {3, "GPU % Utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {21, "% Shaders Busy", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {26, "Fragment ALU Instructions / Sec (Full)", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, + {1, "Clocks / Second", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {3, "GPU % Utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {21, "% Shaders Busy", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {26, "Fragment ALU Instructions / Sec (Full)", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, {30, "Textures / Vertex", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))}, - {31, "Textures / Fragment", validate.And(validate.IsNumber, validate.CheckApproximateTo(1.0, 0.1))}, - {37, "% Time Shading Fragments", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {38, "% Time Shading Vertices", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, + {31, "Textures / Fragment", validate.And(validate.IsNumber, validate.CheckAverageApproximateTo(1.0, 0.1))}, + {37, "% Time Shading Fragments", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {38, "% Time Shading Vertices", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, {39, "% Time Compute", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))}, } ) diff --git a/gapis/trace/android/mali/validate.go b/gapis/trace/android/mali/validate.go index 7e825f0bea..254b553f5f 100644 --- a/gapis/trace/android/mali/validate.go +++ b/gapis/trace/android/mali/validate.go @@ -24,13 +24,13 @@ import ( var ( // All counters must be inside this array. counters = []validate.GpuCounter{ - {6, "GPU active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {8, "Fragment jobs", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {196, "Fragment active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, + {6, "GPU active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {8, "Fragment jobs", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {196, "Fragment active cycles", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, {233, "Compressed texture line fetch requests", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))}, - {65536, "GPU utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {65538, "Fragment queue utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, - {65579, "Execution core utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero)}, + {65536, "GPU utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {65538, "Fragment queue utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, + {65579, "Execution core utilization", validate.And(validate.IsNumber, validate.CheckLargerThanZero())}, {65585, "Texture data fetches form compressed lines", validate.And(validate.IsNumber, validate.CheckEqualTo(0.0))}, } ) diff --git a/gapis/trace/android/validate/validate.go b/gapis/trace/android/validate/validate.go index 31d1029e6a..00166cc24f 100644 --- a/gapis/trace/android/validate/validate.go +++ b/gapis/trace/android/validate/validate.go @@ -79,36 +79,17 @@ func IsNumber(column *perfetto_service.QueryResult_ColumnValues, columnType perf return true } -// CheckLargerThanZero is a checker that checks that the values are all greater than zero. -func CheckLargerThanZero(column *perfetto_service.QueryResult_ColumnValues, columnType perfetto_service.QueryResult_ColumnDesc_Type) bool { - longValues := column.GetLongValues() - doubleValues := column.GetDoubleValues() - for i := 0; i < sampleCounter; i++ { - if columnType == perfetto_service.QueryResult_ColumnDesc_LONG { - if longValues[i] <= 0 { - return false - } - } else if columnType == perfetto_service.QueryResult_ColumnDesc_DOUBLE { - if doubleValues[i] <= 0.0 { - return false - } - } - } - return true -} - -// CheckEqualTo returns a checker that checks that all returned value equal the given value. -func CheckEqualTo(num float64) Checker { +func ForeachValue(check func(float64) bool) Checker { return func(column *perfetto_service.QueryResult_ColumnValues, columnType perfetto_service.QueryResult_ColumnDesc_Type) bool { longValues := column.GetLongValues() doubleValues := column.GetDoubleValues() for i := 0; i < sampleCounter; i++ { if columnType == perfetto_service.QueryResult_ColumnDesc_LONG { - if longValues[i] != int64(num) { + if !check(float64(longValues[i])) { return false } } else if columnType == perfetto_service.QueryResult_ColumnDesc_DOUBLE { - if doubleValues[i] != num { + if !check(doubleValues[i]) { return false } } @@ -117,26 +98,45 @@ func CheckEqualTo(num float64) Checker { } } -// CheckApproximateTo returns a checker that checks that values are within a margin of the given value. -func CheckApproximateTo(num, err float64) Checker { +// Average returns a checker that checks whether the average values meets the condition +func Average(check func(float64) bool) Checker { return func(column *perfetto_service.QueryResult_ColumnValues, columnType perfetto_service.QueryResult_ColumnDesc_Type) bool { longValues := column.GetLongValues() doubleValues := column.GetDoubleValues() + total := float64(0.0) for i := 0; i < sampleCounter; i++ { if columnType == perfetto_service.QueryResult_ColumnDesc_LONG { - if math.Abs(num-float64(longValues[i])) > err { - return false - } + total += float64(longValues[i]) } else if columnType == perfetto_service.QueryResult_ColumnDesc_DOUBLE { - if math.Abs(num-doubleValues[i]) > err { - return false - } + total += doubleValues[i] } } - return true + return check(total / sampleCounter) } } +// CheckLargerThanZero is a checker that checks that the values are all greater than zero. +func CheckLargerThanZero() Checker { + return ForeachValue(func(v float64) bool { + return v > 0.0 + }) +} + +// CheckEqualTo returns a checker that checks that all returned value equal the given value. +func CheckEqualTo(num float64) Checker { + return ForeachValue(func(v float64) bool { + return v == num + }) +} + +// CheckAverageApproximateTo checks whether the average of the values is within +// a margin of the given value. +func CheckAverageApproximateTo(num, margin float64) Checker { + return Average(func(v float64) bool { + return math.Abs(num-v) <= margin + }) +} + // ValidateGpuCounters validates the GPU counters. // GPU counters validation will fail in the below cases: // 1. Fail to query From 680d2754332dc0b6d501e40a3c0f26bad6d8ce33 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 7 Apr 2020 08:30:14 +0100 Subject: [PATCH 0215/1218] Fix device instance name on Android (#197) This also removes the "serial" field, as reading serial number via ro.serialno property is prevented by SELinux, see: https://cs.android.com/android/platform/superproject/+/master:system/sepolicy/public/domain.te;l=541;drc=19a5cc2bab59a4eea424ab38a6f1aa67b65860f1 Bug: b/153327038 --- core/os/device/deviceinfo/cc/android/query.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp index f7e00415ad..f92c084513 100644 --- a/core/os/device/deviceinfo/cc/android/query.cpp +++ b/core/os/device/deviceinfo/cc/android/query.cpp @@ -136,7 +136,6 @@ struct Context { EGLContext mContext; int mNumCores; std::string mHost; - std::string mSerial; std::string mHardware; std::string mOSName; std::string mOSBuild; @@ -501,7 +500,7 @@ const char* gpuName() { return ""; } const char* gpuVendor() { return ""; } -const char* instanceName() { return gContext.mSerial.c_str(); } +const char* instanceName() { return gContext.mHardware.c_str(); } const char* hardwareName() { return gContext.mHardware.c_str(); } From 4652079f5536399cde65430353cf3513ba491f67 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 7 Apr 2020 08:34:35 +0100 Subject: [PATCH 0216/1218] Remove GLES mentions from gapit flag -api (#198) Bug: b/153335128 --- cmd/gapit/benchmark.go | 12 +----------- cmd/gapit/flags.go | 3 +-- cmd/gapit/trace.go | 6 ------ 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/cmd/gapit/benchmark.go b/cmd/gapit/benchmark.go index 9464e9425b..668d371937 100644 --- a/cmd/gapit/benchmark.go +++ b/cmd/gapit/benchmark.go @@ -865,7 +865,7 @@ func (verb *benchmarkVerb) doTrace(ctx context.Context, client client.Client, tr options := &service.TraceOptions{ Device: traceDevice, - Apis: []string{}, + Apis: []string{"Vulkan"}, AdditionalCommandLineArgs: verb.AdditionalArgs, Cwd: verb.WorkingDir, Environment: verb.Env, @@ -886,16 +886,6 @@ func (verb *benchmarkVerb) doTrace(ctx context.Context, client client.Client, tr options.App = &service.TraceOptions_Uri{ uri, } - switch verb.API { - case "vulkan": - options.Apis = []string{"Vulkan"} - case "gles": - options.Apis = []string{"OpenGLES"} - case "": - return fmt.Errorf("Please specify one of vulkan or gles for an api") - default: - return fmt.Errorf("Unknown API %s", verb.API) - } verb.beforeStartTraceTime = time.Now() handler, err := client.Trace(ctx) if err != nil { diff --git a/cmd/gapit/flags.go b/cmd/gapit/flags.go index e9b3c46228..6eb8a6871b 100644 --- a/cmd/gapit/flags.go +++ b/cmd/gapit/flags.go @@ -320,7 +320,7 @@ type ( No struct { Buffer bool `help:"Do not buffer the output, this helps if the application crashes"` } - API string `help:"only capture the given API valid options are gles, vulkan, and perfetto"` + API string `help:"only capture the given API valid options are vulkan and perfetto"` Local struct { Port int `help:"connect to an application already running on the server using this port"` } @@ -335,7 +335,6 @@ type ( AdditionalArgs string `help:"additional arguments to pass to the application"` WorkingDir string `help:"working directory for the application"` URI string `help:"uri of the application to trace"` - API string `help:"only capture the given API valid options are gles and vulkan"` DumpTrace string `help:"dump a systrace of gapis"` StartFrame int `help:"perform a MEC trace starting at this frame"` NoOpt bool `help:"disables optimization of the replay stream"` diff --git a/cmd/gapit/trace.go b/cmd/gapit/trace.go index ae4e118f7e..6a0d880b0b 100644 --- a/cmd/gapit/trace.go +++ b/cmd/gapit/trace.go @@ -336,12 +336,6 @@ func (verb *traceVerb) apiAndType() (apiAndType, error) { []string{"Vulkan"}, ".gfxtrace", }, nil - case "gles": - return apiAndType{ - service.TraceType_Graphics, - []string{"OpenGLES"}, - ".gfxtrace", - }, nil case "perfetto": return apiAndType{ service.TraceType_Perfetto, From d9ad0217e8af4b52c7790a8fbeae55a6dbc3e70c Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 7 Apr 2020 14:08:36 +0100 Subject: [PATCH 0217/1218] Run several Swarming tests (#196) * Refactor Swarming tests to enable running multiple tests This is a prerequisite to use the same scripts for nightly tests. See details in test/swarming/README.md --- kokoro/linux/build.sh | 92 +++++++++++++++--------------- test/swarming/README.md | 84 +++++++++++++++++++++++++++ test/swarming/bot-harness.sh | 97 ++++++++++++++++++++++++++++++++ test/swarming/bot-task.sh | 62 ++++++++++++++++++++ test/swarming/collect.sh | 54 ++++++++++++++++++ test/swarming/manual-run.sh | 38 +++++++++++++ test/swarming/task-files/task.sh | 90 ----------------------------- test/swarming/task.isolate | 11 ---- test/swarming/trigger.sh | 91 ++++++++++++++++++++++++++++++ 9 files changed, 470 insertions(+), 149 deletions(-) create mode 100644 test/swarming/README.md create mode 100755 test/swarming/bot-harness.sh create mode 100755 test/swarming/bot-task.sh create mode 100755 test/swarming/collect.sh create mode 100755 test/swarming/manual-run.sh delete mode 100755 test/swarming/task-files/task.sh delete mode 100644 test/swarming/task.isolate create mode 100755 test/swarming/trigger.sh diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 539abb91e9..002f16c826 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -89,46 +89,39 @@ $SRC/kokoro/linux/package.sh $BUILD_ROOT/out ## Build is done, run some tests ## -## Test on a real device using swarming. APKs are stoed on x20, under: -## teams/android-graphics-tools/agi/kokoro/swarming/apk/*.apk +## Swarming tests, see test/swarming/README.md ## # Install LUCI curl -fsSL -o luci-py.tar.gz https://chromium.googlesource.com/infra/luci/luci-py.git/+archive/0b027452e658080df1f174c403946914443d2aa6.tar.gz mkdir luci-py tar xzvf luci-py.tar.gz --directory luci-py -LUCI_CLIENT_ROOT="$PWD/luci-py/client" +export LUCI_CLIENT_ROOT="$PWD/luci-py/client" -# Credentials come from Keystore -SWARMING_AUTH_TOKEN_FILE=${KOKORO_KEYSTORE_DIR}/74894_kokoro_swarming_access_key - -# Prepare task files -TASK_FILES_DIR=${SRC}/test/swarming/task-files -cp -r bazel-bin/pkg ${TASK_FILES_DIR}/agi -cp -r ${KOKORO_GFILE_DIR}/apk ${TASK_FILES_DIR}/ - -# Trigger task -AUTH_FLAG="--auth-service-account-json=$SWARMING_AUTH_TOKEN_FILE" -TASK_NAME="Kokoro_PR${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" -ISOLATE_SERVER='https://chrome-isolated.appspot.com' -SWARMING_SERVER='https://chrome-swarming.appspot.com' -SWARMING_POOL='SkiaInternal' -DEVICE_TYPE="flame" # pixel4 - -$LUCI_CLIENT_ROOT/isolate.py archive $AUTH_FLAG --isolate-server $ISOLATE_SERVER --isolate ${SRC}/test/swarming/task.isolate --isolated task.isolated -ISOLATED_SHA=`sha1sum task.isolated | awk '{ print $1 }' ` - -# Priority: lower is more priority, defaults to 200: PR short test tasks should be of higher priority than the default -PRIORITY=100 -# Hard timeout: maximum number of seconds for the task to terminate -HARD_TIMEOUT=300 -# Expiration: number of seconds to wait for a bot to be available -EXPIRATION=600 - -$LUCI_CLIENT_ROOT/swarming.py trigger $AUTH_FLAG --swarming $SWARMING_SERVER --isolate-server $ISOLATE_SERVER --isolated $ISOLATED_SHA --task-name ${TASK_NAME} --dump-json task.json --dimension pool $SWARMING_POOL --dimension device_type "$DEVICE_TYPE" --priority=$PRIORITY --expiration=$EXPIRATION --hard-timeout=$HARD_TIMEOUT +# Prepare Swarming files +# SWARMING_X20_TEST_DIR enables different Kokoro jobs to use different sets of tests +if [ -z "${SWARMING_X20_TEST_DIR}" ] ; then + SWARMING_X20_TEST_DIR="tests" +fi +SWARMING_DIR=${SRC}/test/swarming +cp -r bazel-bin/pkg ${SWARMING_DIR}/agi +cp -r ${KOKORO_GFILE_DIR}/${SWARMING_X20_TEST_DIR} ${SWARMING_DIR}/tests + +# Swarming environment +export SWARMING_AUTH_FLAG="--auth-service-account-json=${KOKORO_KEYSTORE_DIR}/74894_kokoro_swarming_access_key" +export SWARMING_BUILD_INFO="Kokoro-PR${KOKORO_GITHUB_PULL_REQUEST_NUMBER}" +export SWARMING_TRIGGERED_DIR="triggered" + +# Trigger the tests +pushd ${SWARMING_DIR} +mkdir -p ${SWARMING_TRIGGERED_DIR} +for t in tests/* ; do + ./trigger.sh ${t} +done +popd -# Collect the Swarming test results after the swiftshader tests, as swarming -# will take a few minutes to schedule+run the task anyway. +# Run the swiftshader test while Swarming tests are being scheduled+run, and +# collect Swarming test results after the Swiftshader test. ## ## Test capture and replay of the Vulkan Sample App. @@ -173,25 +166,28 @@ xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit trace -device host -disable-coherent xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -frames-minimum 10 -out vulkan_sample.mp4 vulkan_sample.gfxtrace ## -## Collect swarming test result +## Collect swarming test results ## -# The "swarming.py collect" call returns the task's exit code, which is non-zero -# if the task has expired (it was never scheduled). Allow for non-zero return -# code, and manually check the task status afterward -set +e -$LUCI_CLIENT_ROOT/swarming.py collect $AUTH_FLAG --swarming $SWARMING_SERVER --json task.json --task-summary-json summary.json -SWARMING_COLLECT_EXIT_CODE=$? -set -e +pushd ${SWARMING_DIR} -# Ignore failures that are not due to the test itself -if [ "$SWARMING_COLLECT_EXIT_CODE" -ne "0" ] ; then - if grep '"state": "EXPIRED"' summary.json > /dev/null ; then - echo "Swarming test was never scheduled, ignoring it" - elif grep '"internal_failure": true' summary.json > /dev/null ; then - echo "Swarming internal failure, ignore the swarming test" +SWARMING_FAILURE=0 +for TEST_NAME in ${SWARMING_TRIGGERED_DIR}/*.json ; do + set +e + ./collect.sh ${TEST_NAME} > `basename ${TEST_NAME} .json`.collect.log + EXIT_CODE=$? + set -e + if [ ${EXIT_CODE} -eq 0 ] ; then + echo "PASS ${TEST_NAME}" else - echo "Swarming test failed" - exit 1 + echo "FAIL ${TEST_NAME}" + SWARMING_FAILURE=1 fi +done + +popd + +if [ ${SWARMING_FAILURE} -eq 1 ] ; then + echo "Error: some Swarming test failed" + exit 1 fi diff --git a/test/swarming/README.md b/test/swarming/README.md new file mode 100644 index 0000000000..1c19791207 --- /dev/null +++ b/test/swarming/README.md @@ -0,0 +1,84 @@ +# Swarming: capture-replay tests on real Android devices + +This is a collection of shell scripts to run AGI tests on real Android devices. + +We can access devices through Swarming, which is part of +[LUCI](https://chromium.googlesource.com/infra/infra/+/master/doc/users/services/about_luci.md), +hence the name "swarming tests". + +A swarming test typically consists in installing an APK using Vulkan, and +running some `gapit` commands to capture-replay this APK. As we don't want to +include APKs in this repo, we store them on x20. + +## Scripts running order + +The scripts are primarly designed to run as part of Kokoro Linux builds. The +running order is: + +1. The Kokoro build script `kokoro/linux/build.sh` uses `test/swarming/trigger.sh` to + schedule Swarming tests. + +2. The Swarming bot runs `test/swarming/bot-harness.sh`, which wraps + `test/swarming/bot-task.sh` to make sure to always turn off the device screen + at the end of the task, even upon failure or time out. It is important to + always turn the screen off to make sure devices can cool-down, otherwise the + Swarming bot may become unusable. + +3. The Kokoro build script uses `test/swarming/collect.sh` to retrieve the + Swarming tests results. + +## How to run a Swarming test manually, outside of Kokoro + +Requirements: + +- LUCI tools installed, and the `LUCI_CLIENT_ROOT` environment variable set + accordingly. + +- valid Swarming/Isolate credentials. + +You can trigger a Swarming test manually with: + +1. Grab tests from x20: + `x20/teams/android-graphics-tools/agi/kokoro/swarming`. Copy the `tests` + folder under `test/swarming/`. + +2. Use `./manual-run.sh tests/foobar` to trigger the foobar test in Swarming and + collect its results. + +## How to run a Swarming test on a local device + +1. Grab tests from x20: + `x20/teams/android-graphics-tools/agi/kokoro/swarming`. Copy the `tests` + folder under `test/swarming/`. + +2. Make sure you have only one Android device plugged into your host machine. + +3. Use `./bot-harness.sh tests/foobar ${LOGDIR} ${TIMEOUT}` to run the foobar + test on the device plugged in your host machine, storing logs in the + `${LOGDIR}` directory, with a timeout limit of `${TIMEOUT}` seconds. + +## Test format + +A test is a folder that contains at least a `env.sh` file, which sets various +environment variables. A typical test contains an APK and a `env.sh` files with +the information needed by `bot-task.sh`, e.g.: + +``` +SWARMING_APK=com_example-app_version42.apk +SWARMING_PACKAGE=com.example.myApp +SWARMING_ACTIVITY=com.example.myApp.myActivity +SWARMING_STARTFRAME=5 +SWARMING_NUMFRAME=5 +``` + +Moreover, some `SWARMING_*` environment variables can be overriden on a +test-specific level. Some interesting ones: + +``` +# Space-separated list of devices to run on +SWARMING_DEVICES=flame +# Priority: lower value is higher priority +SWARMING_PRIORITY=100 +# Timeout: maximum number of seconds for the task to terminate +SWARMING_TIMEOUT=300 +``` diff --git a/test/swarming/bot-harness.sh b/test/swarming/bot-harness.sh new file mode 100755 index 0000000000..aac6d2c8c3 --- /dev/null +++ b/test/swarming/bot-harness.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is the swarming task harness. This is the entry point for the +# Swarming bot. + +set -x + +export SWARMING_TEST_DIR=$1 +if [ -z "${SWARMING_TEST_DIR}" -o ! -d "${SWARMING_TEST_DIR}" ] ; then + echo "Error: missing or invalid test directory argument." + exit 1 +fi + +export SWARMING_TIMEOUT=$2 +if [ -z "${SWARMING_TIMEOUT}" ] ; then + echo "Error: missing timeout argument." + exit 1 +fi + +export SWARMING_OUT_DIR=$3 +if [ -z "${SWARMING_OUT_DIR}" -o ! -d "${SWARMING_OUT_DIR}" ] ; then + echo "Error: missing or invalid outdir argument." + exit 1 +fi + +## Check expected files +if [ ! -f bot-task.sh ] ; then + echo "Error: no bot-task.sh file found" + exit 1 +fi + +if [ ! -d agi ] ; then + echo "Error: no agi/ directory found" + exit 1 +fi + +## Check we can access the Android device +if adb shell true ; then + echo "Device fingeprint: " `adb shell getprop ro.build.fingerprint`; +else + echo "Error: zero or more than one device connected" + exit 1 +fi + +## Set up environment +export SWARMING_AGI=`pwd`/agi +source ${SWARMING_TEST_DIR}/env.sh + +# Number of seconds to dump logcat and turn the screen off. +SWARMING_TIMEOUT_SAFETY=10 +if [ ${SWARMING_TIMEOUT} -lt ${SWARMING_TIMEOUT_SAFETY} ] ; then + echo "Error: SWARMING_TIMEOUT is less than ${SWARMING_TIMEOUT_SAFETY} seconds." + exit 1 +fi +SWARMING_TIMEOUT_GUARD="$(( ${SWARMING_TIMEOUT} - ${SWARMING_TIMEOUT_SAFETY} ))" + +## Lauch task test +adb logcat -c +timeout -k 1 $SWARMING_TIMEOUT_GUARD ./bot-task.sh +EXIT_CODE=$? +adb logcat -d > ${SWARMING_OUT_DIR}/logcat.txt + +echo "Exit code: ${EXIT_CODE}" + +## Turn off the device screen +# Key "power" (26) toggle between screen off and on, so first make sure to have +# the screen on with key "wake up" (224), then press "power" (26) +adb shell input keyevent 224 +sleep 2 # wait a bit to let any kind of device wake up animation terminate +adb shell input keyevent 26 + +# Analyze the exit code +if test ${EXIT_CODE} -eq 124 -o ${EXIT_CODE} -eq 137 ; then + echo "TIMEOUT" + echo "Sleep a bit more to hopefully trigger a Swarming-level timeout, which will be reported as such" + sleep ${SWARMING_TIMEOUT_SAFETY} +elif test ${EXIT_CODE} -ne 0 ; then + echo "FAIL" +else + echo "PASS" +fi + +exit ${EXIT_CODE} diff --git a/test/swarming/bot-task.sh b/test/swarming/bot-task.sh new file mode 100755 index 0000000000..5e2bc6e3f6 --- /dev/null +++ b/test/swarming/bot-task.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script is the actual AGI test to run as a Swarming test. Files written +# under SWARMING_OUT_DIR will be available as Swarming output artifacts. + +set -x +set -e + +if [ -z "${SWARMING_TEST_DIR}" -o ! -d "${SWARMING_TEST_DIR}" ] ; then + echo "Error: missing or invalid value for environment variable SWARMING_TEST_DIR" + exit 1 +fi + +if [ -z "${SWARMING_OUT_DIR}" -o ! -d "${SWARMING_OUT_DIR}" ] ; then + echo "Error: missing or invalid value for environment variable SWARMING_OUT_DIR" + exit 1 +fi + +if [ -z "${SWARMING_AGI}" -o ! -d "${SWARMING_AGI}" ] ; then + echo "Error: missing or invalid value for environment variable SWARMING_AGI" + exit 1 +fi + +cd ${SWARMING_TEST_DIR} + +source env.sh + +# APK install +if [ -z "${SWARMING_FORCE_INSTALL}" ] ; then + # Force-install not imposed, let's see if it is already installed + num_matching_packages=`adb shell pm list packages | grep ${SWARMING_PACKAGE} | wc -l` + if [ "${num_matching_packages}" != "1" ] ; then + SWARMING_FORCE_INSTALL=1 + else + installed_package=`adb shell pm list packages | grep ${SWARMING_PACKAGE} | sed -e 's/^package://'` + if [ "${installed_package}" != "${SWARMING_PACKAGE}" ] ; then + SWARMING_FORCE_INSTALL=1 + fi + fi +fi + +if [ ! -z "${SWARMING_FORCE_INSTALL}" ] ; then + adb install -g -t "$SWARMING_APK" +fi + +# Run AGI test +$SWARMING_AGI/gapit benchmark -api vulkan -startframe "${SWARMING_STARTFRAME}" -numframes "${SWARMING_NUMFRAME}" "${SWARMING_PACKAGE}/${SWARMING_ACTIVITY}" +mv benchmark.gfxtrace ${SWARMING_OUT_DIR}/ diff --git a/test/swarming/collect.sh b/test/swarming/collect.sh new file mode 100755 index 0000000000..70f3b98898 --- /dev/null +++ b/test/swarming/collect.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script collects the results of a Swarming task for a given test. + +set -x +set -e + +if [ -z "${LUCI_CLIENT_ROOT}" ] ; then + echo "Error: empty environment variable: LUCI_CLIENT_ROOT" + exit 1 +fi + +SWARMING_TEST_JSON=$1 +if [ ! -f "${SWARMING_TEST_JSON}" ] ; then + echo "Error: missing or invalid argument (should be the Swarming test json file generated by trigger.sh)." + exit 1 +fi +SWARMING_SUMMARY=summary_`basename ${SWARMING_TEST_JSON}` + +SWARMING_SERVER=https://chrome-swarming.appspot.com + +# The "swarming.py collect" call returns the task's exit code, which is non-zero +# if the task has expired (it was never scheduled). Allow for non-zero return +# code, and manually check the task status afterward +set +e +${LUCI_CLIENT_ROOT}/swarming.py collect ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --json ${SWARMING_TEST_JSON} --task-summary-json ${SWARMING_SUMMARY} +SWARMING_COLLECT_EXIT_CODE=$? +set -e + +# Ignore failures that are not due to the test itself +if [ "${SWARMING_COLLECT_EXIT_CODE}" != "0" ] ; then + if grep '"state": "EXPIRED"' ${SUMMARY} > /dev/null ; then + echo "Swarming test was never scheduled, ignoring it" + elif grep '"internal_failure": true' ${SUMMARY} > /dev/null ; then + echo "Swarming internal failure, ignore the swarming test" + else + echo "Swarming test failed" + exit 1 + fi +fi diff --git a/test/swarming/manual-run.sh b/test/swarming/manual-run.sh new file mode 100755 index 0000000000..8f83fbaf1b --- /dev/null +++ b/test/swarming/manual-run.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script enables to run a Swarming test outside of the Kokoro workflow + +set -e +set -x + +SWARMING_TEST_DIR=$1 +if [ -z "${SWARMING_TEST_DIR}" -o ! -d "${SWARMING_TEST_DIR}" ] ; then + echo "Error: missing or invalid test directory argument." + echo "Usage: `basename $0` tests/foobar" + exit 1 +fi + +# Fake Swarming environment +export SWARMING_AUTH_FLAG="" +export SWARMING_BUILD_INFO="Manual" +export SWARMING_TRIGGERED_DIR="triggered-manual" + +rm -rf ${SWARMING_TRIGGERED_DIR} +mkdir -p ${SWARMING_TRIGGERED_DIR} + +./trigger.sh ${SWARMING_TEST_DIR} +./collect.sh ${SWARMING_TRIGGERED_DIR}/*.json diff --git a/test/swarming/task-files/task.sh b/test/swarming/task-files/task.sh deleted file mode 100755 index daa755ee59..0000000000 --- a/test/swarming/task-files/task.sh +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash -# Copyright (C) 2020 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Swarming task script: this is what runs on the swarming bot - -# The only argument is the path to the isolate output directory -OUTDIR=$1 -# The script is launched in a directory above the task-files, start by cd'ing in -cd task-files - -# Clean-up on exit -cleanup() { - STATUS=$? - if [ -z "$EXIT_STATUS" ] ; then - EXIT_STATUS=${STATUS} - fi - # Key "power" (26) toggle between screen off and on, so first make sure to - # have the screen on with key "wake up" (224), then press "power" (26) - adb shell input keyevent 224 - sleep 1 # wake-up animation can take some time - adb shell input keyevent 26 - exit ${EXIT_STATUS} -} - -trap cleanup EXIT - -set -x - -############################################################################## -# Swarming test - -GAPIT=./agi/gapit - -# Prepare device -# launch adb deamon, this is a good thing to do when starting a swarming task -adb devices -# remove any implicit vulkan layers -adb shell settings delete global enable_gpu_debug_layers -adb shell settings delete global gpu_debug_app -adb shell settings delete global gpu_debug_layers -adb shell settings delete global gpu_debug_layer_app - -# NOTE: This script uses the APKs under the apk/ directory, and it assumes that -# all APKs are named as .apk, e.g. com.example.mygame.apk - -for apk in apk/*.apk -do - - # Install APK - package=`basename ${apk} .apk` - adb install -g -t ${apk} - - # Capture - adb logcat -c - $GAPIT -log-level Verbose trace -disable-pcs -disable-unknown-extensions -record-errors -no-buffer -api vulkan --start-at-frame 20 -capture-frames 5 -observe-frames 1 -out ${OUTDIR}/$package.gfxtrace $package > ${OUTDIR}/trace.out 2> ${OUTDIR}/trace.err - adb logcat -d > ${OUTDIR}/$package.trace.logcat - - # Stop the app - adb shell force-stop $package - - # Replay - adb logcat -c - $GAPIT video -gapir-nofallback -type sxs -frames-minimum 5 -out ${OUTDIR}/$package.mp4 ${OUTDIR}/$package.gfxtrace > ${OUTDIR}/video.out 2> ${OUTDIR}/video.err - adb logcat -d > ${OUTDIR}/$package.video.logcat - - if grep 'FramebufferObservation did not match replayed framebuffer' ${OUTDIR}/video.err > /dev/null ; then - echo "ERROR: replay leads to different image" - EXIT_STATUS=1 - cleanup - # cleanup should never return, but be safe and exit anyway - exit 1 - fi - -done - -EXIT_STATUS=0 -cleanup -exit 0 diff --git a/test/swarming/task.isolate b/test/swarming/task.isolate deleted file mode 100644 index fc47aab717..0000000000 --- a/test/swarming/task.isolate +++ /dev/null @@ -1,11 +0,0 @@ -{ - 'variables': { - 'files': [ - './task-files/', - ], - 'command': [ - './task-files/task.sh', - '${ISOLATED_OUTDIR}', - ], - }, -} diff --git a/test/swarming/trigger.sh b/test/swarming/trigger.sh new file mode 100755 index 0000000000..7a4f16e4b5 --- /dev/null +++ b/test/swarming/trigger.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This script triggers a Swarming task for a given test. + +set -x +set -e + +if [ -z "${LUCI_CLIENT_ROOT}" ] ; then + echo "Error: empty environment variable: LUCI_CLIENT_ROOT" + exit 1 +fi + +if [ -z "${SWARMING_BUILD_INFO}" ] ; then + echo "Error: empty environment variable: SWARMING_BUILD_INFO" + exit 1 +fi + +if [ -z "${SWARMING_TRIGGERED_DIR}" ] ; then + echo "Error: empty environment variable: SWARMING_TRIGGERED_DIR" + exit 1 +fi + +SWARMING_TEST_DIR=$1 +if [ -z "${SWARMING_TEST_DIR}" -o ! -d "${SWARMING_TEST_DIR}" ] ; then + echo "Error: missing or invalid test directory argument." + echo "Usage: `basename $0` tests/foobar" + exit 1 +fi +# Sanitize name +SWARMING_TEST_DIR="`dirname ${SWARMING_TEST_DIR}`/`basename ${SWARMING_TEST_DIR}`" +SWARMING_TEST_NAME=`basename ${SWARMING_TEST_DIR}` + +# Set up environment +SWARMING_TASK_NAME="${SWARMING_BUILD_INFO}_${SWARMING_TEST_NAME}" +SWARMING_ISOLATE_SERVER=https://chrome-isolated.appspot.com +SWARMING_SERVER=https://chrome-swarming.appspot.com +SWARMING_POOL=SkiaInternal +SWARMING_DEVICES=flame # pixel4 +# Priority: lower value is higher priority, defaults to 200: PR short test tasks should be of higher priority than the default +SWARMING_PRIORITY=100 +# Timeout: maximum number of seconds for the task to terminate +SWARMING_TIMEOUT=300 +# Expiration: number of seconds to wait for a bot to be available +SWARMING_EXPIRATION=600 + +# The test may override some of the environment variables +source ${SWARMING_TEST_DIR}/env.sh + +# Generate config for isolate +cat << EOF > ${SWARMING_TEST_NAME}.isolate +{ + 'variables': { + 'files': [ + 'agi/', + 'bot-harness.sh', + 'bot-task.sh', + '${SWARMING_TEST_DIR}/', + ], + 'command': [ + './bot-harness.sh', + '${SWARMING_TEST_DIR}', + '${SWARMING_TIMEOUT}', + '\${ISOLATED_OUTDIR}', + ], + }, +} +EOF + +# Upload to isolate +${LUCI_CLIENT_ROOT}/isolate.py archive ${SWARMING_AUTH_FLAG} --isolate-server ${SWARMING_ISOLATE_SERVER} --isolate ${SWARMING_TEST_NAME}.isolate --isolated ${SWARMING_TEST_NAME}.isolated +SWARMING_ISOLATED_SHA=`sha1sum ${SWARMING_TEST_NAME}.isolated | awk '{ print $1 }'` + +# Trigger Swarming task +for DEV in ${SWARMING_DEVICES} ; do + SWARMING_TASK_JSON=${SWARMING_TRIGGERED_DIR}/${SWARMING_TEST_NAME}.${DEV}.json + ${LUCI_CLIENT_ROOT}/swarming.py trigger ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --isolate-server ${SWARMING_ISOLATE_SERVER} --isolated ${SWARMING_ISOLATED_SHA} --task-name ${SWARMING_TASK_NAME} --dump-json ${SWARMING_TASK_JSON} --dimension pool ${SWARMING_POOL} --dimension device_type ${SWARMING_DEVICES} --priority=${SWARMING_PRIORITY} --expiration=${SWARMING_EXPIRATION} --hard-timeout=${SWARMING_TIMEOUT} +done From 43ccb6d6933c269ff087edddb762a71d75d68986 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 7 Apr 2020 16:01:38 +0100 Subject: [PATCH 0218/1218] Remove -api flag from benchmark call (#201) This flag was removed with #198, which was merged in parallel with #196. --- test/swarming/bot-task.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/swarming/bot-task.sh b/test/swarming/bot-task.sh index 5e2bc6e3f6..9ceda66b0e 100755 --- a/test/swarming/bot-task.sh +++ b/test/swarming/bot-task.sh @@ -58,5 +58,5 @@ if [ ! -z "${SWARMING_FORCE_INSTALL}" ] ; then fi # Run AGI test -$SWARMING_AGI/gapit benchmark -api vulkan -startframe "${SWARMING_STARTFRAME}" -numframes "${SWARMING_NUMFRAME}" "${SWARMING_PACKAGE}/${SWARMING_ACTIVITY}" +$SWARMING_AGI/gapit benchmark -startframe "${SWARMING_STARTFRAME}" -numframes "${SWARMING_NUMFRAME}" "${SWARMING_PACKAGE}/${SWARMING_ACTIVITY}" mv benchmark.gfxtrace ${SWARMING_OUT_DIR}/ From 51407f07b1fc3a71b77c53b5b7d54249a8af0bcc Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 7 Apr 2020 16:04:39 +0100 Subject: [PATCH 0219/1218] Add Kokoro linux/nightly config (#200) --- kokoro/linux/nightly.cfg | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 kokoro/linux/nightly.cfg diff --git a/kokoro/linux/nightly.cfg b/kokoro/linux/nightly.cfg new file mode 100644 index 0000000000..6061509e52 --- /dev/null +++ b/kokoro/linux/nightly.cfg @@ -0,0 +1,24 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Nightly build configuration. +gfile_resources: "/x20/teams/android-graphics-tools/agi/kokoro/swarming_nightly" + +env_vars { + key: "SWARMING_X20_TEST_DIR" + value: "tests_nightly" +} + +# Nightly Swarming tests take hours to complete. +timeout_mins: 480 From c391b37474a2c4259bef3f82d33ab1bb3d05ce8a Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Wed, 8 Apr 2020 15:13:03 +0100 Subject: [PATCH 0220/1218] Reduce noise in Linux build logs (#203) --- kokoro/linux/build.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 002f16c826..2d460eba71 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -95,7 +95,7 @@ $SRC/kokoro/linux/package.sh $BUILD_ROOT/out # Install LUCI curl -fsSL -o luci-py.tar.gz https://chromium.googlesource.com/infra/luci/luci-py.git/+archive/0b027452e658080df1f174c403946914443d2aa6.tar.gz mkdir luci-py -tar xzvf luci-py.tar.gz --directory luci-py +tar xzf luci-py.tar.gz --directory luci-py export LUCI_CLIENT_ROOT="$PWD/luci-py/client" # Prepare Swarming files @@ -138,7 +138,8 @@ unzip -d swiftshader swiftshader.zip # Use SwiftShader. export VK_ICD_FILENAMES="$(pwd)/swiftshader/lib/vk_swiftshader_icd.json" -export VK_LOADER_DEBUG=all +# For extensive Vulkan loader logs, set to VK_LOADER_DEBUG=all +export VK_LOADER_DEBUG=warn # Just try running the app first. From 89cc1d05058985fab21243ec0a37fe57cae790db Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Fri, 10 Apr 2020 11:55:18 +0100 Subject: [PATCH 0221/1218] Avoid possible code injection from x20 (#205) --- test/swarming/trigger.sh | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/test/swarming/trigger.sh b/test/swarming/trigger.sh index 7a4f16e4b5..10e8344e87 100755 --- a/test/swarming/trigger.sh +++ b/test/swarming/trigger.sh @@ -49,16 +49,26 @@ SWARMING_TASK_NAME="${SWARMING_BUILD_INFO}_${SWARMING_TEST_NAME}" SWARMING_ISOLATE_SERVER=https://chrome-isolated.appspot.com SWARMING_SERVER=https://chrome-swarming.appspot.com SWARMING_POOL=SkiaInternal -SWARMING_DEVICES=flame # pixel4 -# Priority: lower value is higher priority, defaults to 200: PR short test tasks should be of higher priority than the default +# String with space-separated device names +SWARMING_DEVICES="flame" +# Priority: lower value is higher priority, defaults to 200: PR short test tasks +# should be of higher priority than the default SWARMING_PRIORITY=100 # Timeout: maximum number of seconds for the task to terminate SWARMING_TIMEOUT=300 # Expiration: number of seconds to wait for a bot to be available SWARMING_EXPIRATION=600 -# The test may override some of the environment variables -source ${SWARMING_TEST_DIR}/env.sh +# The test may override some of the environment variables. For security reasons, +# we don't want to 'source' the test 'env.sh' as this could lead to code +# injection. Instead, we grep all relevant environment variables that may be +# overriden. +for envvar in SWARMING_DEVICES SWARMING_PRIORITY SWARMING_TIMEOUT SWARMING_EXPIRATION ; do + value=`grep ${envvar} ${SWARMING_TEST_DIR}/env.sh | sed -e 's/^.*=//'` + if [ ! -z "${value}" ] ; then + declare ${envvar}=${value} + fi +done # Generate config for isolate cat << EOF > ${SWARMING_TEST_NAME}.isolate From 935924b2469c57948a6ede04f28e17c8d16fa18e Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 6 Apr 2020 21:33:05 -0700 Subject: [PATCH 0222/1218] Events without mutate We only needed to mutate for: - command filter on events, which we don't use - possible unspecified extension uses, of which we have none - the old GLES transform feedback / drawcall flags Unpicking this allows us to remove the mutate (and dependency on sync data) making events significantly cheaper. This reduces the cost of building the event list on the Crytek trace from 540ms to 1.2ms on a Z840. Total cost of building the command tree on the same machine reduces from 2.3s to 1.8s. No significant impact to wall clock time to idle. --- gapil/compiler/testutils/cmd.go | 2 +- gapis/api/cmd.go | 2 +- gapis/api/templates/api.go.tmpl | 33 ++------- gapis/api/vulkan/command_splitter.go | 4 +- gapis/api/vulkan/read_framebuffer.go | 6 +- gapis/replay/custom.go | 28 ++++---- gapis/resolve/cmdgrouper/cmdgrouper.go | 2 +- gapis/resolve/command_tree.go | 2 +- .../dependencygraph2/dependency_graph_test.go | 16 ++--- .../resolve/dependencygraph2/graph_builder.go | 2 +- gapis/resolve/events.go | 70 +------------------ gapis/resolve/resource_data.go | 6 +- gapis/resolve/stats.go | 10 +-- 13 files changed, 39 insertions(+), 144 deletions(-) diff --git a/gapil/compiler/testutils/cmd.go b/gapil/compiler/testutils/cmd.go index 8fc03327ab..ac77bc4081 100644 --- a/gapil/compiler/testutils/cmd.go +++ b/gapil/compiler/testutils/cmd.go @@ -63,7 +63,7 @@ func (c *Cmd) CmdParams() api.Properties { return nil } func (c *Cmd) CmdResult() *api.Property { return nil } // CmdFlags stubs the api.Cmd interface. -func (c *Cmd) CmdFlags(context.Context, api.CmdID, *api.GlobalState) api.CmdFlags { return 0 } +func (c *Cmd) CmdFlags() api.CmdFlags { return 0 } // Extras stubs the api.Cmd interface. func (c *Cmd) Extras() *api.CmdExtras { diff --git a/gapis/api/cmd.go b/gapis/api/cmd.go index e8dab3ac4d..44c7e312d3 100644 --- a/gapis/api/cmd.go +++ b/gapis/api/cmd.go @@ -51,7 +51,7 @@ type Cmd interface { CmdResult() *Property // CmdFlags returns the flags of the command. - CmdFlags(context.Context, CmdID, *GlobalState) CmdFlags + CmdFlags() CmdFlags // Extras returns all the Extras associated with the command. Extras() *CmdExtras diff --git a/gapis/api/templates/api.go.tmpl b/gapis/api/templates/api.go.tmpl index f936173ad0..eebe34a33f 100644 --- a/gapis/api/templates/api.go.tmpl +++ b/gapis/api/templates/api.go.tmpl @@ -1806,7 +1806,7 @@ import ( {{end}} } - func (ϟc *{{$name}}) CmdFlags(ϟctx context.Context, ϟi ϟapi.CmdID, ϟg *ϟapi.GlobalState) ϟapi.CmdFlags { + func (ϟc *{{$name}}) CmdFlags() ϟapi.CmdFlags { {{$names := Strings "draw_call" "transform_feedback" "clear" "frame_start" "frame_end" "user_marker" "push_user_marker" "pop_user_marker" "executed_draw" "submission"}} {{$flags := Strings "DrawCall" "TransformFeedback" "Clear" "StartOfFrame" "EndOfFrame" "UserMarker" "PushUserMarker" "PopUserMarker" "ExecutedDraw" "Submission"}} @@ -2183,34 +2183,9 @@ import ( {{if len $.Annotation.Arguments}} {{$expr := index $.Annotation.Arguments 0}} - {{if $call := Macro "FlagCall" "Expr" $expr "Flag" $.Flag}} - if {{$call}}; v { - out = out | ϟapi.{{$.Flag}} - } - {{else}} - if {{Template "Go.Read" $expr}} { - out = out | ϟapi.{{$.Flag}} - } - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a local assigned to the result of an expression call if $.Expr is a - call. Used by CmdFlags(). -------------------------------------------------------------------------------- -*/}} -{{define "FlagCall"}} - {{AssertType $.Expr "Expression"}} - - {{if IsCall $.Expr}} - {{$call := Unpack $.Expr}} - {{$args := ForEach $call.Arguments "Go.Read" | JoinWith ", "}} - v, _ := {{Template "Go.Subroutine" $call.Target.Function}}(ϟctx, ϟc, ϟi, ϟc.Extras().Observations(), ϟg, GetState(ϟg), ϟc.Thread(), nil, nil, {{$args}}) - {{else}} - {{Error "%T" $.Expr}} + if {{Template "Go.Read" $expr}} { + out = out | ϟapi.{{$.Flag}} + } {{end}} {{end}} diff --git a/gapis/api/vulkan/command_splitter.go b/gapis/api/vulkan/command_splitter.go index e18093f1a3..af74ff5eb6 100644 --- a/gapis/api/vulkan/command_splitter.go +++ b/gapis/api/vulkan/command_splitter.go @@ -73,7 +73,7 @@ func (s *InsertionCommand) CmdResult() *api.Property { return nil } -func (s *InsertionCommand) CmdFlags(context.Context, api.CmdID, *api.GlobalState) api.CmdFlags { +func (s *InsertionCommand) CmdFlags() api.CmdFlags { return 0 } @@ -774,7 +774,7 @@ func (t *commandSplitter) Transform(ctx context.Context, id api.CmdID, cmd api.C } if len(cuts) == 0 { - if cmd.CmdFlags(ctx, id, out.State()).IsEndOfFrame() { + if cmd.CmdFlags().IsEndOfFrame() { if err := out.MutateAndWrite(ctx, id, &InsertionCommand{ VkCommandBuffer(0), append([]VkCommandBuffer{}, t.pendingCommandBuffers...), diff --git a/gapis/api/vulkan/read_framebuffer.go b/gapis/api/vulkan/read_framebuffer.go index cf9ce1e050..846382bdaa 100644 --- a/gapis/api/vulkan/read_framebuffer.go +++ b/gapis/api/vulkan/read_framebuffer.go @@ -71,14 +71,12 @@ func newReadFramebuffer(ctx context.Context) *readFramebuffer { // If we are acutally swapping, we really do want to show the image before // the framebuffer read. func (t *readFramebuffer) Transform(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) error { - s := out.State() - if cmd, ok := cmd.(*InsertionCommand); ok { idx_string := keyFromIndex(cmd.idx) if r, ok := t.injections[idx_string]; ok { // If this command is FOR an EOF command, we want to mutate it, so that // we have the presentation info available. - if cmd.callee != nil && cmd.callee.CmdFlags(ctx, id, s).IsEndOfFrame() { + if cmd.callee != nil && cmd.callee.CmdFlags().IsEndOfFrame() { cmd.callee.Mutate(ctx, id, out.State(), nil, nil) } for _, injection := range r { @@ -166,7 +164,7 @@ func (t *readFramebuffer) Color(ctx context.Context, id api.SubCmdIdx, width, he cb := CommandBuilder{Thread: cmd.Thread(), Arena: s.Arena} - isPresent := cmd.callee != nil && cmd.callee.CmdFlags(ctx, api.CmdID(id[0]), s).IsEndOfFrame() + isPresent := cmd.callee != nil && cmd.callee.CmdFlags().IsEndOfFrame() // TODO: Figure out a better way to select the framebuffer here. diff --git a/gapis/replay/custom.go b/gapis/replay/custom.go index dc26651c39..30bf0d4757 100644 --- a/gapis/replay/custom.go +++ b/gapis/replay/custom.go @@ -41,17 +41,17 @@ func (c Custom) Mutate(ctx context.Context, id api.CmdID, s *api.GlobalState, } // api.Cmd compliance -func (Custom) Caller() api.CmdID { return api.CmdNoID } -func (Custom) SetCaller(api.CmdID) {} -func (cmd Custom) Thread() uint64 { return cmd.T } -func (cmd Custom) SetThread(t uint64) { cmd.T = t } -func (Custom) CmdName() string { return "" } -func (Custom) API() api.API { return nil } -func (Custom) CmdParams() api.Properties { return nil } -func (Custom) CmdResult() *api.Property { return nil } -func (Custom) CmdFlags(context.Context, api.CmdID, *api.GlobalState) api.CmdFlags { return 0 } -func (Custom) Extras() *api.CmdExtras { return nil } -func (cmd Custom) Clone(arena.Arena) api.Cmd { return Custom{cmd.T, cmd.F} } -func (Custom) Alive() bool { return false } -func (Custom) Terminated() bool { return false } -func (Custom) SetTerminated(bool) {} +func (Custom) Caller() api.CmdID { return api.CmdNoID } +func (Custom) SetCaller(api.CmdID) {} +func (cmd Custom) Thread() uint64 { return cmd.T } +func (cmd Custom) SetThread(t uint64) { cmd.T = t } +func (Custom) CmdName() string { return "" } +func (Custom) API() api.API { return nil } +func (Custom) CmdParams() api.Properties { return nil } +func (Custom) CmdResult() *api.Property { return nil } +func (Custom) CmdFlags() api.CmdFlags { return 0 } +func (Custom) Extras() *api.CmdExtras { return nil } +func (cmd Custom) Clone(arena.Arena) api.Cmd { return Custom{cmd.T, cmd.F} } +func (Custom) Alive() bool { return false } +func (Custom) Terminated() bool { return false } +func (Custom) SetTerminated(bool) {} diff --git a/gapis/resolve/cmdgrouper/cmdgrouper.go b/gapis/resolve/cmdgrouper/cmdgrouper.go index 57eeb20874..7f1df5f9d1 100644 --- a/gapis/resolve/cmdgrouper/cmdgrouper.go +++ b/gapis/resolve/cmdgrouper/cmdgrouper.go @@ -89,7 +89,7 @@ type marker struct { } func (g *marker) Process(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState) { - flags := cmd.CmdFlags(ctx, id, s) + flags := cmd.CmdFlags() if flags.IsPushUserMarker() { g.push(ctx, id, cmd, s) } diff --git a/gapis/resolve/command_tree.go b/gapis/resolve/command_tree.go index a4f1b8b38e..d6e613f178 100644 --- a/gapis/resolve/command_tree.go +++ b/gapis/resolve/command_tree.go @@ -330,7 +330,7 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error out.root.AddCommand(id) - if flags := cmd.CmdFlags(ctx, id, s); flags.IsDrawCall() || flags.IsClear() { + if flags := cmd.CmdFlags(); flags.IsDrawCall() || flags.IsClear() { drawOrClearCmds = append(drawOrClearCmds, &api.CmdIDRange{ Start: id, End: id + 1, }) diff --git a/gapis/resolve/dependencygraph2/dependency_graph_test.go b/gapis/resolve/dependencygraph2/dependency_graph_test.go index 92d372ed59..ba56f6d56e 100644 --- a/gapis/resolve/dependencygraph2/dependency_graph_test.go +++ b/gapis/resolve/dependencygraph2/dependency_graph_test.go @@ -31,14 +31,14 @@ import ( type TestCmd struct{} -func (TestCmd) API() api.API { return nil } -func (TestCmd) Caller() api.CmdID { return 0 } -func (TestCmd) SetCaller(api.CmdID) {} -func (TestCmd) Thread() uint64 { return 0 } -func (TestCmd) SetThread(uint64) {} -func (TestCmd) CmdName() string { return "TestCmd" } -func (TestCmd) CmdFlags(context.Context, api.CmdID, *api.GlobalState) api.CmdFlags { return 0 } -func (TestCmd) Extras() *api.CmdExtras { return &api.CmdExtras{} } +func (TestCmd) API() api.API { return nil } +func (TestCmd) Caller() api.CmdID { return 0 } +func (TestCmd) SetCaller(api.CmdID) {} +func (TestCmd) Thread() uint64 { return 0 } +func (TestCmd) SetThread(uint64) {} +func (TestCmd) CmdName() string { return "TestCmd" } +func (TestCmd) CmdFlags() api.CmdFlags { return 0 } +func (TestCmd) Extras() *api.CmdExtras { return &api.CmdExtras{} } func (TestCmd) Mutate(context.Context, api.CmdID, *api.GlobalState, *builder.Builder, api.StateWatcher) error { return nil } diff --git a/gapis/resolve/dependencygraph2/graph_builder.go b/gapis/resolve/dependencygraph2/graph_builder.go index 61e1eb7d66..c0b8837fbe 100644 --- a/gapis/resolve/dependencygraph2/graph_builder.go +++ b/gapis/resolve/dependencygraph2/graph_builder.go @@ -242,7 +242,7 @@ func (b *graphBuilder) GetOrCreateCmdNodeID(ctx context.Context, cmdID api.CmdID return nodeID } fullIdx := append(api.SubCmdIdx{(uint64)(cmdID)}, idx...) - node := CmdNode{fullIdx, cmd.CmdFlags(ctx, cmdID, b.state)} + node := CmdNode{fullIdx, cmd.CmdFlags()} return b.addNode(node) } diff --git a/gapis/resolve/events.go b/gapis/resolve/events.go index 6ca7277511..dee4fcfdea 100644 --- a/gapis/resolve/events.go +++ b/gapis/resolve/events.go @@ -16,11 +16,9 @@ package resolve import ( "context" - "fmt" "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/capture" - "github.com/google/gapid/gapis/extensions" "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" ) @@ -32,40 +30,8 @@ func Events(ctx context.Context, p *path.Events, r *path.ResolveConfig) (*servic return nil, err } - sd, err := SyncData(ctx, p.Capture) - if err != nil { - return nil, err - } - - filter, err := buildFilter(ctx, p.Capture, p.Filter, sd, r) - if err != nil { - return nil, err - } - - // Add any extension event filters - filters := CommandFilters{filter} - for _, e := range extensions.Get() { - if f := e.EventFilter; f != nil { - if filter := CommandFilter(f(ctx, p, r)); filter != nil { - filters = append(filters, filter) - } - } - } - filter = filters.All - - // Add any extension events - eps := []extensions.EventProvider{} - for _, e := range extensions.Get() { - if e.Events != nil { - if ep := e.Events(ctx, p, r); ep != nil { - eps = append(eps, ep) - } - } - } - events := []*service.Event{} - s := c.NewState(ctx) lastCmd := api.CmdID(0) var pending []service.EventKind @@ -81,39 +47,12 @@ func Events(ctx context.Context, p *path.Events, r *path.ResolveConfig) (*servic return 0 } err = api.ForeachCmd(ctx, c.Commands, true, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { - if err := cmd.Mutate(ctx, id, s, nil, nil); err != nil { - return fmt.Errorf("Fail to mutate command %v: %v", cmd, err) - } - - // TODO: Add event generation to the API files. - if !filter(id, cmd, s) { - return nil - } - // For a given command, if the command has a FirstInFrame // event, we want that to come before all other events for that // command, and likewise for a LastInFrame event, it should be // after all other events for that command (except // FramebufferObservation as described below). - // Since extension.EventProvider's can provide any type of - // event, we split them up into FirstInFrame, LastInFrame, and - // rest, and then insert them into the event list in the right - // spot to ensure the ordering is maintained. - var epFirstInFrame, epNormal, epLastInFrame []*service.Event - for _, ep := range eps { - for _, event := range ep(ctx, id, cmd, s) { - switch event.Kind { - case service.EventKind_FirstInFrame: - epFirstInFrame = append(epFirstInFrame, event) - case service.EventKind_LastInFrame: - epLastInFrame = append(epFirstInFrame, event) - default: - epNormal = append(epNormal, event) - } - } - } - - f := cmd.CmdFlags(ctx, id, s) + f := cmd.CmdFlags() // Add LastInFrame event of a previous command first. if p.LastInFrame && f.IsStartOfFrame() && lastCmd > 0 { @@ -142,9 +81,6 @@ func Events(ctx context.Context, p *path.Events, r *path.ResolveConfig) (*servic Timestamp: getTime(cmd), }) } - if p.FirstInFrame { - events = append(events, epFirstInFrame...) - } if p.FirstInFrame && f.IsEndOfFrame() { pending = append(pending, service.EventKind_FirstInFrame) } @@ -156,7 +92,6 @@ func Events(ctx context.Context, p *path.Events, r *path.ResolveConfig) (*servic }) } // Add all non-special event types - events = append(events, epNormal...) if p.DrawCalls && f.IsDrawCall() { events = append(events, &service.Event{ Kind: service.EventKind_DrawCall, @@ -214,9 +149,6 @@ func Events(ctx context.Context, p *path.Events, r *path.ResolveConfig) (*servic Timestamp: getTime(cmd), }) } - if p.LastInFrame { - events = append(events, epLastInFrame...) - } if p.FramebufferObservations { // NOTE: gapit SxS video depends on FBO events coming after // all other event types. diff --git a/gapis/resolve/resource_data.go b/gapis/resolve/resource_data.go index 9723be24a1..954c2ffff5 100644 --- a/gapis/resolve/resource_data.go +++ b/gapis/resolve/resource_data.go @@ -186,12 +186,8 @@ func Pipelines(ctx context.Context, p *path.Pipelines, r *path.ResolveConfig) (i if err != nil { return nil, err } - state, err := GlobalState(ctx, &path.GlobalState{After: p.After}, r) - if err != nil { - return nil, err - } - if !cmd.CmdFlags(ctx, api.CmdID(p.After.Indices[0]), state).IsExecutedDraw() || len(p.After.Indices) == 1 { + if !cmd.CmdFlags().IsExecutedDraw() || len(p.After.Indices) == 1 { return nil, &service.ErrDataUnavailable{Reason: messages.ErrNotADrawCall()} } diff --git a/gapis/resolve/stats.go b/gapis/resolve/stats.go index 740febce01..986d6e0140 100644 --- a/gapis/resolve/stats.go +++ b/gapis/resolve/stats.go @@ -96,13 +96,7 @@ func drawCallStats(ctx context.Context, capt *path.Capture, stats *service.Stats if len(idx) == 1 { cmdflags = flags[idx[0]] } else { - // NOTE: For subcommands its not clear - // what the "correct" state to present - // to CmdFlags is. Since Vulkan - // currently does not use the state, - // pass nil here instead of a - // potentially "incorrect" state. - cmdflags = cmd.CmdFlags(ctx, api.CmdID(idx[0]), nil) + cmdflags = cmd.CmdFlags() } if (len(idx) == 1 && cmdflags.IsDrawCall()) || (len(idx) > 1 && cmdflags.IsExecutedDraw()) { @@ -130,7 +124,7 @@ func drawCallStats(ctx context.Context, capt *path.Capture, stats *service.Stats if err := cmd.Mutate(ctx, api.CmdID(idx), st, nil, nil); err != nil { return fmt.Errorf("Fail to mutate command %v: %v", cmd, err) } - flags[idx] = cmd.CmdFlags(ctx, api.CmdID(idx), st) + flags[idx] = cmd.CmdFlags() // If the command wasn't included in the dependency graph, // assume its a synchronous command (e.g. glDraw) From 959baab988c39505ffecd33ed80965d38568deb4 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 7 Apr 2020 12:04:35 -0700 Subject: [PATCH 0223/1218] Remove extension mechanism --- gapis/extensions/BUILD.bazel | 28 ------------- gapis/extensions/extensions.go | 74 ---------------------------------- gapis/resolve/BUILD.bazel | 1 - gapis/resolve/command_tree.go | 6 --- 4 files changed, 109 deletions(-) delete mode 100644 gapis/extensions/BUILD.bazel delete mode 100644 gapis/extensions/extensions.go diff --git a/gapis/extensions/BUILD.bazel b/gapis/extensions/BUILD.bazel deleted file mode 100644 index 2706a3f840..0000000000 --- a/gapis/extensions/BUILD.bazel +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = ["extensions.go"], - importpath = "github.com/google/gapid/gapis/extensions", - visibility = ["//visibility:public"], - deps = [ - "//gapis/api:go_default_library", - "//gapis/resolve/cmdgrouper:go_default_library", - "//gapis/service:go_default_library", - "//gapis/service/path:go_default_library", - ], -) diff --git a/gapis/extensions/extensions.go b/gapis/extensions/extensions.go deleted file mode 100644 index 149120d271..0000000000 --- a/gapis/extensions/extensions.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package extensions provides extension functionality to GAPIS. -// -// Extensions would ideally be plugins, but golang still doesn't have -// cross platform support. See: https://github.com/golang/go/issues/19282 -package extensions - -import ( - "context" - "sync" - - "github.com/google/gapid/gapis/api" - "github.com/google/gapid/gapis/resolve/cmdgrouper" - "github.com/google/gapid/gapis/service" - "github.com/google/gapid/gapis/service/path" -) - -var ( - extensions []Extension - mutex sync.Mutex -) - -// EventProvider is a function that produces events for the given command and -// state. -type EventProvider func(ctx context.Context, id api.CmdID, cmd api.Cmd, s *api.GlobalState) []*service.Event - -// EventFilter is a predicate used for filtering event commands. -// If the function returns true then the command is considered for event -// generation, otherwise it is ignored. -type EventFilter func(api.CmdID, api.Cmd, *api.GlobalState) bool - -// Extension is a GAPIS extension. -// It should be registered at application initialization with Register. -type Extension struct { - // Name of the extension. - Name string - // Custom command groupers. - CmdGroupers func(ctx context.Context, p *path.CommandTree, r *path.ResolveConfig) []cmdgrouper.Grouper - // Custom events provider. - Events func(ctx context.Context, p *path.Events, r *path.ResolveConfig) EventProvider - // Custom events filters. - EventFilter func(ctx context.Context, p *path.Events, r *path.ResolveConfig) EventFilter -} - -// Register registers the extension e. -func Register(e Extension) { - mutex.Lock() - defer mutex.Unlock() - - extensions = append(extensions, e) -} - -// Get returns the full list of registered extensions. -func Get() []Extension { - mutex.Lock() - defer mutex.Unlock() - - out := make([]Extension, len(extensions)) - copy(out, extensions) - return out -} diff --git a/gapis/resolve/BUILD.bazel b/gapis/resolve/BUILD.bazel index 6325b7b3fe..855801e516 100644 --- a/gapis/resolve/BUILD.bazel +++ b/gapis/resolve/BUILD.bazel @@ -78,7 +78,6 @@ go_library( "//gapis/api/sync:go_default_library", "//gapis/capture:go_default_library", "//gapis/database:go_default_library", - "//gapis/extensions:go_default_library", "//gapis/memory:go_default_library", "//gapis/messages:go_default_library", "//gapis/replay:go_default_library", diff --git a/gapis/resolve/command_tree.go b/gapis/resolve/command_tree.go index d6e613f178..f1a7cd06c6 100644 --- a/gapis/resolve/command_tree.go +++ b/gapis/resolve/command_tree.go @@ -24,7 +24,6 @@ import ( "github.com/google/gapid/gapis/api" "github.com/google/gapid/gapis/capture" "github.com/google/gapid/gapis/database" - "github.com/google/gapid/gapis/extensions" "github.com/google/gapid/gapis/resolve/cmdgrouper" "github.com/google/gapid/gapis/service" "github.com/google/gapid/gapis/service/path" @@ -227,11 +226,6 @@ func (r *CommandTreeResolvable) Resolve(ctx context.Context) (interface{}, error groupers = append(groupers, cmdgrouper.Marker()) } - // Add any extension groupers - for _, e := range extensions.Get() { - groupers = append(groupers, e.CmdGroupers(ctx, p, r.Config)...) - } - // Walk the list of unfiltered commands to build the groups. s := c.NewState(ctx) err = api.ForeachCmd(ctx, c.Commands, false, func(ctx context.Context, id api.CmdID, cmd api.Cmd) error { From 57f26aa9e042c9541467f143d5eb8321359e46c0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 7 Apr 2020 16:29:32 -0700 Subject: [PATCH 0224/1218] Precache the initial payload as soon as we start building a batch In any real session we will need this payload. * If the first batch is from GpuProfile then we don't use the initial payload for this batch but we can completely hide its cost behind the execution time of the GpuProfile replay. * If the first batch is *not* from GpuProfile, then we will end up waiting later in the function for the initial payload, but are able to overlap some of its cost with `Connect` (which can cost 3-4s on a Pixel 4) Improves wall clock time to idle on the Crytek trace on N10 + Z840 by approx 5 seconds. --- gapis/replay/batch.go | 65 ++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/gapis/replay/batch.go b/gapis/replay/batch.go index e913d65904..fc028a9924 100644 --- a/gapis/replay/batch.go +++ b/gapis/replay/batch.go @@ -20,6 +20,7 @@ import ( "github.com/google/gapid/core/app/analytics" "github.com/google/gapid/core/app/benchmark" "github.com/google/gapid/core/app/status" + "github.com/google/gapid/core/context/keys" "github.com/google/gapid/core/data/id" "github.com/google/gapid/core/log" "github.com/google/gapid/core/os/device" @@ -269,6 +270,27 @@ func (m *manager) execute( } ctx = log.V{"replay target ABI": replayABI}.Bind(ctx) + // We may or may not actually need the initial payload, but kick it off now + // so we have the maximum chance of it being ready when we need it. + ipl := InitialPayloadResolvable{ + CaptureID: NewID(captureID), + ApiID: NewID(id.ID(generator.(api.API).ID())), + DeviceID: NewID(d.Instance().ID.ID()), + } + + newCtx := keys.Clone(context.Background(), ctx) + go func() { + // kick the initial payload build. we don't know if we actually + // need it yet, but want to kick it off as early as possible, + // even before we're connected. + + // errors here are OK -- we'll pick them up later when we force completion + cctx := status.PutTask(newCtx, nil) + cctx = status.StartBackground(cctx, "Precaching initial payload") + defer status.Finish(cctx) + _, _ = database.Build(cctx, &ipl) + }() + conn, err := m.connect(ctx, d, replayABI) if err != nil { return log.Err(ctx, err, "Failed to connect to device") @@ -278,31 +300,24 @@ func (m *manager) execute( var depBuilder *builder.Builder var depState *api.GlobalState if !forceNonSplitReplay { - if g, ok := generator.(SplitGenerator); ok { - a, ok := g.(api.API) - if ok { - ipl := InitialPayloadResolvable{ - CaptureID: NewID(captureID), - ApiID: NewID(id.ID(a.ID())), - DeviceID: NewID(d.Instance().ID.ID()), - } - ipr, err := database.Build(ctx, &ipl) - if err != nil { - return err - } - i, ok := ipr.(InitialPayloadResult) - if !ok { - return log.Err(ctx, nil, "Invalid Initial Payload") - } - - depID = i.prerunID - depBuilder = i.oldBuilder - depState = i.oldState - - err = m.PrewarmReplay(ctx, conn, i.prerunID, i.cleanupID) - if err != nil { - return log.Err(ctx, err, "Replay returned error") - } + if _, ok := generator.(SplitGenerator); ok { + // Force initial payload to be finished building + ipr, err := database.Build(ctx, &ipl) + if err != nil { + return err + } + i, ok := ipr.(InitialPayloadResult) + if !ok { + return log.Err(ctx, nil, "Invalid Initial Payload") + } + + depID = i.prerunID + depBuilder = i.oldBuilder + depState = i.oldState + + err = m.PrewarmReplay(ctx, conn, i.prerunID, i.cleanupID) + if err != nil { + return log.Err(ctx, err, "Replay returned error") } } } From 4b9285bd570437f78d342328271e877f3f0e481d Mon Sep 17 00:00:00 2001 From: stellama0208 <49965489+stellama0208@users.noreply.github.com> Date: Tue, 14 Apr 2020 10:18:34 -0700 Subject: [PATCH 0225/1218] Implement draw command grouping. (#207) - Bug: b/143731054. --- gapis/api/vulkan/vulkan.go | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index e84fd39d8d..58df9d822a 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -17,6 +17,7 @@ package vulkan import ( "context" "fmt" + "strings" "github.com/google/gapid/core/app/status" "github.com/google/gapid/core/log" @@ -123,6 +124,7 @@ type MarkerType int const ( DebugMarker = iota RenderPassMarker + DrawGroupMarker ) type markerInfo struct { @@ -168,18 +170,31 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap markerStack = markerStack[0 : len(markerStack)-1] } } + + popMarkerWithNewGroupName := func(ty MarkerType, id uint64, name string) { + if len(markerStack) > 0 { + marker := markerStack[len(markerStack)-1] + d.SubCommandMarkerGroups.NewMarkerGroup(marker.parent, name, marker.start, id+1) + markerStack = markerStack[0 : len(markerStack)-1] + } + } + var walkCommandBuffer func(cb CommandBufferObjectʳ, idx api.SubCmdIdx, id api.CmdID, order uint64) ([]sync.SubcommandReference, []api.SubCmdIdx) walkCommandBuffer = func(cb CommandBufferObjectʳ, idx api.SubCmdIdx, id api.CmdID, order uint64) ([]sync.SubcommandReference, []api.SubCmdIdx) { refs := make([]sync.SubcommandReference, 0) subgroups := make([]api.SubCmdIdx, 0) lastSubpass := 0 nCommands := uint64(cb.CommandReferences().Len()) + canStartDrawGrouping := true + for i := 0; i < cb.CommandReferences().Len(); i++ { initialCommands, ok := st.initialCommands[cb.VulkanHandle()] var ref sync.SubcommandReference if !ok { continue } + + // Update values in sync data. nv := append(api.SubCmdIdx{}, idx...) nv = append(nv, uint64(i)) generatingId := initialCommands[i] @@ -201,6 +216,7 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap d.SubcommandLookup.SetValue(nv, ref) refs = append(refs, ref) + // Handle extra command buffer reference, render pass grouping and debug marker grouping. switch args := GetCommandArgs(ctx, cb.CommandReferences().Get(uint32(i)), st).(type) { case VkCmdExecuteCommandsArgsʳ: d.SubcommandNames.SetValue(nv, "") // Clear the group name so that the original commnd is shown. @@ -291,7 +307,38 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap case VkCmdDebugMarkerEndEXTArgsʳ: popMarker(DebugMarker, uint64(i), nCommands) } + + // Handle draw commands grouping. + cmdName := cb.CommandReferences().Get(uint32(i)).Type().String() + isDrawCmd := strings.HasPrefix(cmdName, "cmd_vkCmdDraw") || strings.HasPrefix(cmdName, "cmd_vkCmdDispatch") + isStateSettingCmd := (strings.HasPrefix(cmdName, "cmd_vkCmdSet") || strings.HasPrefix(cmdName, "cmd_vkCmdBind")) && + !strings.HasPrefix(cmdName, "cmd_vkCmdSetEvent") + if isStateSettingCmd && canStartDrawGrouping { + markerStack = append(markerStack, + &markerInfo{ + name: "State Setting Group", + ty: DrawGroupMarker, + start: uint64(i), + end: uint64(i), + parent: append(api.SubCmdIdx{}, idx...), + }) + canStartDrawGrouping = false + } else if isDrawCmd { + // When a group is complete with state setting cmds following a draw command, override the group name. + groupName := cmdName + if strings.HasPrefix(groupName, "cmd_vkCmd") { // Remove "cmd_vkCmd". + groupName = groupName[9:len(groupName)] + } + popMarkerWithNewGroupName(DrawGroupMarker, uint64(i), groupName) + canStartDrawGrouping = true + } else if !isStateSettingCmd && !isDrawCmd && !canStartDrawGrouping { + // Handle an edge case where a group of state setting commands are + // followed by something other than a drawing command. + popMarker(DrawGroupMarker, uint64(i), nCommands) + canStartDrawGrouping = true + } } + for i := len(markerStack) - 1; i >= 0; i-- { if len(markerStack[i].parent) < len(idx) { break From b0d4aa697c12f8c3cc683fec85fede6d9765f3d4 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Mon, 13 Apr 2020 16:49:08 -0700 Subject: [PATCH 0226/1218] Correctly listen to follower events in GraphicsTraceView. Remove the listener when the widget is disposed, so we don't get events after the tabs are gone. --- .../com/google/gapid/GraphicsTraceView.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/gapic/src/main/com/google/gapid/GraphicsTraceView.java b/gapic/src/main/com/google/gapid/GraphicsTraceView.java index 0ff5a4db93..633a3e40c3 100644 --- a/gapic/src/main/com/google/gapid/GraphicsTraceView.java +++ b/gapic/src/main/com/google/gapid/GraphicsTraceView.java @@ -29,13 +29,13 @@ import com.google.gapid.proto.service.Service.ClientAction; import com.google.gapid.proto.service.path.Path; import com.google.gapid.views.CommandTree; -import com.google.gapid.views.ReplayDeviceSelector; import com.google.gapid.views.FramebufferView; import com.google.gapid.views.GeometryView; import com.google.gapid.views.LogView; import com.google.gapid.views.MemoryView; import com.google.gapid.views.PipelineView; import com.google.gapid.views.ProfileView; +import com.google.gapid.views.ReplayDeviceSelector; import com.google.gapid.views.ReportView; import com.google.gapid.views.ShaderView; import com.google.gapid.views.StateView; @@ -67,12 +67,12 @@ /** * Main view shown when a graphics trace is loaded. */ -public class GraphicsTraceView extends Composite implements MainWindow.MainView { +public class GraphicsTraceView extends Composite implements MainWindow.MainView, Follower.Listener { private final Models models; private final Widgets widgets; protected final Set hiddenTabs; - protected TabArea tabs; + protected final TabArea tabs; public GraphicsTraceView(Composite parent, Models models, Widgets widgets) { super(parent, SWT.NONE); @@ -99,21 +99,9 @@ public TabArea.FolderInfo[] restore() { tabs.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - models.follower.addListener(new Follower.Listener() { - @Override - public void onMemoryFollowed(Path.Memory path) { - tabs.showTab(MainTab.Type.Memory); - } - - @Override - public void onStateFollowed(Path.Any path) { - tabs.showTab(MainTab.Type.ApiState); - } - - @Override - public void onTextureFollowed(Service.Resource resource) { - tabs.showTab(MainTab.Type.Textures); - } + models.follower.addListener(this); + addListener(SWT.Dispose, e -> { + models.follower.removeListener(this); }); } @@ -135,6 +123,21 @@ public void updateViewMenu(MenuManager manager) { manager.add(createViewTabsMenu()); } + @Override + public void onMemoryFollowed(Path.Memory path) { + tabs.showTab(MainTab.Type.Memory); + } + + @Override + public void onStateFollowed(Path.Any path) { + tabs.showTab(MainTab.Type.ApiState); + } + + @Override + public void onTextureFollowed(Service.Resource resource) { + tabs.showTab(MainTab.Type.Textures); + } + private MenuManager createViewTabsMenu() { MenuManager manager = new MenuManager("&Tabs"); for (MainTab.Type type : MainTab.Type.values()) { From aec2fd6021e93cb801476520d6e7166f372a13c4 Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Tue, 14 Apr 2020 19:21:20 +0100 Subject: [PATCH 0227/1218] Create artifacts for Swarming test results (#204) These artifacts are meant to be used for nightly builds to create a table of results. Also fix enumeration of devices in trigger, and a few minor swarming-related issues. --- kokoro/linux/build.sh | 10 +++++++- kokoro/linux/nightly.cfg | 9 +++++++ test/swarming/README.md | 4 ++-- test/swarming/collect.sh | 48 ++++++++++++++++++++++++++++++------- test/swarming/manual-run.sh | 5 +++- test/swarming/trigger.sh | 23 ++++++++++++------ 6 files changed, 79 insertions(+), 20 deletions(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index 2d460eba71..efec0639e5 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -170,10 +170,18 @@ xvfb-run -e xvfb.log -a bazel-bin/pkg/gapit video -gapir-nofallback -type sxs -f ## Collect swarming test results ## +# This directory name must match the artifact regex in nightly.cfg +SWARMING_RESULT_DIR=${KOKORO_ARTIFACTS_DIR}/swarming_results +mkdir -p ${SWARMING_RESULT_DIR} +export SWARMING_RESULT_FILE=${SWARMING_RESULT_DIR}/results.txt + +# Store some build info +echo "commit ${KOKORO_GIT_COMMIT}" > ${SWARMING_RESULT_DIR}/build_info.txt + pushd ${SWARMING_DIR} SWARMING_FAILURE=0 -for TEST_NAME in ${SWARMING_TRIGGERED_DIR}/*.json ; do +for TEST_NAME in ${SWARMING_TRIGGERED_DIR}/*/*.json ; do set +e ./collect.sh ${TEST_NAME} > `basename ${TEST_NAME} .json`.collect.log EXIT_CODE=$? diff --git a/kokoro/linux/nightly.cfg b/kokoro/linux/nightly.cfg index 6061509e52..332a777914 100644 --- a/kokoro/linux/nightly.cfg +++ b/kokoro/linux/nightly.cfg @@ -14,6 +14,7 @@ # Nightly build configuration. gfile_resources: "/x20/teams/android-graphics-tools/agi/kokoro/swarming_nightly" +gfile_resources: "/x20/teams/android-graphics-tools/agi/kokoro/nightly_results" env_vars { key: "SWARMING_X20_TEST_DIR" @@ -22,3 +23,11 @@ env_vars { # Nightly Swarming tests take hours to complete. timeout_mins: 480 + +# Output Swarming results as artifacts +action { + define_artifacts { + regex: "swarming_results/*.txt" + strip_prefix: "swarming_results/" + } +} diff --git a/test/swarming/README.md b/test/swarming/README.md index 1c19791207..e32a3be22d 100644 --- a/test/swarming/README.md +++ b/test/swarming/README.md @@ -75,8 +75,8 @@ Moreover, some `SWARMING_*` environment variables can be overriden on a test-specific level. Some interesting ones: ``` -# Space-separated list of devices to run on -SWARMING_DEVICES=flame +# Array of devices to run on (bash-array format, e.g.: '(dev1 dev2 dev3)' ) +SWARMING_DEVICES=(flame) # Priority: lower value is higher priority SWARMING_PRIORITY=100 # Timeout: maximum number of seconds for the task to terminate diff --git a/test/swarming/collect.sh b/test/swarming/collect.sh index 70f3b98898..35e6c6e565 100755 --- a/test/swarming/collect.sh +++ b/test/swarming/collect.sh @@ -37,18 +37,48 @@ SWARMING_SERVER=https://chrome-swarming.appspot.com # if the task has expired (it was never scheduled). Allow for non-zero return # code, and manually check the task status afterward set +e -${LUCI_CLIENT_ROOT}/swarming.py collect ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --json ${SWARMING_TEST_JSON} --task-summary-json ${SWARMING_SUMMARY} +${LUCI_CLIENT_ROOT}/swarming.py collect ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --task-summary-json=${SWARMING_SUMMARY} --task-output-stdout=none --json ${SWARMING_TEST_JSON} SWARMING_COLLECT_EXIT_CODE=$? set -e -# Ignore failures that are not due to the test itself -if [ "${SWARMING_COLLECT_EXIT_CODE}" != "0" ] ; then - if grep '"state": "EXPIRED"' ${SUMMARY} > /dev/null ; then - echo "Swarming test was never scheduled, ignoring it" - elif grep '"internal_failure": true' ${SUMMARY} > /dev/null ; then - echo "Swarming internal failure, ignore the swarming test" +# Scan summary to set test status. +SWARMING_TEST_STATUS="fail" +if [ "${SWARMING_COLLECT_EXIT_CODE}" == "0" ] ; then + SWARMING_TEST_STATUS="pass" +else + if grep '"state": "EXPIRED"' ${SWARMING_SUMMARY} > /dev/null ; then + SWARMING_TEST_STATUS="expired" + elif grep '"internal_failure": true' ${SWARMING_SUMMARY} > /dev/null ; then + SWARMING_TEST_STATUS="internal_failure" + elif grep '"state": "TIMED_OUT"' ${SWARMING_SUMMARY} > /dev/null ; then + SWARMING_TEST_STATUS="timeout" else - echo "Swarming test failed" - exit 1 + SWARMING_TEST_STATUS="fail" fi fi + +# Append result to result file. Best would be to use JSON, but as we add one +# result at a time, we do not know here if we are the first or last result, so +# we would need some convoluted way to add the JSON list begin/end markers. As a +# workaround, we stick to CSV. +# +# Each line is exactly: device,test_name,task_id,test_status +if [ ! -z "${SWARMING_RESULT_FILE}" ] ; then + device=`grep '"device_type:' ${SWARMING_SUMMARY} | sed -e 's/^.*"device_type://' -e 's/",.*$//'` + test_name=`basename ${SWARMING_TEST_JSON} .json` + task_id=`grep '"run_id":' ${SWARMING_SUMMARY} | sed -e 's/^.*"run_id": "//' -e 's/",.$//'` + echo "${device},${test_name},${task_id},${SWARMING_TEST_STATUS}" >> ${SWARMING_RESULT_FILE} +fi + +# Collect.sh returns an error upon failure except for expired and internal +# failures which are silenced at this level, such that a PR build with +# e.g. expired Swarming tests will not be reported as failing. +echo "Test status: ${SWARMING_TEST_STATUS}" +case "${SWARMING_TEST_STATUS}" in + "pass" | "expired" | "internal_failure" ) + exit 0 + ;; + * ) + exit 1 + ;; +esac diff --git a/test/swarming/manual-run.sh b/test/swarming/manual-run.sh index 8f83fbaf1b..92ab53376c 100755 --- a/test/swarming/manual-run.sh +++ b/test/swarming/manual-run.sh @@ -30,9 +30,12 @@ fi export SWARMING_AUTH_FLAG="" export SWARMING_BUILD_INFO="Manual" export SWARMING_TRIGGERED_DIR="triggered-manual" +export SWARMING_RESULT_FILE="${SWARMING_TRIGGERED_DIR}/results.txt" rm -rf ${SWARMING_TRIGGERED_DIR} mkdir -p ${SWARMING_TRIGGERED_DIR} ./trigger.sh ${SWARMING_TEST_DIR} -./collect.sh ${SWARMING_TRIGGERED_DIR}/*.json +for t in ${SWARMING_TRIGGERED_DIR}/*/*.json; do + ./collect.sh ${t} +done diff --git a/test/swarming/trigger.sh b/test/swarming/trigger.sh index 10e8344e87..fb8ed1287b 100755 --- a/test/swarming/trigger.sh +++ b/test/swarming/trigger.sh @@ -49,8 +49,8 @@ SWARMING_TASK_NAME="${SWARMING_BUILD_INFO}_${SWARMING_TEST_NAME}" SWARMING_ISOLATE_SERVER=https://chrome-isolated.appspot.com SWARMING_SERVER=https://chrome-swarming.appspot.com SWARMING_POOL=SkiaInternal -# String with space-separated device names -SWARMING_DEVICES="flame" +# Bash-array of device names: (dev1 dev2 dev3) +SWARMING_DEVICES=(flame) # Priority: lower value is higher priority, defaults to 200: PR short test tasks # should be of higher priority than the default SWARMING_PRIORITY=100 @@ -63,14 +63,22 @@ SWARMING_EXPIRATION=600 # we don't want to 'source' the test 'env.sh' as this could lead to code # injection. Instead, we grep all relevant environment variables that may be # overriden. -for envvar in SWARMING_DEVICES SWARMING_PRIORITY SWARMING_TIMEOUT SWARMING_EXPIRATION ; do +for envvar in SWARMING_PRIORITY SWARMING_TIMEOUT SWARMING_EXPIRATION ; do value=`grep ${envvar} ${SWARMING_TEST_DIR}/env.sh | sed -e 's/^.*=//'` if [ ! -z "${value}" ] ; then declare ${envvar}=${value} fi done -# Generate config for isolate +# Special case for SWARMING_DEVICES, which is a bash array, we must handle the +# parenthesis accordingly +# This sed line transforms "SWARMING_DEVICES={dev1 dev2)" into "dev1 dev2" +devices=`grep SWARMING_DEVICES ${SWARMING_TEST_DIR}/env.sh |sed -e 's/^.*=[(]//' -e 's/)$//'` +if [ ! -z "${devices}" ] ; then + declare SWARMING_DEVICES=(${devices}) +fi + +# generate config for isolate cat << EOF > ${SWARMING_TEST_NAME}.isolate { 'variables': { @@ -95,7 +103,8 @@ ${LUCI_CLIENT_ROOT}/isolate.py archive ${SWARMING_AUTH_FLAG} --isolate-server ${ SWARMING_ISOLATED_SHA=`sha1sum ${SWARMING_TEST_NAME}.isolated | awk '{ print $1 }'` # Trigger Swarming task -for DEV in ${SWARMING_DEVICES} ; do - SWARMING_TASK_JSON=${SWARMING_TRIGGERED_DIR}/${SWARMING_TEST_NAME}.${DEV}.json - ${LUCI_CLIENT_ROOT}/swarming.py trigger ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --isolate-server ${SWARMING_ISOLATE_SERVER} --isolated ${SWARMING_ISOLATED_SHA} --task-name ${SWARMING_TASK_NAME} --dump-json ${SWARMING_TASK_JSON} --dimension pool ${SWARMING_POOL} --dimension device_type ${SWARMING_DEVICES} --priority=${SWARMING_PRIORITY} --expiration=${SWARMING_EXPIRATION} --hard-timeout=${SWARMING_TIMEOUT} +for DEV in ${SWARMING_DEVICES[@]} ; do + mkdir -p ${SWARMING_TRIGGERED_DIR}/${DEV} + SWARMING_TASK_JSON=${SWARMING_TRIGGERED_DIR}/${DEV}/${SWARMING_TEST_NAME}.json + ${LUCI_CLIENT_ROOT}/swarming.py trigger ${SWARMING_AUTH_FLAG} --swarming ${SWARMING_SERVER} --isolate-server ${SWARMING_ISOLATE_SERVER} --isolated ${SWARMING_ISOLATED_SHA} --task-name ${SWARMING_TASK_NAME} --dump-json ${SWARMING_TASK_JSON} --dimension pool ${SWARMING_POOL} --dimension device_type ${DEV} --priority=${SWARMING_PRIORITY} --expiration=${SWARMING_EXPIRATION} --hard-timeout=${SWARMING_TIMEOUT} done From ee37c8663c19bec31d9dc7a59910bdd293b8520b Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 14 Apr 2020 16:24:37 -0700 Subject: [PATCH 0228/1218] grouping: Consider vkCmdPushConstants to be a state setting command --- gapis/api/vulkan/vulkan.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gapis/api/vulkan/vulkan.go b/gapis/api/vulkan/vulkan.go index 58df9d822a..6a4f063616 100644 --- a/gapis/api/vulkan/vulkan.go +++ b/gapis/api/vulkan/vulkan.go @@ -311,8 +311,8 @@ func (API) ResolveSynchronization(ctx context.Context, d *sync.Data, c *path.Cap // Handle draw commands grouping. cmdName := cb.CommandReferences().Get(uint32(i)).Type().String() isDrawCmd := strings.HasPrefix(cmdName, "cmd_vkCmdDraw") || strings.HasPrefix(cmdName, "cmd_vkCmdDispatch") - isStateSettingCmd := (strings.HasPrefix(cmdName, "cmd_vkCmdSet") || strings.HasPrefix(cmdName, "cmd_vkCmdBind")) && - !strings.HasPrefix(cmdName, "cmd_vkCmdSetEvent") + isStateSettingCmd := (strings.HasPrefix(cmdName, "cmd_vkCmdSet") || strings.HasPrefix(cmdName, "cmd_vkCmdPush") || + strings.HasPrefix(cmdName, "cmd_vkCmdBind")) && !strings.HasPrefix(cmdName, "cmd_vkCmdSetEvent") if isStateSettingCmd && canStartDrawGrouping { markerStack = append(markerStack, &markerInfo{ From 24cfc39d9588f1af81c219f3731db7b02121171c Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Thu, 16 Apr 2020 18:20:13 +0100 Subject: [PATCH 0229/1218] Add DeviceDialog to select replay device (#192) When zero or more than one replay devices are available for a Graphics trace, ask the user to select a replay device via a dialog. This replaces ReplayDeviceSelector. models.devices.loadReplayDevice() now returns an empty list (and not null) when the replay device loading succeeded but did return an empty list. This enables to monitor when the replay devices have been loaded (before, replayDevices was null if either devices were not loaded yet, or there was no replay devices available). --- .../com/google/gapid/GraphicsTraceView.java | 7 +- .../main/com/google/gapid/models/Devices.java | 13 +- .../main/com/google/gapid/util/Messages.java | 6 + .../com/google/gapid/views/DeviceDialog.java | 332 ++++++++++++++++++ .../gapid/views/ReplayDeviceSelector.java | 91 ----- .../com/google/gapid/views/TracerDialog.java | 3 +- .../main/com/google/gapid/widgets/Theme.java | 2 + 7 files changed, 353 insertions(+), 101 deletions(-) create mode 100644 gapic/src/main/com/google/gapid/views/DeviceDialog.java delete mode 100644 gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java diff --git a/gapic/src/main/com/google/gapid/GraphicsTraceView.java b/gapic/src/main/com/google/gapid/GraphicsTraceView.java index 633a3e40c3..62fc014bf9 100644 --- a/gapic/src/main/com/google/gapid/GraphicsTraceView.java +++ b/gapic/src/main/com/google/gapid/GraphicsTraceView.java @@ -29,13 +29,13 @@ import com.google.gapid.proto.service.Service.ClientAction; import com.google.gapid.proto.service.path.Path; import com.google.gapid.views.CommandTree; +import com.google.gapid.views.DeviceDialog; import com.google.gapid.views.FramebufferView; import com.google.gapid.views.GeometryView; import com.google.gapid.views.LogView; import com.google.gapid.views.MemoryView; import com.google.gapid.views.PipelineView; import com.google.gapid.views.ProfileView; -import com.google.gapid.views.ReplayDeviceSelector; import com.google.gapid.views.ReportView; import com.google.gapid.views.ShaderView; import com.google.gapid.views.StateView; @@ -80,10 +80,9 @@ public GraphicsTraceView(Composite parent, Models models, Widgets widgets) { this.widgets = widgets; this.hiddenTabs = getHiddenTabs(models.settings); - setLayout(new GridLayout(1, false)); + new DeviceDialog(this, models, widgets); - new ReplayDeviceSelector(this, models) - .setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + setLayout(new GridLayout(1, false)); tabs = new TabArea(this, models.analytics, widgets.theme, new Persistance() { @Override diff --git a/gapic/src/main/com/google/gapid/models/Devices.java b/gapic/src/main/com/google/gapid/models/Devices.java index a297fa7885..2465ca70f2 100644 --- a/gapic/src/main/com/google/gapid/models/Devices.java +++ b/gapic/src/main/com/google/gapid/models/Devices.java @@ -76,7 +76,9 @@ public Devices(Shell shell, Analytics analytics, Client client, Capture capture, capture.addListener(new Capture.Listener() { @Override public void onCaptureLoadingStart(boolean maintainState) { - resetReplayDevice(); + if (!maintainState) { + resetReplayDevice(); + } } @Override @@ -93,7 +95,7 @@ protected void resetReplayDevice() { selectedReplayDevice = null; } - protected void loadReplayDevices(Path.Capture capturePath) { + public void loadReplayDevices(Path.Capture capturePath) { rpcController.start().listen(MoreFutures.transformAsync(client.getDevicesForReplay(capturePath), devs -> Futures.allAsList(devs.stream() .map(dev -> client.get(Paths.device(dev), dev)) @@ -105,7 +107,7 @@ protected ResultOrError, Void> onRpcThread(Result devs = result.get().stream() .map(v -> v.getDevice()) .collect(toList()); - return devs.isEmpty() ? error(null) : success(devs); + return success(devs); } catch (RpcException | ExecutionException e) { analytics.reportException(e); throttleLogRpcError(LOG, "LoadData error", e); @@ -127,7 +129,6 @@ protected void onUiThreadError(Void error) { protected void updateReplayDevices(List devs) { replayDevices = devs; - selectedReplayDevice = (devs == null) ? null : devs.get(0); listeners.fire().onReplayDevicesLoaded(); } @@ -205,6 +206,10 @@ public boolean isLoaded() { return devices != null; } + public boolean isReplayDevicesLoaded() { + return replayDevices != null; + } + public List getAllDevices() { return (devices == null) ? null : devices.stream().map(info -> info.device).collect(toList()); diff --git a/gapic/src/main/com/google/gapid/util/Messages.java b/gapic/src/main/com/google/gapid/util/Messages.java index c9712adbd9..17929bd747 100644 --- a/gapic/src/main/com/google/gapid/util/Messages.java +++ b/gapic/src/main/com/google/gapid/util/Messages.java @@ -87,4 +87,10 @@ public interface Messages { public static final String KEYBOARD_MOUSE_HELP_TITLE = "Keyboard/Mouse Shortcut Help"; public static final String PROFILE_NO_SLICES = "GPU Profiling is not supported on this device or for this capture"; + public static final String SELECT_DEVICE_TITLE = + "Select Replay Device"; + public static final String SELECT_DEVICE_NO_COMPATIBLE_FOUND = + "No compatible replay device found. Please plug in a compatible device and refresh the list."; + public static final String VALIDATION_FAILED_LANDING_PAGE = "Learn about device compatibility"; + } diff --git a/gapic/src/main/com/google/gapid/views/DeviceDialog.java b/gapic/src/main/com/google/gapid/views/DeviceDialog.java new file mode 100644 index 0000000000..b03f93bf7a --- /dev/null +++ b/gapic/src/main/com/google/gapid/views/DeviceDialog.java @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2020 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gapid.views; + +import static com.google.gapid.util.Logging.throttleLogRpcError; +import static com.google.gapid.util.MoreFutures.logFailure; +import static com.google.gapid.widgets.Widgets.createDropDownViewer; +import static com.google.gapid.widgets.Widgets.createGroup; +import static com.google.gapid.widgets.Widgets.createLabel; +import static com.google.gapid.widgets.Widgets.createLink; +import static com.google.gapid.widgets.Widgets.scheduleIfNotDisposed; +import static com.google.gapid.widgets.Widgets.withIndents; +import static com.google.gapid.widgets.Widgets.withLayoutData; +import static java.util.logging.Level.WARNING; + +import com.google.gapid.models.Capture; +import com.google.gapid.models.Devices; +import com.google.gapid.models.Devices.DeviceCaptureInfo; +import com.google.gapid.models.Devices.DeviceValidationResult; +import com.google.gapid.models.Models; +import com.google.gapid.proto.device.Device; +import com.google.gapid.rpc.Rpc; +import com.google.gapid.rpc.RpcException; +import com.google.gapid.rpc.SingleInFlight; +import com.google.gapid.rpc.UiErrorCallback; +import com.google.gapid.util.Loadable; +import com.google.gapid.util.Messages; +import com.google.gapid.util.Paths; +import com.google.gapid.util.Scheduler; +import com.google.gapid.util.URLs; +import com.google.gapid.widgets.DialogBase; +import com.google.gapid.widgets.LoadingIndicator; +import com.google.gapid.widgets.Widgets; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.program.Program; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * View responsible to show a replay device selection dialog when need be. + */ +public class DeviceDialog implements Devices.Listener, Capture.Listener { + protected static final Logger LOG = Logger.getLogger(DeviceDialog.class.getName()); + + private final Models models; + private final Widgets widgets; + private final Composite parent; + protected SelectReplayDeviceDialog dialog = null; + + public DeviceDialog(Composite parent, Models models, Widgets widgets) { + this.models = models; + this.widgets = widgets; + this.parent = parent; + + models.devices.addListener(this); + models.capture.addListener(this); + parent.addListener(SWT.Dispose, e -> { + models.devices.removeListener(this); + models.capture.removeListener(this); + if (dialog != null && dialog.getShell() != null) { + dialog.close(); + } + }); + } + + @Override + public void onReplayDevicesLoaded() { + selectReplayDevice(); + } + + @Override + public void onCaptureLoaded(Loadable.Message error) { + selectReplayDevice(); + } + + protected void selectReplayDevice() { + + // If the dialog has been closed, remove the reference to it. + if (dialog != null && dialog.getShell() == null) { + dialog = null; + } + + if (dialog != null) { + // Dialog is already open, just refresh it + dialog.refresh(); + return; + } + + if (models.capture.isGraphics() && models.devices.isReplayDevicesLoaded() && !models.devices.hasReplayDevice()) { + // Show dialog unless there is a single compatible and validated replay + // device available, in which case it is auto-selected + boolean skipDialog = false; + Device.Instance device = null; + if (models.devices.getReplayDevices() != null + && models.devices.getReplayDevices().size() == 1) { + device = models.devices.getReplayDevices().get(0); + DeviceValidationResult result = models.devices.getValidationStatus( + new DeviceCaptureInfo(Paths.device(device.getID()), device, null, null)); + skipDialog = result.passed || result.skipped; + } + + if (skipDialog) { + models.devices.selectReplayDevice(device); + } else { + dialog = new SelectReplayDeviceDialog(parent.getShell(), models, widgets); + scheduleIfNotDisposed(parent, () -> dialog.open()); + } + } + } + + /** + * Dialog to select a replay device. + */ + static private class SelectReplayDeviceDialog extends DialogBase { + + private final Models models; + private final Widgets widgets; + + private Label noCompatibleDeviceFound; + private ComboViewer deviceCombo; + private LoadingIndicator.Widget deviceLoader; + private LoadingIndicator.Widget validationStatusLoader; + private Link validationStatusText; + private boolean validationPassed; + + private final SingleInFlight rpcController = new SingleInFlight(); + + public SelectReplayDeviceDialog(Shell shell, Models models, Widgets widgets) { + super(shell, widgets.theme); + this.models = models; + this.widgets = widgets; + validationPassed = false; + } + + @Override + public String getTitle() { + return Messages.SELECT_DEVICE_TITLE; + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite = (Composite) super.createDialogArea(parent); + + // Recap capture info + createLabel(composite, "Capture name: " + models.capture.getName()); + createLabel(composite, + "Capture device: " + Devices.getLabel(models.capture.getData().capture.getDevice())); + + // Warning when no compatible device found + noCompatibleDeviceFound = createLabel(composite, Messages.SELECT_DEVICE_NO_COMPATIBLE_FOUND); + noCompatibleDeviceFound.setForeground(theme.deviceNotFound()); + + // Mirror the device combo from TracerDialog + Group mainGroup = + withLayoutData(createGroup(composite, "Select replay device", new GridLayout(3, false)), + new GridData(GridData.FILL_HORIZONTAL)); + createLabel(mainGroup, "Device:"); + deviceCombo = createDropDownViewer(mainGroup); + deviceCombo.setContentProvider(ArrayContentProvider.getInstance()); + deviceCombo.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + deviceCombo.setLabelProvider(new LabelProvider() { + @Override + public String getText(Object element) { + return Devices.getLabel(((Device.Instance) element)); + } + }); + + deviceLoader = widgets.loading.createWidgetWithRefresh(mainGroup); + deviceLoader + .setLayoutData(withIndents(new GridData(SWT.RIGHT, SWT.CENTER, false, false), 5, 0)); + // TODO: Make this a true button to allow keyboard use. + deviceLoader.addListener(SWT.MouseDown, e -> { + deviceLoader.startLoading(); + // By waiting a tiny bit, the icon will change to the loading indicator, giving the user + // feedback that something is happening, in case the refresh is really quick. + logFailure(LOG, + Scheduler.EXECUTOR.schedule( + () -> models.devices.loadReplayDevices(models.capture.getData().path), 300, + TimeUnit.MILLISECONDS)); + }); + + validationStatusLoader = widgets.loading.createWidgetWithImage(mainGroup, + widgets.theme.check(), widgets.theme.error()); + validationStatusLoader + .setLayoutData(withIndents(new GridData(SWT.LEFT, SWT.BOTTOM, false, false), 0, 0)); + validationStatusText = createLink(mainGroup, "", e -> { + Program.launch(URLs.DEVICE_COMPATIBILITY_URL); + }); + validationStatusText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + + deviceCombo.getCombo().addListener(SWT.Selection, e -> { + runValidationCheck(getSelectedDevice()); + }); + + refresh(); + return composite; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + Button openTrace = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + openTrace.setEnabled(validationPassed); + } + + @Override + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + models.devices.selectReplayDevice(getSelectedDevice()); + } + super.buttonPressed(buttonId); + } + + protected void refresh() { + boolean noReplayDevices = + models.devices.getReplayDevices() == null || models.devices.getReplayDevices().isEmpty(); + + noCompatibleDeviceFound.setVisible(noReplayDevices); + noCompatibleDeviceFound.requestLayout(); + + deviceCombo.setInput(models.devices.getReplayDevices()); + if (noReplayDevices) { + deviceCombo.setSelection(null); + } else { + deviceCombo.setSelection(new StructuredSelection(models.devices.getReplayDevices().get(0))); + } + deviceCombo.getCombo().notifyListeners(SWT.Selection, new Event()); + deviceLoader.stopLoading(); + } + + private Device.Instance getSelectedDevice() { + IStructuredSelection sel = deviceCombo.getStructuredSelection(); + return sel.isEmpty() ? null : (Device.Instance) sel.getFirstElement(); + } + + private void runValidationCheck(Device.Instance deviceInstance) { + if (deviceInstance == null) { + validationStatusLoader.setVisible(false); + validationStatusText.setVisible(false); + return; + } + validationStatusLoader.setVisible(true); + validationStatusText.setVisible(true); + // We need a DeviceCaptureInfo to do validation. + DeviceCaptureInfo dev = + new DeviceCaptureInfo(Paths.device(deviceInstance.getID()), deviceInstance, null, null); + setValidationStatus(models.devices.getValidationStatus(dev)); + if (!models.devices.getValidationStatus(dev).passed) { + validationStatusLoader.startLoading(); + validationStatusText.setText("Device is being validated"); + rpcController.start().listen(models.devices.validateDevice(dev), + new UiErrorCallback( + validationStatusLoader, LOG) { + @Override + protected ResultOrError onRpcThread( + Rpc.Result response) + throws RpcException, ExecutionException { + try { + return success(response.get()); + } catch (RpcException | ExecutionException e) { + throttleLogRpcError(LOG, "LoadData error", e); + return error(null); + } + } + + @Override + protected void onUiThreadSuccess(DeviceValidationResult result) { + setValidationStatus(result); + } + + @Override + protected void onUiThreadError(DeviceValidationResult result) { + LOG.log(WARNING, "UI thread error while validating device"); + setValidationStatus(result); + } + }); + } + } + + protected void setValidationStatus(DeviceValidationResult result) { + if (result.skipped) { + validationStatusLoader.updateStatus(true); + validationStatusLoader.stopLoading(); + validationStatusText.setText("Validation skipped."); + validationPassed = true; + } else { + validationStatusLoader.updateStatus(result.passed); + validationStatusText.setText("Validation " + + (result.passed ? "Passed." : "Failed. " + Messages.VALIDATION_FAILED_LANDING_PAGE)); + validationStatusLoader.stopLoading(); + validationPassed = result.passed; + } + Button openTrace = getButton(IDialogConstants.OK_ID); + if (openTrace != null) { + openTrace.setEnabled(validationPassed); + } + } + + } + +} diff --git a/gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java b/gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java deleted file mode 100644 index ca6217932d..0000000000 --- a/gapic/src/main/com/google/gapid/views/ReplayDeviceSelector.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.gapid.views; - -import static com.google.gapid.widgets.Widgets.createDropDownViewer; -import static com.google.gapid.widgets.Widgets.createLabel; - -import com.google.gapid.models.Analytics.View; -import com.google.gapid.models.Devices; -import com.google.gapid.models.Models; -import com.google.gapid.proto.device.Device; -import com.google.gapid.proto.service.Service.ClientAction; - -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.ComboViewer; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.StructuredSelection; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; - -/** - * Shows a dropdown for the replay device selection. - */ -public class ReplayDeviceSelector extends Composite implements Devices.Listener { - private final Models models; - private final ComboViewer deviceCombo; - - public ReplayDeviceSelector(Composite parent, Models models) { - super(parent, SWT.NONE); - this.models = models; - - setLayout(new GridLayout(2, false)); - - createLabel(this, "Replay Device:"); - deviceCombo = createDropDownViewer(this); - deviceCombo.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); - deviceCombo.setContentProvider(ArrayContentProvider.getInstance()); - deviceCombo.setLabelProvider(new LabelProvider() { - @Override - public String getText(Object element) { - return Devices.getLabel((Device.Instance)element); - } - }); - - models.devices.addListener(this); - addListener(SWT.Dispose, e -> { - models.devices.removeListener(this); - }); - - deviceCombo.getCombo().addListener(SWT.Selection, e -> { - models.analytics.postInteraction(View.ReplayDeviceSelector, ClientAction.Select); - IStructuredSelection selection = deviceCombo.getStructuredSelection(); - if (!selection.isEmpty()) { - models.devices.selectReplayDevice((Device.Instance)selection.getFirstElement()); - } - }); - } - - @Override - public void onReplayDevicesLoaded() { - if (!models.devices.hasReplayDevice()) { - return; - } - - deviceCombo.setInput(models.devices.getReplayDevices()); - deviceCombo.refresh(); - - onReplayDeviceChanged(models.devices.getSelectedReplayDevice()); - } - - @Override - public void onReplayDeviceChanged(Device.Instance dev) { - deviceCombo.setSelection(new StructuredSelection(dev)); - } -} diff --git a/gapic/src/main/com/google/gapid/views/TracerDialog.java b/gapic/src/main/com/google/gapid/views/TracerDialog.java index 5392a27a32..06e8ef0e60 100644 --- a/gapic/src/main/com/google/gapid/views/TracerDialog.java +++ b/gapic/src/main/com/google/gapid/views/TracerDialog.java @@ -284,7 +284,6 @@ private static class TraceInput extends Composite { private static final String PERFETTO_LABEL = "Profile Config: "; private static final String EMPTY_APP_WITH_RENDER_STAGE = "Warning: Application needs to be specified for GPU profiling data."; - private static final String VALIDATION_FAILED_LANDING_PAGE = "Learn about device compatibility"; private final String date = TRACE_DATE_FORMAT.format(new Date()); @@ -657,7 +656,7 @@ protected void setValidationStatus(DeviceValidationResult result) { validationStatus = true; } else { validationStatusLoader.updateStatus(result.passed); - validationStatusText.setText("Validation " + (result.passed ? "Passed." : "Failed. " + VALIDATION_FAILED_LANDING_PAGE)); + validationStatusText.setText("Validation " + (result.passed ? "Passed." : "Failed. " + Messages.VALIDATION_FAILED_LANDING_PAGE)); validationStatusLoader.stopLoading(); validationStatus = result.passed; } diff --git a/gapic/src/main/com/google/gapid/widgets/Theme.java b/gapic/src/main/com/google/gapid/widgets/Theme.java index 7c2e647258..b50052ba5c 100644 --- a/gapic/src/main/com/google/gapid/widgets/Theme.java +++ b/gapic/src/main/com/google/gapid/widgets/Theme.java @@ -194,6 +194,8 @@ public interface Theme { @RGB(argb = 0xfff00000) public Color missingInput(); @RGB(argb = 0xf0000000) public Color filledInput(); + @RGB(argb = 0xfff00000) public Color deviceNotFound(); + @TextStyle(foreground = 0xa9a9a9) public Styler structureStyler(); @TextStyle(foreground = 0x0000ee) public Styler identifierStyler(); @TextStyle(bold = true) public Styler labelStyler(); From 857e8d7e29cff06dc73126b5a53235a9e1ced792 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 13:41:16 -0700 Subject: [PATCH 0230/1218] Don't query the device info in a different thread. --- core/os/device/deviceinfo/cc/query.cpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index 3a37c0979f..9ded3fe274 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -72,12 +72,16 @@ void deviceInstanceID(device::Instance* instance) { delete[] proto_data; } -void buildDeviceInstance(const query::Option& opt, device::Instance** out) { +} // anonymous namespace + +namespace query { + +device::Instance* getDeviceInstance(const Option& opt) { using namespace device; using namespace google::protobuf::io; if (!query::createContext()) { - return; + return nullptr; } // OS @@ -183,20 +187,6 @@ void buildDeviceInstance(const query::Option& opt, device::Instance** out) { query::destroyContext(); } - *out = instance; -} - -} // anonymous namespace - -namespace query { - -device::Instance* getDeviceInstance(const Option& opt) { - device::Instance* instance = nullptr; - - // buildDeviceInstance on a separate thread to avoid EGL screwing with the - // currently bound context. - std::thread thread(buildDeviceInstance, opt, &instance); - thread.join(); return instance; } From 4f17b7b1a26d32f146274f419ed74f19ec58f01f Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 13:42:53 -0700 Subject: [PATCH 0231/1218] Get rid of the conext.mError in device info. Pass in a std::string that queries can append the error to instead. --- .../os/device/deviceinfo/cc/android/query.cpp | 44 +++++++++---------- core/os/device/deviceinfo/cc/instance.cpp | 11 ++++- core/os/device/deviceinfo/cc/linux/query.cpp | 11 ++--- core/os/device/deviceinfo/cc/osx/query.mm | 13 ++---- core/os/device/deviceinfo/cc/query.cpp | 4 +- core/os/device/deviceinfo/cc/query.h | 9 ++-- .../os/device/deviceinfo/cc/windows/query.cpp | 9 ++-- gapii/cc/spy.cpp | 7 ++- 8 files changed, 52 insertions(+), 56 deletions(-) diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp index f92c084513..897d5ab137 100644 --- a/core/os/device/deviceinfo/cc/android/query.cpp +++ b/core/os/device/deviceinfo/cc/android/query.cpp @@ -130,7 +130,6 @@ void abiByName(const std::string name, device::ABI* abi) { namespace query { struct Context { - char mError[512]; EGLDisplay mDisplay; EGLSurface mSurface; EGLContext mContext; @@ -183,7 +182,7 @@ void destroyContext() { } } -bool createContext() { +bool createContext(std::string* errorMsg) { if (gContextRefCount++ > 0) { return true; } @@ -209,16 +208,15 @@ bool createContext() { #undef RESOLVE -#define CHECK(x) \ - x; \ - { \ - EGLint error = eglGetError(); \ - if (error != EGL_SUCCESS) { \ - snprintf(gContext.mError, sizeof(gContext.mError), \ - "EGL error: 0x%x when executing:\n " #x, error); \ - destroyContext(); \ - return false; \ - } \ +#define CHECK(x) \ + x; \ + { \ + EGLint error = eglGetError(); \ + if (error != EGL_SUCCESS) { \ + errorMsg->append("EGL error"); \ + destroyContext(); \ + return false; \ + } \ } CHECK(auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY)); @@ -283,16 +281,16 @@ bool createContext() { #undef CHECK -#define GET_PROP(name, trans) \ - do { \ - char _v[PROP_VALUE_MAX] = {0}; \ - if (__system_property_get(name, _v) == 0) { \ - snprintf(gContext.mError, sizeof(gContext.mError), \ - "Failed reading property %s", name); \ - destroyContext(); \ - return false; \ - } \ - trans; \ +#define GET_PROP(name, trans) \ + do { \ + char _v[PROP_VALUE_MAX] = {0}; \ + if (__system_property_get(name, _v) == 0) { \ + errorMsg->append("Failed reading property "); \ + errorMsg->append(name); \ + destroyContext(); \ + return false; \ + } \ + trans; \ } while (0) #define GET_STRING_PROP(n, t) GET_PROP(n, t = _v) @@ -462,8 +460,6 @@ bool createContext() { return true; } -const char* contextError() { return gContext.mError; } - bool hasGLorGLES() { return true; } int numABIs() { return gContext.mSupportedABIs.size(); } diff --git a/core/os/device/deviceinfo/cc/instance.cpp b/core/os/device/deviceinfo/cc/instance.cpp index 62393cb373..97340de8a1 100644 --- a/core/os/device/deviceinfo/cc/instance.cpp +++ b/core/os/device/deviceinfo/cc/instance.cpp @@ -17,6 +17,12 @@ #include "instance.h" #include "query.h" +namespace { + +std::string error; + +} // anonymous namespace + extern "C" { device_instance get_device_instance() { @@ -25,7 +31,8 @@ device_instance get_device_instance() { query::Option query_opt; query_opt.vulkan.set_query_layers_and_extensions(true) .set_query_physical_devices(true); - auto instance = query::getDeviceInstance(query_opt); + error.clear(); + auto instance = query::getDeviceInstance(query_opt, &error); if (!instance) { return out; } @@ -40,7 +47,7 @@ device_instance get_device_instance() { return out; } -const char* get_device_instance_error() { return query::contextError(); } +const char* get_device_instance_error() { return error.c_str(); } void free_device_instance(device_instance di) { delete[] di.data; } diff --git a/core/os/device/deviceinfo/cc/linux/query.cpp b/core/os/device/deviceinfo/cc/linux/query.cpp index dd6c67f5e1..1a6a290b68 100644 --- a/core/os/device/deviceinfo/cc/linux/query.cpp +++ b/core/os/device/deviceinfo/cc/linux/query.cpp @@ -39,7 +39,6 @@ namespace query { struct Context { - char mError[512]; Display* mDisplay; GLXFBConfig* mFBConfigs; GLXContext mGlCtx; @@ -225,7 +224,7 @@ void createGlContext() { gContext.mPbuffer, gContext.mGlCtx); } -bool createContext() { +bool createContext(std::string* errorMsg) { if (gContextRefCount++ > 0) { return true; } @@ -233,8 +232,7 @@ bool createContext() { memset(&gContext, 0, sizeof(gContext)); if (uname(&gContext.mUbuf) != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), - "uname returned error: %d", errno); + errorMsg->append("uname returned error: " + std::to_string(errno)); destroyContext(); return false; } @@ -242,8 +240,7 @@ bool createContext() { gContext.mNumCores = sysconf(_SC_NPROCESSORS_CONF); if (gethostname(gContext.mHostName, sizeof(gContext.mHostName)) != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), - "gethostname returned error: %d", errno); + errorMsg->append("gethostname returned error: " + std::to_string(errno)); destroyContext(); return false; } @@ -253,8 +250,6 @@ bool createContext() { return true; } -const char* contextError() { return gContext.mError; } - bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } int numABIs() { return 1; } diff --git a/core/os/device/deviceinfo/cc/osx/query.mm b/core/os/device/deviceinfo/cc/osx/query.mm index 09a59fab9c..dbfcb56fe3 100644 --- a/core/os/device/deviceinfo/cc/osx/query.mm +++ b/core/os/device/deviceinfo/cc/osx/query.mm @@ -31,7 +31,6 @@ namespace query { struct Context { - char mError[512]; NSOpenGLPixelFormat* mGlFmt; NSOpenGLContext* mGlCtx; NSOperatingSystemVersion mOsVersion; @@ -86,7 +85,7 @@ void createGlContext() { } } -bool createContext() { +bool createContext(std::string* errorMsg) { if (gContextRefCount++ > 0) { return true; } @@ -98,22 +97,20 @@ bool createContext() { sysctl(mib, 2, nullptr, &len, nullptr, 0); gContext.mHwModel = new char[len]; if (sysctl(mib, 2, gContext.mHwModel, &len, nullptr, 0) != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), - "sysctl {CTL_HW, HW_MODEL} returned error: %d", errno); + errorMsg->append("sysctl {CTL_HW, HW_MODEL} returned error: " + std::to_string(errno)); destroyContext(); return false; } len = sizeof(gContext.mNumCores); if (sysctlbyname("hw.logicalcpu_max", &gContext.mNumCores, &len, nullptr, 0) != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), - "sysctlbyname 'hw.logicalcpu_max' returned error: %d", errno); + errorMsg->append("sysctlbyname 'hw.logicalcpu_max' returned error: " + std::to_string(errno)); destroyContext(); return false; } if (gethostname(gContext.mHostName, sizeof(gContext.mHostName)) != 0) { - snprintf(gContext.mError, sizeof(gContext.mError), "gethostname returned error: %d", errno); + errorMsg->append("gethostname returned error: " + std::to_string(errno)); destroyContext(); return false; } @@ -125,8 +122,6 @@ bool createContext() { return true; } -const char* contextError() { return gContext.mError; } - bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } int numABIs() { return 1; } diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index 9ded3fe274..b2287e7f60 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -76,11 +76,11 @@ void deviceInstanceID(device::Instance* instance) { namespace query { -device::Instance* getDeviceInstance(const Option& opt) { +device::Instance* getDeviceInstance(const Option& opt, std::string* error) { using namespace device; using namespace google::protobuf::io; - if (!query::createContext()) { + if (!query::createContext(error)) { return nullptr; } diff --git a/core/os/device/deviceinfo/cc/query.h b/core/os/device/deviceinfo/cc/query.h index 95fecd3ae8..4df4602af8 100644 --- a/core/os/device/deviceinfo/cc/query.h +++ b/core/os/device/deviceinfo/cc/query.h @@ -63,8 +63,10 @@ struct Option { }; // getDeviceInstance returns the device::Instance proto message for the -// current device. It must be freed with delete. -device::Instance* getDeviceInstance(const Option& opt); +// current device. It must be freed with delete. If there is an error +// getting the device info, null is returned and the error string is filled +// with a message. +device::Instance* getDeviceInstance(const Option& opt, std::string* error); // updateVulkanPhysicalDevices modifies the given device::Instance by adding // device::VulkanPhysicalDevice to the device::Instance. If a @@ -116,8 +118,7 @@ bool hasGLorGLES(); // The functions below are used by getDeviceInstance(), and are implemented // in the target-dependent sub-directories. -bool createContext(); -const char* contextError(); +bool createContext(std::string* error); void destroyContext(); // The functions below require a context to be created. diff --git a/core/os/device/deviceinfo/cc/windows/query.cpp b/core/os/device/deviceinfo/cc/windows/query.cpp index ef58fa0917..53d5736e66 100644 --- a/core/os/device/deviceinfo/cc/windows/query.cpp +++ b/core/os/device/deviceinfo/cc/windows/query.cpp @@ -51,7 +51,6 @@ typedef BOOL(CALLBACK* pfn_wglMakeCurrent)(HDC, HGLRC); typedef BOOL(CALLBACK* pfn_wglDeleteContext)(HGLRC); struct Context { - char mError[512]; HWND mWnd; HDC mHDC; HGLRC mGlCtx; @@ -127,7 +126,7 @@ void createGlContext() { return; } -bool createContext() { +bool createContext(std::string* errorMsg) { if (gContextRefCount++ > 0) { return true; } @@ -177,8 +176,8 @@ bool createContext() { DWORD size = MAX_COMPUTERNAME_LENGTH + 1; WCHAR host_wide[MAX_COMPUTERNAME_LENGTH + 1]; if (!GetComputerNameW(host_wide, &size)) { - snprintf(gContext.mError, sizeof(gContext.mError), - "Couldn't get host name: %d", GetLastError()); + errorMsg->append("Couldn't get host name: " + + std::to_string(GetLastError())); return false; } WideCharToMultiByte(CP_UTF8, // CodePage @@ -194,8 +193,6 @@ bool createContext() { return true; } -const char* contextError() { return gContext.mError; } - bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } int numABIs() { return 1; } diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index 99f08b6127..23c6849ba9 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -169,7 +169,12 @@ Spy::Spy() // deviceinfo queries want to call into EGL / GL commands which will be // patched. query::Option query_opt; - SpyBase::set_device_instance(query::getDeviceInstance(query_opt)); + std::string error; + SpyBase::set_device_instance(query::getDeviceInstance(query_opt, &error)); + if (!error.empty()) { + GAPID_ERROR("Failed to get device info: %s", error.c_str()); + } + SpyBase::set_current_abi(query::currentABI()); if (!SpyBase::writeHeader()) { GAPID_ERROR("Failed at writing trace header."); From 6b36af9ca2a9d53ca1c93323ce3b45f2ec4726ad Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 13:42:53 -0700 Subject: [PATCH 0232/1218] Dirtily remove GLES querying from device info. --- core/cc/BUILD.bazel | 10 +- core/cc/gl/formats.cpp | 140 -------------- core/cc/gl/formats.h | 63 ------ core/cc/gl/versions.h | 50 ----- core/os/device/deviceinfo/cc/BUILD.bazel | 15 +- .../device/deviceinfo/cc/android/egl_lite.h | 83 -------- .../os/device/deviceinfo/cc/android/query.cpp | 142 -------------- core/os/device/deviceinfo/cc/gl.cpp | 99 ---------- core/os/device/deviceinfo/cc/gl_lite.h | 43 ----- core/os/device/deviceinfo/cc/linux/query.cpp | 180 ------------------ core/os/device/deviceinfo/cc/osx/query.mm | 48 +---- core/os/device/deviceinfo/cc/query.cpp | 13 +- core/os/device/deviceinfo/cc/query.h | 9 - .../os/device/deviceinfo/cc/windows/query.cpp | 96 ---------- gapii/cc/spy.cpp | 1 - gapir/cc/context.cpp | 1 - 16 files changed, 9 insertions(+), 984 deletions(-) delete mode 100644 core/cc/gl/formats.cpp delete mode 100644 core/cc/gl/formats.h delete mode 100644 core/cc/gl/versions.h delete mode 100644 core/os/device/deviceinfo/cc/android/egl_lite.h delete mode 100644 core/os/device/deviceinfo/cc/gl.cpp delete mode 100644 core/os/device/deviceinfo/cc/gl_lite.h diff --git a/core/cc/BUILD.bazel b/core/cc/BUILD.bazel index a12bf9d267..a320761dc4 100644 --- a/core/cc/BUILD.bazel +++ b/core/cc/BUILD.bazel @@ -18,10 +18,7 @@ load("//tools/build:rules.bzl", "cc_copts") cc_library( name = "cc", srcs = glob( - [ - "*.cpp", - "gl/*.cpp", - ], + ["*.cpp"], exclude = [ "*_test.cpp", ], @@ -41,10 +38,7 @@ cc_library( "posix/*.cpp", ]), }), - hdrs = glob([ - "*.h", - "gl/*.h", - ]), + hdrs = glob(["*.h"]), copts = cc_copts(), linkopts = select({ "//tools/build:linux": ["-ldl"], diff --git a/core/cc/gl/formats.cpp b/core/cc/gl/formats.cpp deleted file mode 100644 index a2cb744e42..0000000000 --- a/core/cc/gl/formats.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "formats.h" - -#include "core/cc/log.h" - -namespace core { -namespace gl { - -bool getColorFormat(int r, int g, int b, int a, uint32_t& format) { - if (r == 8 && g == 8 && b == 8 && a == 8) { - format = GL_RGBA8; - return true; - } else if (r == 8 && g == 8 && b == 8 && a == 0) { - format = GL_RGB8; - return true; - } else if (r == 5 && g == 6 && b == 5 && a == 0) { - format = GL_RGB565; - return true; - } - return false; // Not a recognised combination. -} - -bool getColorBits(uint32_t format, int& r, int& g, int& b, int& a) { - switch (format) { - case GL_RGBA8: - r = 8; - g = 8; - b = 8; - a = 8; - return true; - case GL_RGB8: - r = 8; - g = 8; - b = 8; - a = 0; - return true; - case GL_RGB565: - r = 5; - g = 6; - b = 5; - a = 0; - return true; - } - return false; // Not a recognised combination. -} - -// See: -// https://www.khronos.org/opengles/sdk/docs/man3/docbook4/xhtml/glRenderbufferStorage.xml -bool getDepthStencilFormat(int d, int s, uint32_t& depth, uint32_t& stencil) { - depth = 0; - stencil = 0; - - if (d == 0 && s == 0) { - return true; // No depth, no stencil. - } - - switch (s) { - case 0: - switch (d) { - case 16: - depth = GL_DEPTH_COMPONENT16; - return true; - case 24: - depth = GL_DEPTH_COMPONENT24; - return true; - case 32: - depth = GL_DEPTH_COMPONENT32F; - return true; - } - break; - case 8: - switch (d) { - case 0: - stencil = GL_STENCIL_INDEX8; - return true; - case 24: - depth = GL_DEPTH24_STENCIL8; - stencil = GL_DEPTH24_STENCIL8; - return true; - case 32: - depth = GL_DEPTH32F_STENCIL8; - stencil = GL_DEPTH32F_STENCIL8; - return true; - } - break; - } - return false; // Not a recognised combination. -} - -bool getDepthBits(uint32_t format, int& d) { - d = 0; - switch (format) { - case 0: - return true; - case GL_DEPTH_COMPONENT16: - d = 16; - return true; - case GL_DEPTH_COMPONENT24: - case GL_DEPTH24_STENCIL8: - d = 24; - return true; - case GL_DEPTH_COMPONENT32F: - case GL_DEPTH32F_STENCIL8: - d = 32; - return true; - } - return false; // Not a recognised combination. -} - -bool getStencilBits(uint32_t format, int& s) { - s = 0; - switch (format) { - case 0: - return true; - case GL_STENCIL_INDEX8: - case GL_DEPTH24_STENCIL8: - case GL_DEPTH32F_STENCIL8: - s = 8; - return true; - } - return false; // Not a recognised combination. -} - -} // namespace gl -} // namespace core diff --git a/core/cc/gl/formats.h b/core/cc/gl/formats.h deleted file mode 100644 index 5d92b90bb5..0000000000 --- a/core/cc/gl/formats.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CORE_GL_FORMATS_H -#define CORE_GL_FORMATS_H - -#include - -namespace core { -namespace gl { - -const uint32_t GL_RGB8 = 0x00008051; -const uint32_t GL_RGBA8 = 0x00008058; -const uint32_t GL_RGB565 = 0x00008D62; -const uint32_t GL_DEPTH_COMPONENT16 = 0x000081A5; -const uint32_t GL_DEPTH_COMPONENT24 = 0x000081A6; -const uint32_t GL_DEPTH_COMPONENT32F = 0x00008CAC; -const uint32_t GL_DEPTH32F_STENCIL8 = 0x00008CAD; -const uint32_t GL_DEPTH24_STENCIL8 = 0x000088F0; -const uint32_t GL_STENCIL_INDEX8 = 0x00008D48; - -// getColorFormat gets the color buffer format given the number of bits for the -// red, green, blue and alpha channels. Returns true on success, or false if -// there is no format for the given bit combination. -bool getColorFormat(int r, int g, int b, int a, uint32_t& format); - -// getColorBits gets the number of bits for the red, green, blue and alpha -// channels for the given format. Returns true on success, or false if the -// format is not recognised. -bool getColorBits(uint32_t format, int& r, int& g, int& b, int& a); - -// getDepthStencilFormat gets the depth and stencil buffer formats given the -// number of bits for the depth and stencil channels. Returns true on success, -// or false if there is no format combination for the given bits. -bool getDepthStencilFormat(int d, int s, uint32_t& depth, uint32_t& stencil); - -// getDepthBits gets the number of bits for the depth channel for the given -// depth format. Returns true on success, or false if the format is not -// recognised. -bool getDepthBits(uint32_t format, int& d); - -// getStencilBits gets the number of bits for the stencil channel for the given -// stencil format. Returns true on success, or false if the format is not -// recognised. -bool getStencilBits(uint32_t format, int& s); - -} // namespace gl -} // namespace core - -#endif // CORE_GL_FORMATS_H diff --git a/core/cc/gl/versions.h b/core/cc/gl/versions.h deleted file mode 100644 index 8203b0e72c..0000000000 --- a/core/cc/gl/versions.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CORE_GL_VERSIONS_H -#define CORE_GL_VERSIONS_H - -namespace core { -namespace gl { - -// Version represents a single major.minor version of an OpenGL context. -struct Version { - int major; - int minor; -}; - -// sVersionSearchOrder is an preference-ordered list of OpenGL context versions -// that should be searched in order to pick the most recent version of OpenGL. -// The driver is always free to return a newer version, however some -// implementations will return the precise version requested, so if we request -// 3.2, we would get 3.2 even if a new version is available. -static const Version sVersionSearchOrder[] = { - // clang-format off - {4, 5}, // Compatible with OpenGL ES 3.1 - {4, 4}, - {4, 3}, // Compatible with OpenGL ES 3.0 - {4, 2}, - {4, 1}, // Compatible with OpenGL ES 2.0 - {4, 0}, - {3, 3}, - {3, 2}, // Introduces core profile - // clang-format on -}; - -} // namespace gl -} // namespace core - -#endif // CORE_GL_VERSIONS_H diff --git a/core/os/device/deviceinfo/cc/BUILD.bazel b/core/os/device/deviceinfo/cc/BUILD.bazel index 32edf4dccc..417a733b24 100644 --- a/core/os/device/deviceinfo/cc/BUILD.bazel +++ b/core/os/device/deviceinfo/cc/BUILD.bazel @@ -17,10 +17,7 @@ load("//tools/build:rules.bzl", "android_dynamic_library", "cc_copts", "mm_libra mm_library( name = "darwin_query", srcs = glob(["osx/*.mm"]), - copts = cc_copts() + [ - # Avoid OpenGL deprecation error. - "-DGL_SILENCE_DEPRECATION", - ], + copts = cc_copts(), copy_hdrs = ["query.h"], deps = ["//core/os/device:device_cc_proto"], ) @@ -41,17 +38,11 @@ cc_library( copts = cc_copts(), linkopts = select({ "//tools/build:linux": [], - "//tools/build:darwin": [ - "-framework Cocoa", - "-framework OpenGL", - ], - "//tools/build:windows": ["-lgdi32"], + "//tools/build:darwin": [], + "//tools/build:windows": [], # Android "//conditions:default": [ - "-lEGL", - "-lGLESv2", "-llog", - "-landroid", "-lm", ], }), diff --git a/core/os/device/deviceinfo/cc/android/egl_lite.h b/core/os/device/deviceinfo/cc/android/egl_lite.h deleted file mode 100644 index 45d91e103e..0000000000 --- a/core/os/device/deviceinfo/cc/android/egl_lite.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPID_CORE_OS_DEVICEINFO_ANDROID_EGL_LITE -#define GAPID_CORE_OS_DEVICEINFO_ANDROID_EGL_LITE - -typedef int EGLBoolean; -typedef int EGLint; -typedef unsigned int EGLenum; -typedef void* EGLConfig; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLNativeDisplayType; -typedef void* EGLSurface; - -const EGLint EGL_PBUFFER_BIT = 0x0001; -const EGLint EGL_OPENGL_ES2_BIT = 0x0004; - -const EGLint EGL_TRUE = 0x0001; -const EGLint EGL_SUCCESS = 0x3000; -const EGLint EGL_BUFFER_SIZE = 0x3020; -const EGLint EGL_ALPHA_SIZE = 0x3021; -const EGLint EGL_BLUE_SIZE = 0x3022; -const EGLint EGL_GREEN_SIZE = 0x3023; -const EGLint EGL_RED_SIZE = 0x3024; -const EGLint EGL_DEPTH_SIZE = 0x3025; -const EGLint EGL_STENCIL_SIZE = 0x3026; -const EGLint EGL_CONFIG_ID = 0x3028; -const EGLint EGL_SURFACE_TYPE = 0x3033; -const EGLint EGL_NONE = 0x3038; -const EGLint EGL_RENDERABLE_TYPE = 0x3040; -const EGLint EGL_EXTENSIONS = 0x3055; -const EGLint EGL_HEIGHT = 0x3056; -const EGLint EGL_WIDTH = 0x3057; -const EGLint EGL_SWAP_BEHAVIOR = 0x3093; -const EGLint EGL_BUFFER_PRESERVED = 0x3094; -const EGLint EGL_CONTEXT_CLIENT_VERSION = 0x3098; -const EGLint EGL_OPENGL_ES_API = 0x30A0; - -const EGLNativeDisplayType EGL_DEFAULT_DISPLAY = nullptr; -const EGLContext EGL_NO_CONTEXT = 0; -const EGLDisplay EGL_NO_DISPLAY = 0; -const EGLSurface EGL_NO_SURFACE = 0; - -typedef EGLBoolean (*PFNEGLBINDAPI)(EGLenum api); -typedef EGLBoolean (*PFNEGLCHOOSECONFIG)(EGLDisplay display, - const EGLint* attrib_list, - EGLConfig* configs, EGLint config_size, - EGLint* num_config); -typedef EGLBoolean (*PFNEGLDESTROYCONTEXT)(EGLDisplay display, - EGLContext context); -typedef EGLBoolean (*PFNEGLDESTROYSURFACE)(EGLDisplay display, - EGLSurface surface); -typedef EGLBoolean (*PFNEGLINITIALIZE)(EGLDisplay dpy, EGLint* major, - EGLint* minor); -typedef EGLBoolean (*PFNEGLMAKECURRENT)(EGLDisplay display, EGLSurface draw, - EGLSurface read, EGLContext context); -typedef EGLBoolean (*PFNEGLTERMINATE)(EGLDisplay display); -typedef EGLContext (*PFNEGLCREATECONTEXT)(EGLDisplay display, EGLConfig config, - EGLContext share_context, - const EGLint* attrib_list); -typedef EGLDisplay (*PFNEGLGETDISPLAY)(EGLNativeDisplayType native_display); -typedef EGLint (*PFNEGLGETERROR)(); -typedef EGLSurface (*PFNEGLCREATEPBUFFERSURFACE)(EGLDisplay display, - EGLConfig config, - const EGLint* attrib_list); -typedef const char* (*PFNEGLQUERYSTRING)(EGLDisplay display, EGLint name); -typedef EGLBoolean (*PFNEGLRELEASETHREAD)(); - -#endif // GAPID_CORE_OS_DEVICEINFO_ANDROID_EGL_LITE diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp index 897d5ab137..49d74123a8 100644 --- a/core/os/device/deviceinfo/cc/android/query.cpp +++ b/core/os/device/deviceinfo/cc/android/query.cpp @@ -14,12 +14,9 @@ * limitations under the License. */ -#include "egl_lite.h" - #include "../query.h" #include "core/cc/assert.h" -#include "core/cc/get_gles_proc_address.h" #include "core/cc/log.h" #include @@ -34,10 +31,6 @@ #define LOG_WARN(...) \ __android_log_print(ANDROID_LOG_WARN, "GAPID", __VA_ARGS__); -typedef int GLint; -typedef unsigned int GLuint; -typedef uint8_t GLubyte; - namespace { device::DataTypeLayout* new_dt_layout(int size, int alignment) { @@ -130,9 +123,6 @@ void abiByName(const std::string name, device::ABI* abi) { namespace query { struct Context { - EGLDisplay mDisplay; - EGLSurface mSurface; - EGLContext mContext; int mNumCores; std::string mHost; std::string mHardware; @@ -143,7 +133,6 @@ struct Context { int mOSVersionMinor; std::vector mSupportedABIs; device::Architecture mCpuArchitecture; - std::string eglExtensions; }; static Context gContext; @@ -153,33 +142,6 @@ void destroyContext() { if (--gContextRefCount > 0) { return; } - - auto eglMakeCurrent = reinterpret_cast( - core::GetGlesProcAddress("eglMakeCurrent")); - auto eglDestroyContext = reinterpret_cast( - core::GetGlesProcAddress("eglDestroyContext")); - auto eglDestroySurface = reinterpret_cast( - core::GetGlesProcAddress("eglDestroySurface")); - auto eglTerminate = reinterpret_cast( - core::GetGlesProcAddress("eglTerminate")); - auto eglReleaseThread = reinterpret_cast( - core::GetGlesProcAddress("eglReleaseThread")); - - if (gContext.mContext) { - eglMakeCurrent(gContext.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - eglDestroyContext(gContext.mDisplay, gContext.mContext); - gContext.mContext = 0; - } - if (gContext.mSurface) { - eglDestroySurface(gContext.mDisplay, gContext.mSurface); - gContext.mSurface = 0; - } - if (gContext.mDisplay) { - eglReleaseThread(); - eglTerminate(gContext.mDisplay); - gContext.mDisplay = nullptr; - } } bool createContext(std::string* errorMsg) { @@ -187,100 +149,8 @@ bool createContext(std::string* errorMsg) { return true; } - gContext.mDisplay = nullptr; - gContext.mSurface = nullptr; - gContext.mContext = nullptr; gContext.mNumCores = 0; -#define RESOLVE(name, pfun) \ - auto name = reinterpret_cast(core::GetGlesProcAddress(#name)); \ - GAPID_ASSERT(name != nullptr) - - RESOLVE(eglGetError, PFNEGLGETERROR); - RESOLVE(eglInitialize, PFNEGLINITIALIZE); - RESOLVE(eglBindAPI, PFNEGLBINDAPI); - RESOLVE(eglChooseConfig, PFNEGLCHOOSECONFIG); - RESOLVE(eglCreateContext, PFNEGLCREATECONTEXT); - RESOLVE(eglCreatePbufferSurface, PFNEGLCREATEPBUFFERSURFACE); - RESOLVE(eglMakeCurrent, PFNEGLMAKECURRENT); - RESOLVE(eglGetDisplay, PFNEGLGETDISPLAY); - RESOLVE(eglQueryString, PFNEGLQUERYSTRING); - -#undef RESOLVE - -#define CHECK(x) \ - x; \ - { \ - EGLint error = eglGetError(); \ - if (error != EGL_SUCCESS) { \ - errorMsg->append("EGL error"); \ - destroyContext(); \ - return false; \ - } \ - } - - CHECK(auto display = eglGetDisplay(EGL_DEFAULT_DISPLAY)); - - EGLint major, minor; - CHECK(eglInitialize(display, &major, &minor)); - - gContext.mDisplay = display; - - if (major > 1 || minor >= 5) { - // Client extensions (null display) were added in EGL 1.5. - CHECK(auto exts = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS)); - gContext.eglExtensions.append(exts); - gContext.eglExtensions.append(" "); - } - CHECK(auto exts = eglQueryString(display, EGL_EXTENSIONS)); - gContext.eglExtensions.append(exts); - - CHECK(eglBindAPI(EGL_OPENGL_ES_API)); - - // Find a supported EGL context config. - int r = 8, g = 8, b = 8, a = 8, d = 24, s = 8; - const int configAttribList[] = { - // clang-format off - EGL_RED_SIZE, r, - EGL_GREEN_SIZE, g, - EGL_BLUE_SIZE, b, - EGL_ALPHA_SIZE, a, - EGL_BUFFER_SIZE, r+g+b+a, - EGL_DEPTH_SIZE, d, - EGL_STENCIL_SIZE, s, - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE - // clang-format on - }; - - int one = 1; - EGLConfig eglConfig; - - CHECK(eglChooseConfig(display, configAttribList, &eglConfig, 1, &one)); - - // Create an EGL context. - const int contextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - - CHECK(gContext.mContext = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, - contextAttribList)); - - const int surfaceAttribList[] = { - // clang-format off - EGL_WIDTH, 16, - EGL_HEIGHT, 16, - EGL_NONE - // clang-format on - }; - - CHECK(gContext.mSurface = - eglCreatePbufferSurface(display, eglConfig, surfaceAttribList)); - - CHECK(eglMakeCurrent(display, gContext.mSurface, gContext.mSurface, - gContext.mContext)); - -#undef CHECK - #define GET_PROP(name, trans) \ do { \ char _v[PROP_VALUE_MAX] = {0}; \ @@ -460,8 +330,6 @@ bool createContext(std::string* errorMsg) { return true; } -bool hasGLorGLES() { return true; } - int numABIs() { return gContext.mSupportedABIs.size(); } device::ABI* currentABI() { @@ -512,16 +380,6 @@ int osMinor() { return gContext.mOSVersionMinor; } int osPoint() { return 0; } -void glDriverPlatform(device::OpenGLDriver* driver) { - std::istringstream iss(gContext.eglExtensions); - std::string extension; - while (std::getline(iss, extension, ' ')) { - if (extension != "") { - driver->add_extensions(extension); - } - } -} - device::VulkanProfilingLayers* get_vulkan_profiling_layers() { auto layers = new device::VulkanProfilingLayers(); layers->set_cpu_timing(true); diff --git a/core/os/device/deviceinfo/cc/gl.cpp b/core/os/device/deviceinfo/cc/gl.cpp deleted file mode 100644 index a9e67619e5..0000000000 --- a/core/os/device/deviceinfo/cc/gl.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gl_lite.h" -#include "query.h" - -#include "core/cc/assert.h" -#include "core/cc/get_gles_proc_address.h" -#include "core/cc/log.h" - -#include - -namespace query { - -const char* safe_string(void* x) { - return (x != nullptr) ? reinterpret_cast(x) : ""; -} - -void glDriver(device::OpenGLDriver* driver) { - GLint major_version = 2; - GLint minor_version = 0; - GLint uniformbufferalignment = 1; - GLint maxtransformfeedbackseparateattribs = 0; - GLint maxtransformfeedbackinterleavedcomponents = 0; - - auto glGetIntegerv = reinterpret_cast( - core::GetGlesProcAddress("glGetIntegerv")); - auto glGetError = - reinterpret_cast(core::GetGlesProcAddress("glGetError")); - auto glGetString = - reinterpret_cast(core::GetGlesProcAddress("glGetString")); - auto glGetStringi = reinterpret_cast( - core::GetGlesProcAddress("glGetStringi")); - - GAPID_ASSERT(glGetError != nullptr); - GAPID_ASSERT(glGetString != nullptr); - - glGetError(); // Clear error state. - glGetIntegerv(GL_MAJOR_VERSION, &major_version); - glGetIntegerv(GL_MINOR_VERSION, &minor_version); - if (glGetError() != GL_NO_ERROR) { - // GL_MAJOR_VERSION/GL_MINOR_VERSION were introduced in GLES 3.0, - // so if the commands returned error we assume it is GLES 2.0. - major_version = 2; - minor_version = 0; - } - - if (major_version >= 3) { - GAPID_ASSERT(glGetIntegerv != nullptr); - GAPID_ASSERT(glGetStringi != nullptr); - - glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformbufferalignment); - glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, - &maxtransformfeedbackseparateattribs); - glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, - &maxtransformfeedbackinterleavedcomponents); - - int32_t c = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &c); - for (int32_t i = 0; i < c; i++) { - driver->add_extensions(safe_string(glGetStringi(GL_EXTENSIONS, i))); - } - } else { - std::string extensions = safe_string(glGetString(GL_EXTENSIONS)); - if (glGetError() == GL_NO_ERROR) { - std::istringstream iss(extensions); - std::string extension; - while (std::getline(iss, extension, ' ')) { - driver->add_extensions(extension); - } - } - } - - driver->set_renderer(safe_string(glGetString(GL_RENDERER))); - driver->set_vendor(safe_string(glGetString(GL_VENDOR))); - driver->set_version(safe_string(glGetString(GL_VERSION))); - driver->set_uniform_buffer_alignment(uniformbufferalignment); - driver->set_max_transform_feedback_separate_attribs( - maxtransformfeedbackseparateattribs); - driver->set_max_transform_feedback_interleaved_components( - maxtransformfeedbackinterleavedcomponents); - - glDriverPlatform(driver); -} - -} // namespace query diff --git a/core/os/device/deviceinfo/cc/gl_lite.h b/core/os/device/deviceinfo/cc/gl_lite.h deleted file mode 100644 index 5f14eac1ba..0000000000 --- a/core/os/device/deviceinfo/cc/gl_lite.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GAPID_CORE_OS_DEVICEINFO_GL_LITE -#define GAPID_CORE_OS_DEVICEINFO_GL_LITE - -typedef unsigned int GLenum; -typedef unsigned char GLubyte; -typedef unsigned int GLuint; -typedef int GLint; - -const GLint GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = 0x8A34; - -const GLint GL_NO_ERROR = 0x0000; -const GLint GL_VENDOR = 0x1F00; -const GLint GL_RENDERER = 0x1F01; -const GLint GL_VERSION = 0x1F02; -const GLint GL_EXTENSIONS = 0x1F03; -const GLint GL_MINOR_VERSION = 0x821C; -const GLint GL_MAJOR_VERSION = 0x821B; -const GLint GL_NUM_EXTENSIONS = 0x821D; -const GLint GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS = 0x8C8A; -const GLint GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B; - -typedef void (*PFNGLGETINTEGERV)(GLenum param, GLint* values); -typedef GLenum (*PFNGLGETERROR)(); -typedef GLubyte* (*PFNGLGETSTRING)(GLenum param); -typedef GLubyte* (*PFNGLGETSTRINGI)(GLenum name, GLuint index); - -#endif // GAPID_CORE_OS_DEVICEINFO_GL_LITE diff --git a/core/os/device/deviceinfo/cc/linux/query.cpp b/core/os/device/deviceinfo/cc/linux/query.cpp index 1a6a290b68..badb8b5484 100644 --- a/core/os/device/deviceinfo/cc/linux/query.cpp +++ b/core/os/device/deviceinfo/cc/linux/query.cpp @@ -17,10 +17,7 @@ #include "../query.h" #include "core/cc/dl_loader.h" -#include "core/cc/get_gles_proc_address.h" -#include "core/cc/gl/versions.h" -#include #include #include #include @@ -39,10 +36,6 @@ namespace query { struct Context { - Display* mDisplay; - GLXFBConfig* mFBConfigs; - GLXContext mGlCtx; - GLXPbuffer mPbuffer; int mNumCores; utsname mUbuf; char mHostName[512]; @@ -51,177 +44,10 @@ struct Context { static Context gContext; static int gContextRefCount = 0; -typedef GLXFBConfig* (*pfn_glXChooseFBConfig)(Display* dpy, int screen, - const int* attrib_list, - int* nelements); -typedef GLXContext (*pfn_glXCreateNewContext)(Display* dpy, GLXFBConfig config, - int render_type, - GLXContext shader_list, - bool direct); -typedef GLXPbuffer (*pfn_glXCreatePbuffer)(Display* dpy, GLXFBConfig config, - const int* attrib_list); -typedef void (*pfn_glXDestroyPbuffer)(Display* dpy, GLXPbuffer pbuf); -typedef void (*pfn_glXDestroyContext)(Display* dpy, GLXContext ctx); -typedef Bool (*pfn_glXMakeContextCurrent)(Display* dpy, GLXDrawable draw, - GLXDrawable read, GLXContext ctx); -typedef GLXContext (*pfn_glXCreateContextAttribsARB)(Display* dpy, - GLXFBConfig config, - GLXContext share_context, - Bool direct, - const int* attrib_list); - -typedef int (*pfn_XFree)(void*); -typedef int (*pfn_XCloseDisplay)(Display*); -typedef Display* (*pfn_XOpenDisplay)(_Xconst char*); -typedef XErrorHandler (*pfn_XSetErrorHandler)(XErrorHandler); - void destroyContext() { if (--gContextRefCount > 0) { return; } - - if (!core::DlLoader::can_load("libX11.so")) { - return; - } - - if (!core::hasGLorGLES()) { - return; - } - - core::DlLoader libX("libX11.so"); - pfn_XFree fn_XFree = (pfn_XFree)libX.lookup("XFree"); - pfn_XCloseDisplay fn_XCloseDisplay = - (pfn_XCloseDisplay)libX.lookup("XCloseDisplay"); - - pfn_glXDestroyPbuffer fn_glXDestroyPbuffer = - (pfn_glXDestroyPbuffer)core::GetGlesProcAddress("glXDestroyPbuffer"); - pfn_glXDestroyContext fn_glXDestroyContext = - (pfn_glXDestroyContext)core::GetGlesProcAddress("glXDestroyContext"); - - if (gContext.mPbuffer && fn_glXDestroyPbuffer) { - (*fn_glXDestroyPbuffer)(gContext.mDisplay, gContext.mPbuffer); - gContext.mPbuffer = 0; - } - if (gContext.mGlCtx && fn_glXDestroyContext) { - (*fn_glXDestroyContext)(gContext.mDisplay, gContext.mGlCtx); - gContext.mGlCtx = nullptr; - } - if (gContext.mFBConfigs) { - fn_XFree(gContext.mFBConfigs); - gContext.mFBConfigs = nullptr; - } - if (gContext.mDisplay) { - fn_XCloseDisplay(gContext.mDisplay); - gContext.mDisplay = nullptr; - } -} - -void createGlContext() { - if (!core::hasGLorGLES()) { - return; - } - auto fn_glXChooseFBConfig = - (pfn_glXChooseFBConfig)core::GetGlesProcAddress("glXChooseFBConfig"); - auto fn_glXCreateNewContext = - (pfn_glXCreateNewContext)core::GetGlesProcAddress("glXCreateNewContext"); - auto fn_glXCreatePbuffer = - (pfn_glXCreatePbuffer)core::GetGlesProcAddress("glXCreatePbuffer"); - auto fn_glXMakeContextCurrent = - (pfn_glXMakeContextCurrent)core::GetGlesProcAddress( - "glXMakeContextCurrent"); - auto fn_glXCreateContextAttribsARB = - (pfn_glXCreateContextAttribsARB)core::GetGlesProcAddress( - "glXCreateContextAttribsARB"); - - if (!fn_glXChooseFBConfig || !fn_glXCreateNewContext || - !fn_glXCreatePbuffer || !fn_glXMakeContextCurrent) { - return; - } - - if (!core::DlLoader::can_load("libX11.so")) { - return; - } - - core::DlLoader libX("libX11.so"); - - pfn_XOpenDisplay fn_XOpenDisplay = - (pfn_XOpenDisplay)libX.lookup("XOpenDisplay"); - pfn_XSetErrorHandler fn_XSetErrorHandler = - (pfn_XSetErrorHandler)libX.lookup("XSetErrorHandler"); - - gContext.mDisplay = fn_XOpenDisplay(nullptr); - if (gContext.mDisplay == nullptr) { - return; - } - - const int visualAttribs[] = { - // clang-format off - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT, - None - // clang-format on - }; - int fbConfigsCount = 0; - gContext.mFBConfigs = (*fn_glXChooseFBConfig)( - gContext.mDisplay, DefaultScreen(gContext.mDisplay), visualAttribs, - &fbConfigsCount); - if (!gContext.mFBConfigs) { - return; - } - - GLXFBConfig fbConfig = gContext.mFBConfigs[0]; - - if (fn_glXCreateContextAttribsARB == nullptr) { - gContext.mGlCtx = (*fn_glXCreateNewContext)(gContext.mDisplay, fbConfig, - GLX_RGBA_TYPE, nullptr, True); - } else { - // Prevent X from taking down the process if the GL version is not - // supported. - auto oldHandler = - fn_XSetErrorHandler([](Display*, XErrorEvent*) -> int { return 0; }); - for (auto gl_version : core::gl::sVersionSearchOrder) { - // List of name-value pairs. - const int contextAttribs[] = { - // clang-format off - GLX_RENDER_TYPE, GLX_RGBA_TYPE, - GLX_CONTEXT_MAJOR_VERSION_ARB, gl_version.major, - GLX_CONTEXT_MINOR_VERSION_ARB, gl_version.minor, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None, - // clang-format on - }; - gContext.mGlCtx = - fn_glXCreateContextAttribsARB(gContext.mDisplay, fbConfig, nullptr, - /* direct */ True, contextAttribs); - if (gContext.mGlCtx != nullptr) { - break; - } - } - fn_XSetErrorHandler(oldHandler); - } - - if (!gContext.mGlCtx) { - return; - } - - const int pbufferAttribs[] = {GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, - None}; - - gContext.mPbuffer = - fn_glXCreatePbuffer(gContext.mDisplay, fbConfig, pbufferAttribs); - if (!gContext.mPbuffer) { - return; - } - - fn_glXMakeContextCurrent(gContext.mDisplay, gContext.mPbuffer, - gContext.mPbuffer, gContext.mGlCtx); } bool createContext(std::string* errorMsg) { @@ -245,13 +71,9 @@ bool createContext(std::string* errorMsg) { return false; } - createGlContext(); - return true; } -bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } - int numABIs() { return 1; } void abi(int idx, device::ABI* abi) { @@ -289,8 +111,6 @@ int osMinor() { return 0; } int osPoint() { return 0; } -void glDriverPlatform(device::OpenGLDriver*) {} - device::VulkanProfilingLayers* get_vulkan_profiling_layers() { auto layers = new device::VulkanProfilingLayers(); layers->set_cpu_timing(true); diff --git a/core/os/device/deviceinfo/cc/osx/query.mm b/core/os/device/deviceinfo/cc/osx/query.mm index dbfcb56fe3..9facb434bf 100644 --- a/core/os/device/deviceinfo/cc/osx/query.mm +++ b/core/os/device/deviceinfo/cc/osx/query.mm @@ -17,22 +17,17 @@ #include "../query.h" #import -#import - -#include - -#include #include #include +#include +#include #define STR_OR_EMPTY(x) ((x != nullptr) ? x : "") namespace query { struct Context { - NSOpenGLPixelFormat* mGlFmt; - NSOpenGLContext* mGlCtx; NSOperatingSystemVersion mOsVersion; int mNumCores; char* mHwModel; @@ -50,39 +45,6 @@ void destroyContext() { if (gContext.mHwModel) { delete[] gContext.mHwModel; } - if (gContext.mGlFmt) { - [gContext.mGlFmt release]; - gContext.mGlFmt = nullptr; - } - if (gContext.mGlCtx) { - [gContext.mGlCtx release]; - gContext.mGlCtx = nullptr; - } -} - -void createGlContext() { - NSOpenGLPixelFormatAttribute attributes[] = { - // clang-format off - NSOpenGLPFANoRecovery, - NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)32, - NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24, - NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute)8, - NSOpenGLPFAAccelerated, - NSOpenGLPFABackingStore, - NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, - (NSOpenGLPixelFormatAttribute)0 - // clang-format on - }; - - gContext.mGlFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - if (gContext.mGlFmt != nullptr) { - gContext.mGlCtx = [[NSOpenGLContext alloc] initWithFormat:gContext.mGlFmt shareContext:nil]; - if (gContext.mGlCtx == nullptr) { - return; - } - - [gContext.mGlCtx makeCurrentContext]; - } } bool createContext(std::string* errorMsg) { @@ -115,15 +77,11 @@ bool createContext(std::string* errorMsg) { return false; } - createGlContext(); - gContext.mOsVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; return true; } -bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } - int numABIs() { return 1; } void abi(int idx, device::ABI* abi) { @@ -161,8 +119,6 @@ void abi(int idx, device::ABI* abi) { int osPoint() { return gContext.mOsVersion.patchVersion; } -void glDriverPlatform(device::OpenGLDriver*) {} - device::VulkanProfilingLayers* get_vulkan_profiling_layers() { return nullptr; } bool hasAtrace() { return false; } diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index b2287e7f60..346b2b0411 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -96,16 +96,8 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { // Instance.Configuration.Drivers auto drivers = new Drivers(); - const char* backupVendor = ""; + const char* backupVendor = ""; // TODO: we no longer have a backup for this const char* backupName = ""; - if (query::hasGLorGLES()) { - // Instance.Configuration.Drivers.OpenGLDriver - auto opengl_driver = new OpenGLDriver(); - query::glDriver(opengl_driver); - drivers->set_allocated_opengl(opengl_driver); - backupVendor = opengl_driver->vendor().c_str(); - backupName = opengl_driver->renderer().c_str(); - } // Checks if the device supports Vulkan (have Vulkan loader) first, then // populates the VulkanDriver message. @@ -116,8 +108,7 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { } if (opt.vulkan.query_physical_devices()) { query::vkPhysicalDevices(vulkan_driver); - if (strlen(backupName) == 0 && - vulkan_driver->physical_devices_size() > 0) { + if (vulkan_driver->physical_devices_size() > 0) { backupName = vulkan_driver->physical_devices(0).device_name().c_str(); } } diff --git a/core/os/device/deviceinfo/cc/query.h b/core/os/device/deviceinfo/cc/query.h index 4df4602af8..f4cda39399 100644 --- a/core/os/device/deviceinfo/cc/query.h +++ b/core/os/device/deviceinfo/cc/query.h @@ -111,10 +111,6 @@ device::VulkanProfilingLayers* get_vulkan_profiling_layers(); // false. bool hasVulkanLoader(); -// hasGLorGLES returns true if there is a OpenGL or OpenGL ES display driver -// that can be used. -bool hasGLorGLES(); - // The functions below are used by getDeviceInstance(), and are implemented // in the target-dependent sub-directories. @@ -140,11 +136,6 @@ const char* gpuVendor(); const char* instanceName(); -// This queries the platform independent GL things. -void glDriver(device::OpenGLDriver*); -// This queries the platform depended GL things. -void glDriverPlatform(device::OpenGLDriver*); - device::OSKind osKind(); const char* osName(); const char* osBuild(); diff --git a/core/os/device/deviceinfo/cc/windows/query.cpp b/core/os/device/deviceinfo/cc/windows/query.cpp index 53d5736e66..d03308c6b0 100644 --- a/core/os/device/deviceinfo/cc/windows/query.cpp +++ b/core/os/device/deviceinfo/cc/windows/query.cpp @@ -16,52 +16,15 @@ #include "../query.h" -#include "core/cc/get_gles_proc_address.h" - -#include #include -#include - -namespace { - -static const char* wndClassName = TEXT("opengl-dummy-window"); - -WNDCLASSEX registerWindowClass() { - WNDCLASSEX wc; - memset(&wc, 0, sizeof(wc)); - wc.cbSize = sizeof(wc); - // We must use CS_OWNDC here if we are to use this window with GL. - // https://www.khronos.org/opengl/wiki/Creating_an_OpenGL_Context_(WGL)#The_Window_Itself - wc.style = CS_OWNDC; - wc.lpfnWndProc = DefWindowProc; - wc.hInstance = GetModuleHandle(0); - wc.hCursor = LoadCursor(0, IDC_ARROW); - wc.lpszMenuName = TEXT(""); - wc.lpszClassName = wndClassName; - RegisterClassEx(&wc); - return wc; -} - -} // anonymous namespace namespace query { -typedef HGLRC(CALLBACK* pfn_wglCreateContext)(HDC); -typedef BOOL(CALLBACK* pfn_wglMakeCurrent)(HDC, HGLRC); -typedef BOOL(CALLBACK* pfn_wglDeleteContext)(HGLRC); - struct Context { - HWND mWnd; - HDC mHDC; - HGLRC mGlCtx; int mNumCores; char mHostName[MAX_COMPUTERNAME_LENGTH * 4 + 1]; // Stored as UTF-8 OSVERSIONINFOEX mOsVersion; const char* mOsName; - - pfn_wglCreateContext wglCreateContext; - pfn_wglMakeCurrent wglMakeCurrent; - pfn_wglDeleteContext wglDeleteContext; }; static Context gContext; @@ -71,59 +34,6 @@ void destroyContext() { if (--gContextRefCount > 0) { return; } - - if (gContext.mWnd != nullptr) { - DestroyWindow(gContext.mWnd); - } - if (gContext.mGlCtx != nullptr) { - gContext.wglMakeCurrent(gContext.mHDC, 0); - gContext.wglDeleteContext(gContext.mGlCtx); - } -} - -void createGlContext() { - gContext.wglCreateContext = - (pfn_wglCreateContext)core::GetGlesProcAddress("wglCreateContext"); - gContext.wglMakeCurrent = - (pfn_wglMakeCurrent)core::GetGlesProcAddress("wglMakeCurrent"); - gContext.wglDeleteContext = - (pfn_wglDeleteContext)core::GetGlesProcAddress("wglDeleteContext"); - - if (gContext.wglCreateContext == nullptr || - gContext.wglMakeCurrent == nullptr || - gContext.wglDeleteContext == nullptr) { - return; - } - - WNDCLASSEX wc = registerWindowClass(); - gContext.mWnd = CreateWindow(wndClassName, TEXT(""), WS_POPUP, 0, 0, 8, 8, 0, - 0, GetModuleHandle(0), 0); - if (gContext.mWnd == nullptr) { - return; - } - - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cRedBits = 8; - pfd.cGreenBits = 8; - pfd.cBlueBits = 8; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - pfd.cColorBits = 32; - pfd.iLayerType = PFD_MAIN_PLANE; - gContext.mHDC = GetDC(gContext.mWnd); - SetPixelFormat(gContext.mHDC, ChoosePixelFormat(gContext.mHDC, &pfd), &pfd); - gContext.mGlCtx = gContext.wglCreateContext(gContext.mHDC); - if (gContext.mGlCtx != nullptr) { - gContext.wglMakeCurrent(gContext.mHDC, gContext.mGlCtx); - } - - return; } bool createContext(std::string* errorMsg) { @@ -131,8 +41,6 @@ bool createContext(std::string* errorMsg) { return true; } - createGlContext(); - gContext.mOsVersion.dwOSVersionInfoSize = sizeof(gContext.mOsVersion); GetVersionEx((OSVERSIONINFO*)(&gContext.mOsVersion)); int major = gContext.mOsVersion.dwMajorVersion; @@ -193,8 +101,6 @@ bool createContext(std::string* errorMsg) { return true; } -bool hasGLorGLES() { return gContext.mGlCtx != nullptr; } - int numABIs() { return 1; } void abi(int idx, device::ABI* abi) { @@ -232,8 +138,6 @@ int osMinor() { return gContext.mOsVersion.dwMinorVersion; } int osPoint() { return gContext.mOsVersion.dwBuildNumber; } -void glDriverPlatform(device::OpenGLDriver*) {} - device::VulkanProfilingLayers* get_vulkan_profiling_layers() { return nullptr; } bool hasAtrace() { return false; } diff --git a/gapii/cc/spy.cpp b/gapii/cc/spy.cpp index 23c6849ba9..2d2264375a 100644 --- a/gapii/cc/spy.cpp +++ b/gapii/cc/spy.cpp @@ -24,7 +24,6 @@ #include "gapii/cc/spy.h" -#include "core/cc/gl/formats.h" #include "core/cc/lock.h" #include "core/cc/log.h" #include "core/cc/null_writer.h" diff --git a/gapir/cc/context.cpp b/gapir/cc/context.cpp index 1044df4ecc..5556232bbf 100644 --- a/gapir/cc/context.cpp +++ b/gapir/cc/context.cpp @@ -26,7 +26,6 @@ #include "stack.h" #include "vulkan_renderer.h" -#include "core/cc/gl/formats.h" #include "core/cc/log.h" #include "core/cc/target.h" From e39537f5115e80800d3e68e64962279e14309345 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 15:22:48 -0700 Subject: [PATCH 0233/1218] Move the Mesa LLVM hack from GLES to Vulkan. The Vulkan driver has the exact same issue, we've just been relying on GLES being loaded first. --- core/cc/linux/get_gles_proc_address.cpp | 21 --------------------- core/cc/linux/get_vulkan_proc_address.cpp | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/core/cc/linux/get_gles_proc_address.cpp b/core/cc/linux/get_gles_proc_address.cpp index 72d8616c45..5cd0af80e3 100644 --- a/core/cc/linux/get_gles_proc_address.cpp +++ b/core/cc/linux/get_gles_proc_address.cpp @@ -18,32 +18,11 @@ #include "../dl_loader.h" #include "../log.h" -#include - namespace { -// The mesa driver does bad things with LLVM. Since we also use llvm, -// we can't have the mesa driver do bad things to our code. -// Therefore we should preload any versions of llvm that may be required -// into the start of our address space. -// See: https://github.com/google/gapid/issues/1707 for more information -struct MesaLLVMOpener { - MesaLLVMOpener() { - char name[512]; - for (int i = 3; i <= 9; i++) { - snprintf(name, sizeof(name), "libLLVM-%d.0.so.1", i); - dlopen(name, RTLD_LAZY | RTLD_DEEPBIND); - snprintf(name, sizeof(name), "libLLVM-%d.so.1", i); - dlopen(name, RTLD_LAZY | RTLD_DEEPBIND); - } - } -}; - void* getGlesProcAddress(const char* name) { using namespace core; typedef void* (*GPAPROC)(const char* name); - static MesaLLVMOpener _dummy; - (void)_dummy; // Why .1 ? // See: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826 diff --git a/core/cc/linux/get_vulkan_proc_address.cpp b/core/cc/linux/get_vulkan_proc_address.cpp index 55663b8cde..52a4298941 100644 --- a/core/cc/linux/get_vulkan_proc_address.cpp +++ b/core/cc/linux/get_vulkan_proc_address.cpp @@ -18,6 +18,8 @@ #include "../dl_loader.h" #include "../log.h" +#include + namespace { using namespace core; @@ -28,9 +30,29 @@ typedef void* PFN_vkVoidFunction; typedef size_t VkDevice; typedef size_t VkInstance; +// The mesa driver does bad things with LLVM. Since we also use llvm, +// we can't have the mesa driver do bad things to our code. +// Therefore we should preload any versions of llvm that may be required +// into the start of our address space. +// See: https://github.com/google/gapid/issues/1707 for more information +struct MesaLLVMOpener { + MesaLLVMOpener() { + char name[512]; + for (int i = 3; i <= 9; i++) { + snprintf(name, sizeof(name), "libLLVM-%d.0.so.1", i); + dlopen(name, RTLD_LAZY | RTLD_DEEPBIND); + snprintf(name, sizeof(name), "libLLVM-%d.so.1", i); + dlopen(name, RTLD_LAZY | RTLD_DEEPBIND); + } + } +}; + void* getVulkanInstanceProcAddress(size_t instance, const char* name) { typedef PFN_vkVoidFunction (*VPAPROC)(VkInstance instance, const char* name); + static MesaLLVMOpener _dummy; + (void)_dummy; + static DlLoader dylib("libvulkan.so", "libvulkan.so.1"); if (VPAPROC vpa = From ef283f2012f132ca266b4dd18c476429a1e00cd7 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 15:30:29 -0700 Subject: [PATCH 0234/1218] Get rid of core::GetGlesProcAddress and friends. --- core/cc/android/get_gles_proc_address.cpp | 104 --------------------- core/cc/armlinux/get_gles_proc_address.cpp | 102 -------------------- core/cc/get_gles_proc_address.h | 32 ------- core/cc/linux/get_gles_proc_address.cpp | 56 ----------- core/cc/osx/get_gles_proc_address.cpp | 72 -------------- core/cc/windows/get_gles_proc_address.cpp | 70 -------------- 6 files changed, 436 deletions(-) delete mode 100644 core/cc/android/get_gles_proc_address.cpp delete mode 100644 core/cc/armlinux/get_gles_proc_address.cpp delete mode 100644 core/cc/get_gles_proc_address.h delete mode 100644 core/cc/linux/get_gles_proc_address.cpp delete mode 100644 core/cc/osx/get_gles_proc_address.cpp delete mode 100644 core/cc/windows/get_gles_proc_address.cpp diff --git a/core/cc/android/get_gles_proc_address.cpp b/core/cc/android/get_gles_proc_address.cpp deleted file mode 100644 index 96ed6729ee..0000000000 --- a/core/cc/android/get_gles_proc_address.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../get_gles_proc_address.h" -#include "../dl_loader.h" -#include "../log.h" - -#include -#include - -#if defined(__LP64__) -#define SYSTEM_LIB_PATH "/system/lib64/" -#else -#define SYSTEM_LIB_PATH "/system/lib/" -#endif - -namespace { - -void* ResolveSymbol(const char* name) { - using namespace core; - typedef void* (*GPAPROC)(const char* name); - - static DlLoader libegl(SYSTEM_LIB_PATH "libEGL.so"); - if (void* proc = libegl.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> %p (from libEGL dlsym)", name, proc); - return proc; - } - - static DlLoader libglesv2(SYSTEM_LIB_PATH "libGLESv2.so"); - if (void* proc = libglesv2.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> %p (from libGLESv2 dlsym)", name, - proc); - return proc; - } - - static DlLoader libglesv1(SYSTEM_LIB_PATH "libGLESv1_CM.so"); - if (void* proc = libglesv1.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> %p (from libGLESv1_CM dlsym)", name, - proc); - return proc; - } - - if (GPAPROC gpa = - reinterpret_cast(libegl.lookup("eglGetProcAddress"))) { - if (void* proc = gpa(name)) { - static DlLoader local(nullptr); - void* local_proc = local.lookup(name); - if (local_proc == proc) { - GAPID_WARNING( - "libEGL eglGetProcAddress returned a local address %p for %s, this " - "will be ignored", - proc, name); - } else { - GAPID_DEBUG( - "GetGlesProcAddress(%s) -> %p (via libEGL eglGetProcAddress)", name, - proc); - return proc; - } - } - } - - GAPID_DEBUG("GetGlesProcAddress(%s) -> not found", name); - return nullptr; -} - -void* getGlesProcAddress(const char* name) { - static std::unordered_map cache; - - auto it = cache.find(name); - if (it != cache.end()) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> %p (from cache)", name, it->second); - return it->second; - } - - void* proc = ResolveSymbol(name); - cache[name] = proc; - return proc; -} - -} // anonymous namespace - -namespace core { - -GetGlesProcAddressFunc* GetGlesProcAddress = getGlesProcAddress; -bool hasGLorGLES() { - return DlLoader::can_load(SYSTEM_LIB_PATH "libEGL.so") || - DlLoader::can_load(SYSTEM_LIB_PATH "libGLESv2.so") || - DlLoader::can_load(SYSTEM_LIB_PATH "libGLESv1_CM.so"); -} - -} // namespace core diff --git a/core/cc/armlinux/get_gles_proc_address.cpp b/core/cc/armlinux/get_gles_proc_address.cpp deleted file mode 100644 index cfd43dfa01..0000000000 --- a/core/cc/armlinux/get_gles_proc_address.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../get_gles_proc_address.h" -#include "../dl_loader.h" -#include "../log.h" - -#include -#include - -#define SYSTEM_LIB_PATH "/usr/lib/" - -namespace { - -void* ResolveSymbol(const char* name) { - using namespace core; - typedef void* (*GPAPROC)(const char* name); - - static DlLoader libegl(SYSTEM_LIB_PATH "libEGL.so"); - if (void* proc = libegl.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from libEGL dlsym)", name, - proc); - return proc; - } - - static DlLoader libglesv2(SYSTEM_LIB_PATH "libGLESv2.so"); - if (void* proc = libglesv2.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from libGLESv2 dlsym)", name, - proc); - return proc; - } - - static DlLoader libglesv1(SYSTEM_LIB_PATH "libGLESv1_CM.so"); - if (void* proc = libglesv1.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from libGLESv1_CM dlsym)", - name, proc); - return proc; - } - - if (GPAPROC gpa = - reinterpret_cast(libegl.lookup("eglGetProcAddress"))) { - if (void* proc = gpa(name)) { - static DlLoader local(nullptr); - void* local_proc = local.lookup(name); - if (local_proc == proc) { - GAPID_WARNING( - "libEGL eglGetProcAddress returned a local address %p for %s, this " - "will be ignored", - proc, name); - } else { - GAPID_DEBUG( - "GetGlesProcAddress(%s) -> 0x%x (via libEGL eglGetProcAddress)", - name, proc); - return proc; - } - } - } - - GAPID_DEBUG("GetGlesProcAddress(%s) -> not found", name); - return nullptr; -} - -void* getGlesProcAddress(const char* name) { - static std::unordered_map cache; - - auto it = cache.find(name); - if (it != cache.end()) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from cache)", name, - it->second); - return it->second; - } - - void* proc = ResolveSymbol(name); - cache[name] = proc; - return proc; -} - -} // anonymous namespace - -namespace core { -bool hasGLorGLES() { - return DlLoader::can_load(SYSTEM_LIB_PATH "libEGL.so") || - DlLoader::can_load(SYSTEM_LIB_PATH "libGLESv2.so") || - DlLoader::can_load(SYSTEM_LIB_PATH SYSTEM_LIB_PATH "libGLESv1_CM.so"); -} - -GetGlesProcAddressFunc* GetGlesProcAddress = getGlesProcAddress; - -} // namespace core diff --git a/core/cc/get_gles_proc_address.h b/core/cc/get_gles_proc_address.h deleted file mode 100644 index 1c91274b3c..0000000000 --- a/core/cc/get_gles_proc_address.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CORE_GET_GLES_PROC_ADDRESS_H -#define CORE_GET_GLES_PROC_ADDRESS_H - -namespace core { - -typedef void*(GetGlesProcAddressFunc)(const char* name); - -// GetGlesProcAddress returns the GLES function pointer to the function with -// the given name, or nullptr if the function was not found. -extern GetGlesProcAddressFunc* GetGlesProcAddress; - -bool hasGLorGLES(); - -} // namespace core - -#endif // CORE_GET_GLES_PROC_ADDRESS_H diff --git a/core/cc/linux/get_gles_proc_address.cpp b/core/cc/linux/get_gles_proc_address.cpp deleted file mode 100644 index 5cd0af80e3..0000000000 --- a/core/cc/linux/get_gles_proc_address.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../get_gles_proc_address.h" -#include "../dl_loader.h" -#include "../log.h" - -namespace { - -void* getGlesProcAddress(const char* name) { - using namespace core; - typedef void* (*GPAPROC)(const char* name); - - // Why .1 ? - // See: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826 - static DlLoader libgl("libGL.so.1"); - if (GPAPROC gpa = - reinterpret_cast(libgl.lookup("glXGetProcAddress"))) { - if (void* proc = gpa(name)) { - GAPID_VERBOSE( - "GetGlesProcAddress(%s) -> 0x%x (via libGL glXGetProcAddress)", name, - proc); - return proc; - } - } - if (void* proc = libgl.lookup(name)) { - GAPID_VERBOSE("GetGlesProcAddress(%s) -> 0x%x (from libGL dlsym)", name, - proc); - return proc; - } - - GAPID_DEBUG("GetGlesProcAddress(%s) -> not found", name); - return nullptr; -} - -} // anonymous namespace - -namespace core { - -GetGlesProcAddressFunc* GetGlesProcAddress = getGlesProcAddress; -bool hasGLorGLES() { return DlLoader::can_load("libGL.so.1"); } - -} // namespace core diff --git a/core/cc/osx/get_gles_proc_address.cpp b/core/cc/osx/get_gles_proc_address.cpp deleted file mode 100644 index da5c084caa..0000000000 --- a/core/cc/osx/get_gles_proc_address.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../get_gles_proc_address.h" -#include "../dl_loader.h" -#include "../log.h" - -namespace { - -#define FRAMEWORK_ROOT "/System/Library/Frameworks/OpenGL.framework/" -#define CORE_GRAPHICS \ - "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics" - -void* getGlesProcAddress(const char* name) { - using namespace core; - static DlLoader opengl(FRAMEWORK_ROOT "OpenGL"); - if (void* proc = opengl.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from OpenGL dlsym)", name, - proc); - return proc; - } - - static DlLoader libgl(FRAMEWORK_ROOT "Libraries/libGL.dylib"); - if (void* proc = libgl.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from libGL dlsym)", name, - proc); - return proc; - } - - static DlLoader libglu(FRAMEWORK_ROOT "Libraries/libGLU.dylib"); - if (void* proc = libglu.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from libGLU dlsym)", name, - proc); - return proc; - } - - static DlLoader coregraphics(CORE_GRAPHICS); - if (void* proc = coregraphics.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from CoreGraphics dlsym)", - name, proc); - return proc; - } - - return nullptr; -} - -} // anonymous namespace - -namespace core { - -GetGlesProcAddressFunc* GetGlesProcAddress = getGlesProcAddress; -bool hasGLorGLES() { - return DlLoader::can_load(FRAMEWORK_ROOT "OpenGL") || - DlLoader::can_load(FRAMEWORK_ROOT "Libraries/libGL.dylib") || - DlLoader::can_load(FRAMEWORK_ROOT "Libraries/libGLU.dylib") || - DlLoader::can_load(CORE_GRAPHICS); -} - -} // namespace core diff --git a/core/cc/windows/get_gles_proc_address.cpp b/core/cc/windows/get_gles_proc_address.cpp deleted file mode 100644 index 2c3d344f03..0000000000 --- a/core/cc/windows/get_gles_proc_address.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "../get_gles_proc_address.h" -#include "../dl_loader.h" -#include "../log.h" -#include "../target.h" // STDCALL - -#include -#include - -#include -#include - -namespace { - -std::string systemOpengl32Path() { - char sysdir[MAX_PATH]; - GetSystemDirectoryA(sysdir, MAX_PATH - 1); - - std::stringstream path; - path << sysdir << "\\opengl32.dll"; - return path.str(); -} - -void* getGlesProcAddress(const char* name) { - using namespace core; - typedef void* (*GPAPROC)(const char* name); - - static DlLoader opengl(systemOpengl32Path().c_str()); - if (GPAPROC gpa = - reinterpret_cast(opengl.lookup("wglGetProcAddress"))) { - if (void* proc = gpa(name)) { - GAPID_DEBUG( - "GetGlesProcAddress(%s) -> 0x%x (via opengl32 wglGetProcAddress)", - name, proc); - return proc; - } - } - if (void* proc = opengl.lookup(name)) { - GAPID_DEBUG("GetGlesProcAddress(%s) -> 0x%x (from opengl32 symbol)", name, - proc); - return proc; - } - - GAPID_DEBUG("GetGlesProcAddress(%s) -> not found", name); - return nullptr; -} - -} // anonymous namespace - -namespace core { - -GetGlesProcAddressFunc* GetGlesProcAddress = getGlesProcAddress; -bool hasGLorGLES() { return DlLoader::can_load(systemOpengl32Path().c_str()); } - -} // namespace core From 4c854d4c03dde17fdb017f74f51ef7a924cb37d4 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 15:30:56 -0700 Subject: [PATCH 0235/1218] Delete a bunch of unused ancient OpenGL templates. --- gapis/api/templates/BUILD.bazel | 40 - gapis/api/templates/opengl32_exports.def.tmpl | 45 - gapis/api/templates/opengl32_exports.tmpl | 387 ----- gapis/api/templates/opengl32_resolve.cpp.tmpl | 56 - gapis/api/templates/opengl32_x64.asm.tmpl | 98 -- .../opengl_framework_exports.cpp.tmpl | 58 - .../templates/opengl_framework_exports.tmpl | 1451 ----------------- 7 files changed, 2135 deletions(-) delete mode 100644 gapis/api/templates/opengl32_exports.def.tmpl delete mode 100644 gapis/api/templates/opengl32_exports.tmpl delete mode 100644 gapis/api/templates/opengl32_resolve.cpp.tmpl delete mode 100644 gapis/api/templates/opengl32_x64.asm.tmpl delete mode 100644 gapis/api/templates/opengl_framework_exports.cpp.tmpl delete mode 100644 gapis/api/templates/opengl_framework_exports.tmpl diff --git a/gapis/api/templates/BUILD.bazel b/gapis/api/templates/BUILD.bazel index b7292e4e08..242643dc28 100644 --- a/gapis/api/templates/BUILD.bazel +++ b/gapis/api/templates/BUILD.bazel @@ -219,46 +219,6 @@ api_template( template = "api_types.cpp.tmpl", ) -api_template( - name = "opengl32_exports.def", - includes = [ - "opengl32_exports.tmpl", - ":cpp_common_deps", - ], - outputs = ["opengl32_exports.def"], - template = "opengl32_exports.def.tmpl", -) - -api_template( - name = "opengl32_resolve.cpp", - includes = [ - "opengl32_exports.tmpl", - ":cpp_common_deps", - ], - outputs = ["opengl32_resolve.cpp"], - template = "opengl32_resolve.cpp.tmpl", -) - -api_template( - name = "opengl32_x64.asm", - includes = [ - "opengl32_exports.tmpl", - ":cpp_common_deps", - ], - outputs = ["opengl32_x64.asm"], - template = "opengl32_x64.asm.tmpl", -) - -api_template( - name = "opengl_framework_exports.cpp", - includes = [ - "opengl_framework_exports.tmpl", - ":cpp_common_deps", - ], - outputs = ["opengl_framework_exports.cpp"], - template = "opengl_framework_exports.cpp.tmpl", -) - api_template( name = "enum_lookup.go", includes = [":go_common_deps"], diff --git a/gapis/api/templates/opengl32_exports.def.tmpl b/gapis/api/templates/opengl32_exports.def.tmpl deleted file mode 100644 index f33e42d87e..0000000000 --- a/gapis/api/templates/opengl32_exports.def.tmpl +++ /dev/null @@ -1,45 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{Include "opengl32_exports.tmpl"}} -{{Include "cpp_common.tmpl"}} -{{$ | Macro "opengl32_exports.def" | Reflow 2 | Write "opengl32_exports.def"}} - -{{/* -------------------------------------------------------------------------------- - Emits a MSVC module-definition file (.def) to export all of the OpenGL32.dll - functions. -------------------------------------------------------------------------------- -*/}} -{{define "opengl32_exports.def"}} - {{AssertType $ "API"}} - - {{/* This is the list of functions that OpenGL32.dll needs to export. */}} - {{$opengl32_exports := Strings (Macro "OpenGL32Exports") | SplitEOL}} - - {{/* This is the list of functions that the spy exports. */}} - {{$api_exports := (ForEach (AllCommands $) "CmdName") | Strings "wglGetProcAddress"}} - - {{/* This is list of functions we need to export. */}} - {{$exports := $opengl32_exports | FilterOut $api_exports}} - -LIBRARY -EXPORTS» - {{range $f := $exports}} - {{$f}} - {{end}} -« -{{end}} \ No newline at end of file diff --git a/gapis/api/templates/opengl32_exports.tmpl b/gapis/api/templates/opengl32_exports.tmpl deleted file mode 100644 index a491a90b75..0000000000 --- a/gapis/api/templates/opengl32_exports.tmpl +++ /dev/null @@ -1,387 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* The full list of exported functions from OpenGL32.dll */}} -{{define "OpenGL32Exports"}} -glAccum -glAlphaFunc -glAreTexturesResident -glArrayElement -glBegin -glBindTexture -glBitmap -glBlendFunc -glCallList -glCallLists -glClear -glClearAccum -glClearColor -glClearDepth -glClearIndex -glClearStencil -glClipPlane -glColor3b -glColor3bv -glColor3d -glColor3dv -glColor3f -glColor3fv -glColor3i -glColor3iv -glColor3s -glColor3sv -glColor3ub -glColor3ubv -glColor3ui -glColor3uiv -glColor3us -glColor3usv -glColor4b -glColor4bv -glColor4d -glColor4dv -glColor4f -glColor4fv -glColor4i -glColor4iv -glColor4s -glColor4sv -glColor4ub -glColor4ubv -glColor4ui -glColor4uiv -glColor4us -glColor4usv -glColorMask -glColorMaterial -glColorPointer -glCopyPixels -glCopyTexImage1D -glCopyTexImage2D -glCopyTexSubImage1D -glCopyTexSubImage2D -glCullFace -glDebugEntry -glDeleteLists -glDeleteTextures -glDepthFunc -glDepthMask -glDepthRange -glDisable -glDisableClientState -glDrawArrays -glDrawBuffer -glDrawElements -glDrawPixels -glEdgeFlag -glEdgeFlagPointer -glEdgeFlagv -glEnable -glEnableClientState -glEnd -glEndList -glEvalCoord1d -glEvalCoord1dv -glEvalCoord1f -glEvalCoord1fv -glEvalCoord2d -glEvalCoord2dv -glEvalCoord2f -glEvalCoord2fv -glEvalMesh1 -glEvalMesh2 -glEvalPoint1 -glEvalPoint2 -glFeedbackBuffer -glFinish -glFlush -glFogf -glFogfv -glFogi -glFogiv -glFrontFace -glFrustum -glGenLists -glGenTextures -glGetBooleanv -glGetClipPlane -glGetDoublev -glGetError -glGetFloatv -glGetIntegerv -glGetLightfv -glGetLightiv -glGetMapdv -glGetMapfv -glGetMapiv -glGetMaterialfv -glGetMaterialiv -glGetPixelMapfv -glGetPixelMapuiv -glGetPixelMapusv -glGetPointerv -glGetPolygonStipple -glGetString -glGetTexEnvfv -glGetTexEnviv -glGetTexGendv -glGetTexGenfv -glGetTexGeniv -glGetTexImage -glGetTexLevelParameterfv -glGetTexLevelParameteriv -glGetTexParameterfv -glGetTexParameteriv -glHint -glIndexd -glIndexdv -glIndexf -glIndexfv -glIndexi -glIndexiv -glIndexMask -glIndexPointer -glIndexs -glIndexsv -glIndexub -glIndexubv -glInitNames -glInterleavedArrays -glIsEnabled -glIsList -glIsTexture -glLightf -glLightfv -glLighti -glLightiv -glLightModelf -glLightModelfv -glLightModeli -glLightModeliv -glLineStipple -glLineWidth -glListBase -glLoadIdentity -glLoadMatrixd -glLoadMatrixf -glLoadName -glLogicOp -glMap1d -glMap1f -glMap2d -glMap2f -glMapGrid1d -glMapGrid1f -glMapGrid2d -glMapGrid2f -glMaterialf -glMaterialfv -glMateriali -glMaterialiv -glMatrixMode -GlmfBeginGlsBlock -GlmfCloseMetaFile -GlmfEndGlsBlock -GlmfEndPlayback -GlmfInitPlayback -GlmfPlayGlsRecord -glMultMatrixd -glMultMatrixf -glNewList -glNormal3b -glNormal3bv -glNormal3d -glNormal3dv -glNormal3f -glNormal3fv -glNormal3i -glNormal3iv -glNormal3s -glNormal3sv -glNormalPointer -glOrtho -glPassThrough -glPixelMapfv -glPixelMapuiv -glPixelMapusv -glPixelStoref -glPixelStorei -glPixelTransferf -glPixelTransferi -glPixelZoom -glPointSize -glPolygonMode -glPolygonOffset -glPolygonStipple -glPopAttrib -glPopClientAttrib -glPopMatrix -glPopName -glPrioritizeTextures -glPushAttrib -glPushClientAttrib -glPushMatrix -glPushName -glRasterPos2d -glRasterPos2dv -glRasterPos2f -glRasterPos2fv -glRasterPos2i -glRasterPos2iv -glRasterPos2s -glRasterPos2sv -glRasterPos3d -glRasterPos3dv -glRasterPos3f -glRasterPos3fv -glRasterPos3i -glRasterPos3iv -glRasterPos3s -glRasterPos3sv -glRasterPos4d -glRasterPos4dv -glRasterPos4f -glRasterPos4fv -glRasterPos4i -glRasterPos4iv -glRasterPos4s -glRasterPos4sv -glReadBuffer -glReadPixels -glRectd -glRectdv -glRectf -glRectfv -glRecti -glRectiv -glRects -glRectsv -glRenderMode -glRotated -glRotatef -glScaled -glScalef -glScissor -glSelectBuffer -glShadeModel -glStencilFunc -glStencilMask -glStencilOp -glTexCoord1d -glTexCoord1dv -glTexCoord1f -glTexCoord1fv -glTexCoord1i -glTexCoord1iv -glTexCoord1s -glTexCoord1sv -glTexCoord2d -glTexCoord2dv -glTexCoord2f -glTexCoord2fv -glTexCoord2i -glTexCoord2iv -glTexCoord2s -glTexCoord2sv -glTexCoord3d -glTexCoord3dv -glTexCoord3f -glTexCoord3fv -glTexCoord3i -glTexCoord3iv -glTexCoord3s -glTexCoord3sv -glTexCoord4d -glTexCoord4dv -glTexCoord4f -glTexCoord4fv -glTexCoord4i -glTexCoord4iv -glTexCoord4s -glTexCoord4sv -glTexCoordPointer -glTexEnvf -glTexEnvfv -glTexEnvi -glTexEnviv -glTexGend -glTexGendv -glTexGenf -glTexGenfv -glTexGeni -glTexGeniv -glTexImage1D -glTexImage2D -glTexParameterf -glTexParameterfv -glTexParameteri -glTexParameteriv -glTexSubImage1D -glTexSubImage2D -glTranslated -glTranslatef -glVertex2d -glVertex2dv -glVertex2f -glVertex2fv -glVertex2i -glVertex2iv -glVertex2s -glVertex2sv -glVertex3d -glVertex3dv -glVertex3f -glVertex3fv -glVertex3i -glVertex3iv -glVertex3s -glVertex3sv -glVertex4d -glVertex4dv -glVertex4f -glVertex4fv -glVertex4i -glVertex4iv -glVertex4s -glVertex4sv -glVertexPointer -glViewport -wglChoosePixelFormat -wglCopyContext -wglCreateContext -wglCreateLayerContext -wglDeleteContext -wglDescribeLayerPlane -wglDescribePixelFormat -wglGetCurrentContext -wglGetCurrentDC -wglGetDefaultProcAddress -wglGetLayerPaletteEntries -wglGetPixelFormat -wglGetProcAddress -wglMakeCurrent -wglRealizeLayerPalette -wglSetLayerPaletteEntries -wglSetPixelFormat -wglShareLists -wglSwapBuffers -wglSwapLayerBuffers -wglSwapMultipleBuffers -wglUseFontBitmapsA -wglUseFontBitmapsW -wglUseFontOutlinesA -wglUseFontOutlinesW -{{end}} \ No newline at end of file diff --git a/gapis/api/templates/opengl32_resolve.cpp.tmpl b/gapis/api/templates/opengl32_resolve.cpp.tmpl deleted file mode 100644 index a5b0033280..0000000000 --- a/gapis/api/templates/opengl32_resolve.cpp.tmpl +++ /dev/null @@ -1,56 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{Include "opengl32_exports.tmpl"}} -{{Include "cpp_common.tmpl"}} -{{$ | Macro "opengl32_resolve.cpp" | Reflow 4 | Write "opengl32_resolve.cpp"}} - -{{/* -------------------------------------------------------------------------------- - Entry point. -------------------------------------------------------------------------------- -*/}} -{{define "opengl32_resolve.cpp"}} - {{/* This is the list of functions that OpenGL32.dll needs to export. */}} - {{$opengl32_exports := Strings (Macro "OpenGL32Exports") | SplitEOL}} - - {{/* This is the list of functions that the spy exports. */}} - {{$api_exports := (ForEach (AllCommands $) "CmdName") | Strings "wglGetProcAddress"}} - - {{/* This is list of functions we need to resolve. */}} - {{$resolve := $opengl32_exports | FilterOut $api_exports}} - - {{Template "C++.Copyright"}} -¶ -#include "core/cc/get_gles_proc_address.h" -¶ -extern "C" {« -¶ - {{range $f := $resolve}} - void* real__{{$f}} = nullptr; - {{end}} -¶ - int resolved = 0; - void __stdcall resolve() { - {{range $f := $resolve}} - real__{{$f}} = core::GetGlesProcAddress("{{$f}}"); - {{end}} - resolved = 1; - } -¶ -»} // extern "C" -¶ -{{end}} diff --git a/gapis/api/templates/opengl32_x64.asm.tmpl b/gapis/api/templates/opengl32_x64.asm.tmpl deleted file mode 100644 index 1c3afe992c..0000000000 --- a/gapis/api/templates/opengl32_x64.asm.tmpl +++ /dev/null @@ -1,98 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{Include "cpp_common.tmpl"}} -{{Include "opengl32_exports.tmpl"}} -{{$ | Macro "opengl32_x64.asm" | Reflow 4 | Write "opengl32_x64.asm"}} - -{{/* -------------------------------------------------------------------------------- - Entry point. -------------------------------------------------------------------------------- -*/}} -{{define "opengl32_x64.asm"}} -; Copyright (C) 2017 Google Inc. -; -; Licensed under the Apache License, Version 2.0 (the "License"); -; you may not use this file except in compliance with the License. -; You may obtain a copy of the License at -; -; http://www.apache.org/licenses/LICENSE-2.0 -; -; Unless required by applicable law or agreed to in writing, software -; distributed under the License is distributed on an "AS IS" BASIS, -; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -; See the License for the specific language governing permissions and -; limitations under the License. -¶ -; This masm exposes trampoline functions for OpenGL 1.1 and WGL functions that -; are expected to be exposed by OpenGL32.dll but not declared by the API files. -¶ -; Lazy resolve all functions, then trampoline to the resolved address -TRAMPOLINE macro FUNC, REAL» - local skip - public FUNC - extern REAL:proc -¶ -«FUNC PROC» - mov eax, resolved - cmp eax, 0 - jnz skip - ; Function are not resolved, resolve now... -¶ - ; Preserve arguments stored in registers (ecx, edx, r8 and r9) - push rcx - push rdx - push r8 - push r9 -¶ - ; give resolve() the necessary 32 byte 'shadow space', and call resolve - sub rsp, 28h - call resolve - add rsp, 28h -¶ - ; Reload argument registers - pop r9 - pop r8 - pop rdx - pop rcx -«skip:» - mov rax, [REAL] - mov rax, [rax] - jmp rax -«FUNC ENDP» - endm -« -¶ -extern resolve:proc -extern resolved:SDWORD -¶ -.CODE - {{/* This is the list of functions that OpenGL32.dll needs to export. */}} - {{$opengl32_exports := Strings (Macro "OpenGL32Exports") | SplitEOL}} - - {{/* This is the list of functions that the spy exports. */}} - {{$api_exports := (ForEach (AllCommands $) "CmdName") | Strings "wglGetProcAddress"}} - - {{/* This is list of functions we need to create trampolines for. */}} - {{$trampolines := $opengl32_exports | FilterOut $api_exports}} - - {{range $f := $trampolines}} - TRAMPOLINE {{$f}}, real__{{$f}} - {{end}} -end -¶ -{{end}} diff --git a/gapis/api/templates/opengl_framework_exports.cpp.tmpl b/gapis/api/templates/opengl_framework_exports.cpp.tmpl deleted file mode 100644 index 578b1a1dc5..0000000000 --- a/gapis/api/templates/opengl_framework_exports.cpp.tmpl +++ /dev/null @@ -1,58 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{Include "opengl_framework_exports.tmpl"}} -{{Include "cpp_common.tmpl"}} -{{$ | Macro "opengl_framework_exports.cpp" | Reflow 4 | Write "opengl_framework_exports.cpp"}} - -{{/* -------------------------------------------------------------------------------- - Entry point. -------------------------------------------------------------------------------- -*/}} -{{define "opengl_framework_exports.cpp"}} - {{/* This is the list of functions that the OpenGL framework needs to export. */}} - {{$opengl_framework_exports := Strings (Macro "OpenGLFrameworkExports") | SplitEOL}} - - {{/* This is the list of functions that the spy exports. */}} - {{$api_exports := (ForEach (AllCommands $) "CmdName")}} - - {{/* This is list of functions we need to expose. */}} - {{$expose := $opengl_framework_exports | FilterOut $api_exports}} - - {{Template "C++.Copyright"}} -¶ -#include "core/cc/get_gles_proc_address.h" -#include "core/cc/target.h" -¶ -extern "C" {« -¶ - {{range $f := $expose}} - static void* real__{{$f}} = nullptr; - EXPORT void __attribute__((naked)) {{$f}}() { - asm("jmp *%%rax" : : "a"(real__{{$f}}) : ); - } - {{end}} -¶ - __attribute__((constructor)) - static void initExports() { - {{range $f := $expose}} - real__{{$f}} = core::GetGlesProcAddress("{{$f}}"); - {{end}} - } -»} // extern "C" -¶ -{{end}} diff --git a/gapis/api/templates/opengl_framework_exports.tmpl b/gapis/api/templates/opengl_framework_exports.tmpl deleted file mode 100644 index 38e5656bd2..0000000000 --- a/gapis/api/templates/opengl_framework_exports.tmpl +++ /dev/null @@ -1,1451 +0,0 @@ -{{/* - * Copyright (C) 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */}} - -{{/* The full list of exported functions from the OpenGL OSX framework */}} -{{define "OpenGLFrameworkExports"}} -CGLAreContextsShared -CGLBackDispatch -CGLChoosePixelFormat -CGLClearDrawable -CGLCopyContext -CGLCreateContext -CGLCreatePBuffer -CGLDescribePBuffer -CGLDescribePixelFormat -CGLDescribeRenderer -CGLDestroyContext -CGLDestroyPBuffer -CGLDestroyPixelFormat -CGLDestroyRendererInfo -CGLDisable -CGLEnable -CGLErrorString -CGLFlushDrawable -CGLFrontDispatch -CGLGetContextRetainCount -CGLGetCurrentContext -CGLGetGlobalOption -CGLGetNextContext -CGLGetOffScreen -CGLGetOption -CGLGetPBuffer -CGLGetPBufferRetainCount -CGLGetParameter -CGLGetPixelFormat -CGLGetPixelFormatRetainCount -CGLGetShareGroup -CGLGetSurface -CGLGetVersion -CGLGetVirtualScreen -CGLIsEnabled -CGLLockContext -CGLOpenCLMuxLockDown -CGLQueryRendererInfo -CGLReleaseContext -CGLReleasePBuffer -CGLReleasePixelFormat -CGLRestoreDispatch -CGLRestoreDispatchFunction -CGLRetainContext -CGLRetainPBuffer -CGLRetainPixelFormat -CGLSelectDispatch -CGLSelectDispatchBounded -CGLSelectDispatchFunction -CGLSetCurrentContext -CGLSetFullScreen -CGLSetFullScreenOnDisplay -CGLSetGlobalOption -CGLSetOffScreen -CGLSetOption -CGLSetPBuffer -CGLSetPBufferVolatileState -CGLSetParameter -CGLSetSurface -CGLSetVirtualScreen -CGLTexImageIOSurface2D -CGLTexImagePBuffer -CGLUnlockContext -CGLUpdateContext -GLCDescribePixelFormat -GLCGetPBuffer -GLCGetParameter -GLCGetProfilerStorage -GLCGetSurface -GLCGetVirtualScreen -GLCSetProfilerStorage -cglBadApplicationNotMuxAwareLockDown -glcDebugListener -glcGetIOAccelService -glcNoop -glcPluginConnect -glcPluginCount -glcPluginDisconnect -glcRecordError - -glAccum -glActiveShaderProgram -glActiveStencilFaceEXT -glActiveTexture -glActiveTextureARB -glAlphaFunc -glAreTexturesResident -glArrayElement -glAttachObjectARB -glAttachShader -glBegin -glBeginConditionalRender -glBeginConditionalRenderNV -glBeginQuery -glBeginQueryARB -glBeginQueryIndexed -glBeginTransformFeedback -glBeginTransformFeedbackEXT -glBindAttribLocation -glBindAttribLocationARB -glBindBuffer -glBindBufferARB -glBindBufferBase -glBindBufferBaseEXT -glBindBufferOffsetEXT -glBindBufferRange -glBindBufferRangeEXT -glBindFragDataLocation -glBindFragDataLocationEXT -glBindFragDataLocationIndexed -glBindFramebuffer -glBindFramebufferEXT -glBindProgramARB -glBindProgramPipeline -glBindRenderbuffer -glBindRenderbufferEXT -glBindSampler -glBindTexture -glBindTransformFeedback -glBindVertexArray -glBindVertexArrayAPPLE -glBitmap -glBlendColor -glBlendColorEXT -glBlendEquation -glBlendEquationEXT -glBlendEquationSeparate -glBlendEquationSeparateATI -glBlendEquationSeparateEXT -glBlendEquationSeparatei -glBlendEquationSeparateiARB -glBlendEquationi -glBlendEquationiARB -glBlendFunc -glBlendFuncSeparate -glBlendFuncSeparateEXT -glBlendFuncSeparatei -glBlendFuncSeparateiARB -glBlendFunci -glBlendFunciARB -glBlitFramebuffer -glBlitFramebufferEXT -glBufferData -glBufferDataARB -glBufferParameteriAPPLE -glBufferSubData -glBufferSubDataARB -glCallList -glCallLists -glCheckFramebufferStatus -glCheckFramebufferStatusEXT -glClampColor -glClampColorARB -glClear -glClearAccum -glClearBufferfi -glClearBufferfv -glClearBufferiv -glClearBufferuiv -glClearColor -glClearColorIiEXT -glClearColorIuiEXT -glClearDepth -glClearDepthf -glClearIndex -glClearStencil -glClientActiveTexture -glClientActiveTextureARB -glClientWaitSync -glClipPlane -glColor3b -glColor3bv -glColor3d -glColor3dv -glColor3f -glColor3fv -glColor3i -glColor3iv -glColor3s -glColor3sv -glColor3ub -glColor3ubv -glColor3ui -glColor3uiv -glColor3us -glColor3usv -glColor4b -glColor4bv -glColor4d -glColor4dv -glColor4f -glColor4fv -glColor4i -glColor4iv -glColor4s -glColor4sv -glColor4ub -glColor4ubv -glColor4ui -glColor4uiv -glColor4us -glColor4usv -glColorMask -glColorMaskIndexedEXT -glColorMaski -glColorMaterial -glColorPointer -glColorSubTable -glColorSubTableEXT -glColorTable -glColorTableEXT -glColorTableParameterfv -glColorTableParameteriv -glCombinerInputNV -glCombinerOutputNV -glCombinerParameterfNV -glCombinerParameterfvNV -glCombinerParameteriNV -glCombinerParameterivNV -glCombinerStageParameterfvNV -glCompileShader -glCompileShaderARB -glCompileShaderIncludeARB -glCompressedTexImage1D -glCompressedTexImage1DARB -glCompressedTexImage2D -glCompressedTexImage2DARB -glCompressedTexImage3D -glCompressedTexImage3DARB -glCompressedTexSubImage1D -glCompressedTexSubImage1DARB -glCompressedTexSubImage2D -glCompressedTexSubImage2DARB -glCompressedTexSubImage3D -glCompressedTexSubImage3DARB -glConvolutionFilter1D -glConvolutionFilter2D -glConvolutionParameterf -glConvolutionParameterfv -glConvolutionParameteri -glConvolutionParameteriv -glCopyBufferSubData -glCopyColorSubTable -glCopyColorTable -glCopyConvolutionFilter1D -glCopyConvolutionFilter2D -glCopyPixels -glCopyTexImage1D -glCopyTexImage2D -glCopyTexSubImage1D -glCopyTexSubImage2D -glCopyTexSubImage3D -glCreateProgram -glCreateProgramObjectARB -glCreateShader -glCreateShaderObjectARB -glCreateShaderProgramv -glCullFace -glDeleteBuffers -glDeleteBuffersARB -glDeleteFencesAPPLE -glDeleteFramebuffers -glDeleteFramebuffersEXT -glDeleteLists -glDeleteNamedStringARB -glDeleteObjectARB -glDeleteProgram -glDeleteProgramPipelines -glDeleteProgramsARB -glDeleteQueries -glDeleteQueriesARB -glDeleteRenderbuffers -glDeleteRenderbuffersEXT -glDeleteSamplers -glDeleteShader -glDeleteSync -glDeleteTextures -glDeleteTransformFeedbacks -glDeleteVertexArrays -glDeleteVertexArraysAPPLE -glDepthBoundsEXT -glDepthFunc -glDepthMask -glDepthRange -glDepthRangeArrayv -glDepthRangeIndexed -glDepthRangef -glDetachObjectARB -glDetachShader -glDisable -glDisableClientState -glDisableIndexedEXT -glDisableVertexAttribAPPLE -glDisableVertexAttribArray -glDisableVertexAttribArrayARB -glDisablei -glDrawArrays -glDrawArraysIndirect -glDrawArraysInstanced -glDrawArraysInstancedARB -glDrawBuffer -glDrawBuffers -glDrawBuffersARB -glDrawElementArrayAPPLE -glDrawElements -glDrawElementsBaseVertex -glDrawElementsIndirect -glDrawElementsInstanced -glDrawElementsInstancedARB -glDrawElementsInstancedBaseVertex -glDrawPixels -glDrawRangeElementArrayAPPLE -glDrawRangeElements -glDrawRangeElementsBaseVertex -glDrawRangeElementsEXT -glDrawTransformFeedback -glDrawTransformFeedbackStream -glEdgeFlag -glEdgeFlagPointer -glEdgeFlagv -glElementPointerAPPLE -glEnable -glEnableClientState -glEnableIndexedEXT -glEnableVertexAttribAPPLE -glEnableVertexAttribArray -glEnableVertexAttribArrayARB -glEnablei -glEnd -glEndConditionalRender -glEndConditionalRenderNV -glEndList -glEndQuery -glEndQueryARB -glEndQueryIndexed -glEndTransformFeedback -glEndTransformFeedbackEXT -glEvalCoord1d -glEvalCoord1dv -glEvalCoord1f -glEvalCoord1fv -glEvalCoord2d -glEvalCoord2dv -glEvalCoord2f -glEvalCoord2fv -glEvalMesh1 -glEvalMesh2 -glEvalPoint1 -glEvalPoint2 -glFeedbackBuffer -glFenceSync -glFinalCombinerInputNV -glFinish -glFinishFenceAPPLE -glFinishObjectAPPLE -glFinishRenderAPPLE -glFlush -glFlushMappedBufferRange -glFlushMappedBufferRangeAPPLE -glFlushRenderAPPLE -glFlushVertexArrayRangeAPPLE -glFogCoordPointer -glFogCoordPointerEXT -glFogCoordd -glFogCoorddEXT -glFogCoorddv -glFogCoorddvEXT -glFogCoordf -glFogCoordfEXT -glFogCoordfv -glFogCoordfvEXT -glFogf -glFogfv -glFogi -glFogiv -glFramebufferRenderbuffer -glFramebufferRenderbufferEXT -glFramebufferTexture -glFramebufferTexture1D -glFramebufferTexture1DEXT -glFramebufferTexture2D -glFramebufferTexture2DEXT -glFramebufferTexture3D -glFramebufferTexture3DEXT -glFramebufferTextureEXT -glFramebufferTextureFaceEXT -glFramebufferTextureLayer -glFramebufferTextureLayerEXT -glFrontFace -glFrustum -glGenBuffers -glGenBuffersARB -glGenFencesAPPLE -glGenFramebuffers -glGenFramebuffersEXT -glGenLists -glGenProgramPipelines -glGenProgramsARB -glGenQueries -glGenQueriesARB -glGenRenderbuffers -glGenRenderbuffersEXT -glGenSamplers -glGenTextures -glGenTransformFeedbacks -glGenVertexArrays -glGenVertexArraysAPPLE -glGenerateMipmap -glGenerateMipmapEXT -glGetActiveAttrib -glGetActiveAttribARB -glGetActiveSubroutineName -glGetActiveSubroutineUniformName -glGetActiveSubroutineUniformiv -glGetActiveUniform -glGetActiveUniformARB -glGetActiveUniformBlockName -glGetActiveUniformBlockiv -glGetActiveUniformName -glGetActiveUniformsiv -glGetAttachedObjectsARB -glGetAttachedShaders -glGetAttribLocation -glGetAttribLocationARB -glGetBooleanIndexedvEXT -glGetBooleani_v -glGetBooleanv -glGetBufferParameteri64v -glGetBufferParameteriv -glGetBufferParameterivARB -glGetBufferPointerv -glGetBufferPointervARB -glGetBufferSubData -glGetBufferSubDataARB -glGetClipPlane -glGetColorTable -glGetColorTableEXT -glGetColorTableParameterfv -glGetColorTableParameterfvEXT -glGetColorTableParameteriv -glGetColorTableParameterivEXT -glGetCombinerInputParameterfvNV -glGetCombinerInputParameterivNV -glGetCombinerOutputParameterfvNV -glGetCombinerOutputParameterivNV -glGetCombinerStageParameterfvNV -glGetCompressedTexImage -glGetCompressedTexImageARB -glGetConvolutionFilter -glGetConvolutionParameterfv -glGetConvolutionParameteriv -glGetDoublei_v -glGetDoublev -glGetError -glGetFinalCombinerInputParameterfvNV -glGetFinalCombinerInputParameterivNV -glGetFloati_v -glGetFloatv -glGetFragDataIndex -glGetFragDataLocation -glGetFragDataLocationEXT -glGetFramebufferAttachmentParameteriv -glGetFramebufferAttachmentParameterivEXT -glGetHandleARB -glGetHistogram -glGetHistogramParameterfv -glGetHistogramParameteriv -glGetInfoLogARB -glGetInteger64i_v -glGetInteger64v -glGetIntegerIndexedvEXT -glGetIntegeri_v -glGetIntegerv -glGetInternalformativ -glGetLightfv -glGetLightiv -glGetMapdv -glGetMapfv -glGetMapiv -glGetMaterialfv -glGetMaterialiv -glGetMinmax -glGetMinmaxParameterfv -glGetMinmaxParameteriv -glGetMultisamplefv -glGetNamedStringARB -glGetNamedStringivARB -glGetObjectLabelEXT -glGetObjectParameterfvARB -glGetObjectParameterivAPPLE -glGetObjectParameterivARB -glGetPixelMapfv -glGetPixelMapuiv -glGetPixelMapusv -glGetPointerv -glGetPolygonStipple -glGetProgramBinary -glGetProgramEnvParameterdvARB -glGetProgramEnvParameterfvARB -glGetProgramInfoLog -glGetProgramLocalParameterdvARB -glGetProgramLocalParameterfvARB -glGetProgramPipelineInfoLog -glGetProgramPipelineiv -glGetProgramStageiv -glGetProgramStringARB -glGetProgramiv -glGetProgramivARB -glGetQueryIndexediv -glGetQueryObjecti64v -glGetQueryObjecti64vEXT -glGetQueryObjectiv -glGetQueryObjectivARB -glGetQueryObjectui64v -glGetQueryObjectui64vEXT -glGetQueryObjectuiv -glGetQueryObjectuivARB -glGetQueryiv -glGetQueryivARB -glGetRenderbufferParameteriv -glGetRenderbufferParameterivEXT -glGetSamplerParameterIiv -glGetSamplerParameterIuiv -glGetSamplerParameterfv -glGetSamplerParameteriv -glGetSeparableFilter -glGetShaderInfoLog -glGetShaderPrecisionFormat -glGetShaderSource -glGetShaderSourceARB -glGetShaderiv -glGetString -glGetStringi -glGetSubroutineIndex -glGetSubroutineUniformLocation -glGetSynciv -glGetTexEnvfv -glGetTexEnviv -glGetTexGendv -glGetTexGenfv -glGetTexGeniv -glGetTexImage -glGetTexLevelParameterfv -glGetTexLevelParameteriv -glGetTexParameterIiv -glGetTexParameterIivEXT -glGetTexParameterIuiv -glGetTexParameterIuivEXT -glGetTexParameterPointervAPPLE -glGetTexParameterfv -glGetTexParameteriv -glGetTransformFeedbackVarying -glGetTransformFeedbackVaryingEXT -glGetUniformBlockIndex -glGetUniformBufferSizeEXT -glGetUniformIndices -glGetUniformLocation -glGetUniformLocationARB -glGetUniformOffsetEXT -glGetUniformSubroutineuiv -glGetUniformdv -glGetUniformfv -glGetUniformfvARB -glGetUniformiv -glGetUniformivARB -glGetUniformuiv -glGetUniformuivEXT -glGetVertexAttribIiv -glGetVertexAttribIivEXT -glGetVertexAttribIuiv -glGetVertexAttribIuivEXT -glGetVertexAttribLdv -glGetVertexAttribPointerv -glGetVertexAttribPointervARB -glGetVertexAttribdv -glGetVertexAttribdvARB -glGetVertexAttribfv -glGetVertexAttribfvARB -glGetVertexAttribiv -glGetVertexAttribivARB -glHint -glHistogram -glIndexMask -glIndexPointer -glIndexd -glIndexdv -glIndexf -glIndexfv -glIndexi -glIndexiv -glIndexs -glIndexsv -glIndexub -glIndexubv -glInitNames -glInsertEventMarkerEXT -glInterleavedArrays -glIsBuffer -glIsBufferARB -glIsEnabled -glIsEnabledIndexedEXT -glIsEnabledi -glIsFenceAPPLE -glIsFramebuffer -glIsFramebufferEXT -glIsList -glIsNamedStringARB -glIsProgram -glIsProgramARB -glIsProgramPipeline -glIsQuery -glIsQueryARB -glIsRenderbuffer -glIsRenderbufferEXT -glIsSampler -glIsShader -glIsSync -glIsTexture -glIsTransformFeedback -glIsVertexArray -glIsVertexArrayAPPLE -glIsVertexAttribEnabledAPPLE -glLabelObjectEXT -glLabelObjectWithResponsibleProcessAPPLE -glLightModelf -glLightModelfv -glLightModeli -glLightModeliv -glLightf -glLightfv -glLighti -glLightiv -glLineStipple -glLineWidth -glLinkProgram -glLinkProgramARB -glListBase -glLoadIdentity -glLoadMatrixd -glLoadMatrixf -glLoadName -glLoadTransposeMatrixd -glLoadTransposeMatrixdARB -glLoadTransposeMatrixf -glLoadTransposeMatrixfARB -glLockArraysEXT -glLogicOp -glMap1d -glMap1f -glMap2d -glMap2f -glMapBuffer -glMapBufferARB -glMapBufferRange -glMapGrid1d -glMapGrid1f -glMapGrid2d -glMapGrid2f -glMapVertexAttrib1dAPPLE -glMapVertexAttrib1fAPPLE -glMapVertexAttrib2dAPPLE -glMapVertexAttrib2fAPPLE -glMaterialf -glMaterialfv -glMateriali -glMaterialiv -glMatrixMode -glMinSampleShading -glMinSampleShadingARB -glMinmax -glMultMatrixd -glMultMatrixf -glMultTransposeMatrixd -glMultTransposeMatrixdARB -glMultTransposeMatrixf -glMultTransposeMatrixfARB -glMultiDrawArrays -glMultiDrawArraysEXT -glMultiDrawElementArrayAPPLE -glMultiDrawElements -glMultiDrawElementsBaseVertex -glMultiDrawElementsEXT -glMultiDrawRangeElementArrayAPPLE -glMultiTexCoord1d -glMultiTexCoord1dARB -glMultiTexCoord1dv -glMultiTexCoord1dvARB -glMultiTexCoord1f -glMultiTexCoord1fARB -glMultiTexCoord1fv -glMultiTexCoord1fvARB -glMultiTexCoord1i -glMultiTexCoord1iARB -glMultiTexCoord1iv -glMultiTexCoord1ivARB -glMultiTexCoord1s -glMultiTexCoord1sARB -glMultiTexCoord1sv -glMultiTexCoord1svARB -glMultiTexCoord2d -glMultiTexCoord2dARB -glMultiTexCoord2dv -glMultiTexCoord2dvARB -glMultiTexCoord2f -glMultiTexCoord2fARB -glMultiTexCoord2fv -glMultiTexCoord2fvARB -glMultiTexCoord2i -glMultiTexCoord2iARB -glMultiTexCoord2iv -glMultiTexCoord2ivARB -glMultiTexCoord2s -glMultiTexCoord2sARB -glMultiTexCoord2sv -glMultiTexCoord2svARB -glMultiTexCoord3d -glMultiTexCoord3dARB -glMultiTexCoord3dv -glMultiTexCoord3dvARB -glMultiTexCoord3f -glMultiTexCoord3fARB -glMultiTexCoord3fv -glMultiTexCoord3fvARB -glMultiTexCoord3i -glMultiTexCoord3iARB -glMultiTexCoord3iv -glMultiTexCoord3ivARB -glMultiTexCoord3s -glMultiTexCoord3sARB -glMultiTexCoord3sv -glMultiTexCoord3svARB -glMultiTexCoord4d -glMultiTexCoord4dARB -glMultiTexCoord4dv -glMultiTexCoord4dvARB -glMultiTexCoord4f -glMultiTexCoord4fARB -glMultiTexCoord4fv -glMultiTexCoord4fvARB -glMultiTexCoord4i -glMultiTexCoord4iARB -glMultiTexCoord4iv -glMultiTexCoord4ivARB -glMultiTexCoord4s -glMultiTexCoord4sARB -glMultiTexCoord4sv -glMultiTexCoord4svARB -glNamedStringARB -glNewList -glNormal3b -glNormal3bv -glNormal3d -glNormal3dv -glNormal3f -glNormal3fv -glNormal3i -glNormal3iv -glNormal3s -glNormal3sv -glNormalPointer -glObjectPurgeableAPPLE -glObjectUnpurgeableAPPLE -glOrtho -glPNTrianglesfATI -glPNTrianglesfATIX -glPNTrianglesiATI -glPNTrianglesiATIX -glPassThrough -glPatchParameterfv -glPatchParameteri -glPauseTransformFeedback -glPixelMapfv -glPixelMapuiv -glPixelMapusv -glPixelStoref -glPixelStorei -glPixelTransferf -glPixelTransferi -glPixelZoom -glPointParameterf -glPointParameterfARB -glPointParameterfv -glPointParameterfvARB -glPointParameteri -glPointParameteriNV -glPointParameteriv -glPointParameterivNV -glPointSize -glPointSizePointerAPPLE -glPolygonMode -glPolygonOffset -glPolygonStipple -glPopAttrib -glPopClientAttrib -glPopGroupMarkerEXT -glPopMatrix -glPopName -glPrimitiveRestartIndex -glPrioritizeTextures -glProgramBinary -glProgramEnvParameter4dARB -glProgramEnvParameter4dvARB -glProgramEnvParameter4fARB -glProgramEnvParameter4fvARB -glProgramEnvParameters4fvEXT -glProgramLocalParameter4dARB -glProgramLocalParameter4dvARB -glProgramLocalParameter4fARB -glProgramLocalParameter4fvARB -glProgramLocalParameters4fvEXT -glProgramParameteri -glProgramParameteriEXT -glProgramStringARB -glProgramUniform1d -glProgramUniform1dv -glProgramUniform1f -glProgramUniform1fv -glProgramUniform1i -glProgramUniform1iv -glProgramUniform1ui -glProgramUniform1uiv -glProgramUniform2d -glProgramUniform2dv -glProgramUniform2f -glProgramUniform2fv -glProgramUniform2i -glProgramUniform2iv -glProgramUniform2ui -glProgramUniform2uiv -glProgramUniform3d -glProgramUniform3dv -glProgramUniform3f -glProgramUniform3fv -glProgramUniform3i -glProgramUniform3iv -glProgramUniform3ui -glProgramUniform3uiv -glProgramUniform4d -glProgramUniform4dv -glProgramUniform4f -glProgramUniform4fv -glProgramUniform4i -glProgramUniform4iv -glProgramUniform4ui -glProgramUniform4uiv -glProgramUniformMatrix2dv -glProgramUniformMatrix2fv -glProgramUniformMatrix2x3dv -glProgramUniformMatrix2x3fv -glProgramUniformMatrix2x4dv -glProgramUniformMatrix2x4fv -glProgramUniformMatrix3dv -glProgramUniformMatrix3fv -glProgramUniformMatrix3x2dv -glProgramUniformMatrix3x2fv -glProgramUniformMatrix3x4dv -glProgramUniformMatrix3x4fv -glProgramUniformMatrix4dv -glProgramUniformMatrix4fv -glProgramUniformMatrix4x2dv -glProgramUniformMatrix4x2fv -glProgramUniformMatrix4x3dv -glProgramUniformMatrix4x3fv -glProvokingVertex -glProvokingVertexEXT -glPushAttrib -glPushClientAttrib -glPushGroupMarkerEXT -glPushMatrix -glPushName -glQueryCounter -glRasterPos2d -glRasterPos2dv -glRasterPos2f -glRasterPos2fv -glRasterPos2i -glRasterPos2iv -glRasterPos2s -glRasterPos2sv -glRasterPos3d -glRasterPos3dv -glRasterPos3f -glRasterPos3fv -glRasterPos3i -glRasterPos3iv -glRasterPos3s -glRasterPos3sv -glRasterPos4d -glRasterPos4dv -glRasterPos4f -glRasterPos4fv -glRasterPos4i -glRasterPos4iv -glRasterPos4s -glRasterPos4sv -glReadBuffer -glReadPixels -glRectd -glRectdv -glRectf -glRectfv -glRecti -glRectiv -glRects -glRectsv -glReleaseShaderCompiler -glRenderMode -glRenderbufferStorage -glRenderbufferStorageEXT -glRenderbufferStorageMultisample -glRenderbufferStorageMultisampleEXT -glResetHistogram -glResetMinmax -glResumeTransformFeedback -glRotated -glRotatef -glSampleCoverage -glSampleCoverageARB -glSampleMaski -glSamplePass -glSamplePassARB -glSamplerParameterIiv -glSamplerParameterIuiv -glSamplerParameterf -glSamplerParameterfv -glSamplerParameteri -glSamplerParameteriv -glScaled -glScalef -glScissor -glScissorArrayv -glScissorIndexed -glScissorIndexedv -glSecondaryColor3b -glSecondaryColor3bEXT -glSecondaryColor3bv -glSecondaryColor3bvEXT -glSecondaryColor3d -glSecondaryColor3dEXT -glSecondaryColor3dv -glSecondaryColor3dvEXT -glSecondaryColor3f -glSecondaryColor3fEXT -glSecondaryColor3fv -glSecondaryColor3fvEXT -glSecondaryColor3i -glSecondaryColor3iEXT -glSecondaryColor3iv -glSecondaryColor3ivEXT -glSecondaryColor3s -glSecondaryColor3sEXT -glSecondaryColor3sv -glSecondaryColor3svEXT -glSecondaryColor3ub -glSecondaryColor3ubEXT -glSecondaryColor3ubv -glSecondaryColor3ubvEXT -glSecondaryColor3ui -glSecondaryColor3uiEXT -glSecondaryColor3uiv -glSecondaryColor3uivEXT -glSecondaryColor3us -glSecondaryColor3usEXT -glSecondaryColor3usv -glSecondaryColor3usvEXT -glSecondaryColorPointer -glSecondaryColorPointerEXT -glSelectBuffer -glSeparableFilter2D -glSetFenceAPPLE -glShadeModel -glShaderBinary -glShaderSource -glShaderSourceARB -glStencilFunc -glStencilFuncSeparate -glStencilFuncSeparateATI -glStencilMask -glStencilMaskSeparate -glStencilOp -glStencilOpSeparate -glStencilOpSeparateATI -glSwapAPPLE -glTestFenceAPPLE -glTestObjectAPPLE -glTexBuffer -glTexCoord1d -glTexCoord1dv -glTexCoord1f -glTexCoord1fv -glTexCoord1i -glTexCoord1iv -glTexCoord1s -glTexCoord1sv -glTexCoord2d -glTexCoord2dv -glTexCoord2f -glTexCoord2fv -glTexCoord2i -glTexCoord2iv -glTexCoord2s -glTexCoord2sv -glTexCoord3d -glTexCoord3dv -glTexCoord3f -glTexCoord3fv -glTexCoord3i -glTexCoord3iv -glTexCoord3s -glTexCoord3sv -glTexCoord4d -glTexCoord4dv -glTexCoord4f -glTexCoord4fv -glTexCoord4i -glTexCoord4iv -glTexCoord4s -glTexCoord4sv -glTexCoordPointer -glTexEnvf -glTexEnvfv -glTexEnvi -glTexEnviv -glTexGend -glTexGendv -glTexGenf -glTexGenfv -glTexGeni -glTexGeniv -glTexImage1D -glTexImage2D -glTexImage2DMultisample -glTexImage3D -glTexImage3DMultisample -glTexParameterIiv -glTexParameterIivEXT -glTexParameterIuiv -glTexParameterIuivEXT -glTexParameterf -glTexParameterfv -glTexParameteri -glTexParameteriv -glTexStorage1D -glTexStorage2D -glTexStorage3D -glTexSubImage1D -glTexSubImage2D -glTexSubImage3D -glTextureBarrierNV -glTextureRangeAPPLE -glTransformFeedbackVaryings -glTransformFeedbackVaryingsEXT -glTranslated -glTranslatef -glUniform1d -glUniform1dv -glUniform1f -glUniform1fARB -glUniform1fv -glUniform1fvARB -glUniform1i -glUniform1iARB -glUniform1iv -glUniform1ivARB -glUniform1ui -glUniform1uiEXT -glUniform1uiv -glUniform1uivEXT -glUniform2d -glUniform2dv -glUniform2f -glUniform2fARB -glUniform2fv -glUniform2fvARB -glUniform2i -glUniform2iARB -glUniform2iv -glUniform2ivARB -glUniform2ui -glUniform2uiEXT -glUniform2uiv -glUniform2uivEXT -glUniform3d -glUniform3dv -glUniform3f -glUniform3fARB -glUniform3fv -glUniform3fvARB -glUniform3i -glUniform3iARB -glUniform3iv -glUniform3ivARB -glUniform3ui -glUniform3uiEXT -glUniform3uiv -glUniform3uivEXT -glUniform4d -glUniform4dv -glUniform4f -glUniform4fARB -glUniform4fv -glUniform4fvARB -glUniform4i -glUniform4iARB -glUniform4iv -glUniform4ivARB -glUniform4ui -glUniform4uiEXT -glUniform4uiv -glUniform4uivEXT -glUniformBlockBinding -glUniformBufferEXT -glUniformMatrix2dv -glUniformMatrix2fv -glUniformMatrix2fvARB -glUniformMatrix2x3dv -glUniformMatrix2x3fv -glUniformMatrix2x4dv -glUniformMatrix2x4fv -glUniformMatrix3dv -glUniformMatrix3fv -glUniformMatrix3fvARB -glUniformMatrix3x2dv -glUniformMatrix3x2fv -glUniformMatrix3x4dv -glUniformMatrix3x4fv -glUniformMatrix4dv -glUniformMatrix4fv -glUniformMatrix4fvARB -glUniformMatrix4x2dv -glUniformMatrix4x2fv -glUniformMatrix4x3dv -glUniformMatrix4x3fv -glUniformSubroutinesuiv -glUnlockArraysEXT -glUnmapBuffer -glUnmapBufferARB -glUseProgram -glUseProgramObjectARB -glUseProgramStages -glValidateProgram -glValidateProgramARB -glValidateProgramPipeline -glVertex2d -glVertex2dv -glVertex2f -glVertex2fv -glVertex2i -glVertex2iv -glVertex2s -glVertex2sv -glVertex3d -glVertex3dv -glVertex3f -glVertex3fv -glVertex3i -glVertex3iv -glVertex3s -glVertex3sv -glVertex4d -glVertex4dv -glVertex4f -glVertex4fv -glVertex4i -glVertex4iv -glVertex4s -glVertex4sv -glVertexArrayParameteriAPPLE -glVertexArrayRangeAPPLE -glVertexAttrib1d -glVertexAttrib1dARB -glVertexAttrib1dv -glVertexAttrib1dvARB -glVertexAttrib1f -glVertexAttrib1fARB -glVertexAttrib1fv -glVertexAttrib1fvARB -glVertexAttrib1s -glVertexAttrib1sARB -glVertexAttrib1sv -glVertexAttrib1svARB -glVertexAttrib2d -glVertexAttrib2dARB -glVertexAttrib2dv -glVertexAttrib2dvARB -glVertexAttrib2f -glVertexAttrib2fARB -glVertexAttrib2fv -glVertexAttrib2fvARB -glVertexAttrib2s -glVertexAttrib2sARB -glVertexAttrib2sv -glVertexAttrib2svARB -glVertexAttrib3d -glVertexAttrib3dARB -glVertexAttrib3dv -glVertexAttrib3dvARB -glVertexAttrib3f -glVertexAttrib3fARB -glVertexAttrib3fv -glVertexAttrib3fvARB -glVertexAttrib3s -glVertexAttrib3sARB -glVertexAttrib3sv -glVertexAttrib3svARB -glVertexAttrib4Nbv -glVertexAttrib4NbvARB -glVertexAttrib4Niv -glVertexAttrib4NivARB -glVertexAttrib4Nsv -glVertexAttrib4NsvARB -glVertexAttrib4Nub -glVertexAttrib4NubARB -glVertexAttrib4Nubv -glVertexAttrib4NubvARB -glVertexAttrib4Nuiv -glVertexAttrib4NuivARB -glVertexAttrib4Nusv -glVertexAttrib4NusvARB -glVertexAttrib4bv -glVertexAttrib4bvARB -glVertexAttrib4d -glVertexAttrib4dARB -glVertexAttrib4dv -glVertexAttrib4dvARB -glVertexAttrib4f -glVertexAttrib4fARB -glVertexAttrib4fv -glVertexAttrib4fvARB -glVertexAttrib4iv -glVertexAttrib4ivARB -glVertexAttrib4s -glVertexAttrib4sARB -glVertexAttrib4sv -glVertexAttrib4svARB -glVertexAttrib4ubv -glVertexAttrib4ubvARB -glVertexAttrib4uiv -glVertexAttrib4uivARB -glVertexAttrib4usv -glVertexAttrib4usvARB -glVertexAttribDivisor -glVertexAttribDivisorARB -glVertexAttribI1i -glVertexAttribI1iEXT -glVertexAttribI1iv -glVertexAttribI1ivEXT -glVertexAttribI1ui -glVertexAttribI1uiEXT -glVertexAttribI1uiv -glVertexAttribI1uivEXT -glVertexAttribI2i -glVertexAttribI2iEXT -glVertexAttribI2iv -glVertexAttribI2ivEXT -glVertexAttribI2ui -glVertexAttribI2uiEXT -glVertexAttribI2uiv -glVertexAttribI2uivEXT -glVertexAttribI3i -glVertexAttribI3iEXT -glVertexAttribI3iv -glVertexAttribI3ivEXT -glVertexAttribI3ui -glVertexAttribI3uiEXT -glVertexAttribI3uiv -glVertexAttribI3uivEXT -glVertexAttribI4bv -glVertexAttribI4bvEXT -glVertexAttribI4i -glVertexAttribI4iEXT -glVertexAttribI4iv -glVertexAttribI4ivEXT -glVertexAttribI4sv -glVertexAttribI4svEXT -glVertexAttribI4ubv -glVertexAttribI4ubvEXT -glVertexAttribI4ui -glVertexAttribI4uiEXT -glVertexAttribI4uiv -glVertexAttribI4uivEXT -glVertexAttribI4usv -glVertexAttribI4usvEXT -glVertexAttribIPointer -glVertexAttribIPointerEXT -glVertexAttribL1d -glVertexAttribL1dv -glVertexAttribL2d -glVertexAttribL2dv -glVertexAttribL3d -glVertexAttribL3dv -glVertexAttribL4d -glVertexAttribL4dv -glVertexAttribLPointer -glVertexAttribP1ui -glVertexAttribP1uiv -glVertexAttribP2ui -glVertexAttribP2uiv -glVertexAttribP3ui -glVertexAttribP3uiv -glVertexAttribP4ui -glVertexAttribP4uiv -glVertexAttribPointer -glVertexAttribPointerARB -glVertexBlendARB -glVertexPointSizefAPPLE -glVertexPointer -glViewport -glViewportArrayv -glViewportIndexedf -glViewportIndexedfv -glWaitSync -glWeightPointerARB -glWeightbvARB -glWeightdvARB -glWeightfvARB -glWeightivARB -glWeightsvARB -glWeightubvARB -glWeightuivARB -glWeightusvARB -glWindowPos2d -glWindowPos2dARB -glWindowPos2dv -glWindowPos2dvARB -glWindowPos2f -glWindowPos2fARB -glWindowPos2fv -glWindowPos2fvARB -glWindowPos2i -glWindowPos2iARB -glWindowPos2iv -glWindowPos2ivARB -glWindowPos2s -glWindowPos2sARB -glWindowPos2sv -glWindowPos2svARB -glWindowPos3d -glWindowPos3dARB -glWindowPos3dv -glWindowPos3dvARB -glWindowPos3f -glWindowPos3fARB -glWindowPos3fv -glWindowPos3fvARB -glWindowPos3i -glWindowPos3iARB -glWindowPos3iv -glWindowPos3ivARB -glWindowPos3s -glWindowPos3sARB -glWindowPos3sv -glWindowPos3svARB - -gluBeginCurve -gluBeginPolygon -gluBeginSurface -gluBeginTrim -gluBuild1DMipmapLevels -gluBuild1DMipmapLevelsCTX -gluBuild1DMipmaps -gluBuild2DMipmapLevels -gluBuild2DMipmapLevelsCTX -gluBuild2DMipmaps -gluBuild2DMipmapsCTX -gluBuild3DMipmapLevels -gluBuild3DMipmapLevelsCTX -gluBuild3DMipmaps -gluBuild3DMipmapsCTX -gluCheckExtension -gluCylinder -gluCylinderCTX -gluDeleteNurbsRenderer -gluDeleteQuadric -gluDeleteTess -gluDisk -gluDiskCTX -gluEndCurve -gluEndPolygon -gluEndSurface -gluEndTrim -gluErrorString -gluGetNurbsProperty -gluGetString -gluGetTessProperty -gluLoadSamplingMatrices -gluLookAt -gluLookAtCTX -gluNewNurbsRenderer -gluNewNurbsRendererCTX -gluNewQuadric -gluNewQuadricCTX -gluNewTess -gluNextContour -gluNurbsCallback -gluNurbsCallbackCFM -gluNurbsCallbackData -gluNurbsCallbackDataEXT -gluNurbsCurve -gluNurbsProperty -gluNurbsSurface -gluOrtho2D -gluOrtho2DCTX -gluPartialDisk -gluPartialDiskCTX -gluPerspective -gluPerspectiveCTX -gluPickMatrix -gluPickMatrixCTX -gluProject -gluPwlCurve -gluQuadricCallback -gluQuadricCallbackCFM -gluQuadricDrawStyle -gluQuadricNormals -gluQuadricOrientation -gluQuadricTexture -gluScaleImage -gluScaleImageCTX -gluSphere -gluSphereCTX -gluTessBeginContour -gluTessBeginPolygon -gluTessCallback -gluTessCallbackCFM -gluTessEndContour -gluTessEndPolygon -gluTessNormal -gluTessProperty -gluTessVertex -gluUnProject -gluUnProject4 -{{end}} \ No newline at end of file From a33bdcb1e173d99375171da0366181ba02bbf15a Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 10 Apr 2020 17:50:04 -0700 Subject: [PATCH 0236/1218] Cleanup/simplification of device info C++ code. --- core/os/android/adb/device.go | 4 +- .../os/device/deviceinfo/cc/android/query.cpp | 237 +++--------------- core/os/device/deviceinfo/cc/cpu.cpp | 84 ++++--- core/os/device/deviceinfo/cc/linux/query.cpp | 88 ++----- core/os/device/deviceinfo/cc/osx/query.mm | 107 +++----- core/os/device/deviceinfo/cc/query.cpp | 62 ++--- core/os/device/deviceinfo/cc/query.h | 48 ++-- .../os/device/deviceinfo/cc/windows/query.cpp | 132 ++++------ 8 files changed, 250 insertions(+), 512 deletions(-) diff --git a/core/os/android/adb/device.go b/core/os/android/adb/device.go index c5f4c00997..83408eefd7 100644 --- a/core/os/android/adb/device.go +++ b/core/os/android/adb/device.go @@ -242,7 +242,9 @@ func newDevice(ctx context.Context, serial string, status bind.Status) (*binding d.To.Configuration.Hardware == nil { return nil, log.Errf(ctx, nil, "Cannot get device information") } - d.Instance().Name = d.To.Configuration.Hardware.Name + if d.Instance().GetName() == "" { + d.Instance().Name = d.To.Configuration.Hardware.Name + } if i := d.Instance(); i.ID == nil || allZero(i.ID.Data) { // Generate an identifier for the device based on it's details. i.GenID() diff --git a/core/os/device/deviceinfo/cc/android/query.cpp b/core/os/device/deviceinfo/cc/android/query.cpp index 49d74123a8..7757215474 100644 --- a/core/os/device/deviceinfo/cc/android/query.cpp +++ b/core/os/device/deviceinfo/cc/android/query.cpp @@ -118,38 +118,26 @@ void abiByName(const std::string name, device::ABI* abi) { } } +typedef struct { + int major, minor; +} AndroidVersion; + +const AndroidVersion kVersionBySdk[] = { + {0, 0}, {1, 0}, {1, 1}, {1, 5}, {1, 6}, /* 0- 4 */ + {2, 0}, {2, 0}, {2, 1}, {2, 2}, {2, 3}, /* 5- 9 */ + {2, 3}, {3, 0}, {3, 1}, {3, 2}, {4, 0}, /* 10-14 */ + {4, 0}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, /* 15-19 */ + {4, 4}, {5, 0}, {5, 1}, {6, 0}, {7, 0}, /* 20-24 */ + {7, 1}, {8, 0}, {8, 1}, {9, 0}, {10, 0}, /* 25-29*/ + {11, 0}}; +constexpr int kMaxKnownSdk = (sizeof(kVersionBySdk) / sizeof(AndroidVersion)); + } // anonymous namespace namespace query { -struct Context { - int mNumCores; - std::string mHost; - std::string mHardware; - std::string mOSName; - std::string mOSBuild; - int mOSVersion; - int mOSVersionMajor; - int mOSVersionMinor; - std::vector mSupportedABIs; - device::Architecture mCpuArchitecture; -}; - -static Context gContext; -static int gContextRefCount = 0; - -void destroyContext() { - if (--gContextRefCount > 0) { - return; - } -} - -bool createContext(std::string* errorMsg) { - if (gContextRefCount++ > 0) { - return true; - } - - gContext.mNumCores = 0; +bool queryPlatform(PlatformInfo* info, std::string* errorMsg) { + info->numCpuCores = 0; #define GET_PROP(name, trans) \ do { \ @@ -157,7 +145,6 @@ bool createContext(std::string* errorMsg) { if (__system_property_get(name, _v) == 0) { \ errorMsg->append("Failed reading property "); \ errorMsg->append(name); \ - destroyContext(); \ return false; \ } \ trans; \ @@ -177,161 +164,47 @@ bool createContext(std::string* errorMsg) { std::string manufacturer; std::string model; - - GET_STRING_LIST_PROP("ro.product.cpu.abilist", gContext.mSupportedABIs); - GET_STRING_PROP("ro.build.host", gContext.mHost); GET_STRING_PROP("ro.product.manufacturer", manufacturer); GET_STRING_PROP("ro.product.model", model); - GET_STRING_PROP("ro.hardware", gContext.mHardware); - GET_STRING_PROP("ro.build.display.id", gContext.mOSBuild); - + GET_STRING_PROP("ro.hardware", info->hardwareName); if (model != "") { if (manufacturer != "") { - gContext.mHardware = manufacturer + " " + model; + info->name = manufacturer + " " + model; } else { - gContext.mHardware = model; + info->name = model; } + } else { + info->name = info->hardwareName; } - GET_STRING_PROP("ro.build.version.release", gContext.mOSName); - GET_INT_PROP("ro.build.version.sdk", gContext.mOSVersion); + std::vector supportedABIs; + GET_STRING_LIST_PROP("ro.product.cpu.abilist", supportedABIs); + info->abis.resize(supportedABIs.size()); + for (size_t i = 0; i < supportedABIs.size(); i++) { + abiByName(supportedABIs[i], &info->abis[i]); + } + + info->numCpuCores = 0; + + info->osKind = device::Android; + GET_STRING_PROP("ro.build.version.release", info->osName); + GET_STRING_PROP("ro.build.display.id", info->osBuild); + int sdkVersion = 0; + GET_INT_PROP("ro.build.version.sdk", sdkVersion); // preview_sdk is used to determine the version for the next OS release // Until the official release, the new OS releases will use the same sdk // version as the previous OS while setting the preview_sdk int previewSdk = 0; GET_INT_PROP("ro.build.version.preview_sdk", previewSdk); - gContext.mOSVersion += previewSdk; - - if (gContext.mSupportedABIs.size() > 0) { - auto primaryABI = gContext.mSupportedABIs[0]; - if (primaryABI == "armeabi-v7a") { - gContext.mCpuArchitecture = device::ARMv7a; - } else if (primaryABI == "arm64-v8a") { - gContext.mCpuArchitecture = device::ARMv8a; - } else if (primaryABI == "x86") { - gContext.mCpuArchitecture = device::X86; - } else if (primaryABI == "x86_64") { - gContext.mCpuArchitecture = device::X86_64; - } else { - LOG_WARN("Unrecognised ABI: %s", primaryABI.c_str()); - } - } - - switch (gContext.mOSVersion) { - case 30: // Android 11 - gContext.mOSVersionMajor = 11; - gContext.mOSVersionMinor = 0; - break; - case 29: // Android 10 - gContext.mOSVersionMajor = 10; - gContext.mOSVersionMinor = 0; - break; - case 28: // Pie - gContext.mOSVersionMajor = 9; - gContext.mOSVersionMinor = 0; - break; - case 27: // Oreo - gContext.mOSVersionMajor = 8; - gContext.mOSVersionMinor = 1; - break; - case 26: // Oreo - gContext.mOSVersionMajor = 8; - gContext.mOSVersionMinor = 0; - break; - case 25: // Nougat - gContext.mOSVersionMajor = 7; - gContext.mOSVersionMinor = 1; - break; - case 24: // Nougat - gContext.mOSVersionMajor = 7; - gContext.mOSVersionMinor = 0; - break; - case 23: // Marshmallow - gContext.mOSVersionMajor = 6; - gContext.mOSVersionMinor = 0; - break; - case 22: // Lollipop - gContext.mOSVersionMajor = 5; - gContext.mOSVersionMinor = 1; - break; - case 21: // Lollipop - gContext.mOSVersionMajor = 5; - gContext.mOSVersionMinor = 0; - break; - case 19: // KitKat - gContext.mOSVersionMajor = 4; - gContext.mOSVersionMinor = 4; - break; - case 18: // Jelly Bean - gContext.mOSVersionMajor = 4; - gContext.mOSVersionMinor = 3; - break; - case 17: // Jelly Bean - gContext.mOSVersionMajor = 4; - gContext.mOSVersionMinor = 2; - break; - case 16: // Jelly Bean - gContext.mOSVersionMajor = 4; - gContext.mOSVersionMinor = 1; - break; - case 15: // Ice Cream Sandwich - case 14: // Ice Cream Sandwich - gContext.mOSVersionMajor = 4; - gContext.mOSVersionMinor = 0; - break; - case 13: // Honeycomb - gContext.mOSVersionMajor = 3; - gContext.mOSVersionMinor = 2; - break; - case 12: // Honeycomb - gContext.mOSVersionMajor = 3; - gContext.mOSVersionMinor = 1; - break; - case 11: // Honeycomb - gContext.mOSVersionMajor = 3; - gContext.mOSVersionMinor = 0; - break; - case 10: // Gingerbread - case 9: // Gingerbread - gContext.mOSVersionMajor = 2; - gContext.mOSVersionMinor = 3; - break; - case 8: // Froyo - gContext.mOSVersionMajor = 2; - gContext.mOSVersionMinor = 2; - break; - case 7: // Eclair - gContext.mOSVersionMajor = 2; - gContext.mOSVersionMinor = 1; - break; - case 6: // Eclair - case 5: // Eclair - gContext.mOSVersionMajor = 2; - gContext.mOSVersionMinor = 0; - break; - case 4: // Donut - gContext.mOSVersionMajor = 1; - gContext.mOSVersionMinor = 6; - break; - case 3: // Cupcake - gContext.mOSVersionMajor = 1; - gContext.mOSVersionMinor = 5; - break; - case 2: // (no code name) - gContext.mOSVersionMajor = 1; - gContext.mOSVersionMinor = 1; - break; - case 1: // (no code name) - gContext.mOSVersionMajor = 1; - gContext.mOSVersionMinor = 0; - break; + sdkVersion += previewSdk; + if (sdkVersion >= 0 && sdkVersion < kMaxKnownSdk) { + info->osMajor = kVersionBySdk[sdkVersion].major; + info->osMinor = kVersionBySdk[sdkVersion].minor; } return true; } -int numABIs() { return gContext.mSupportedABIs.size(); } - device::ABI* currentABI() { device::ABI* out = new device::ABI(); #if defined(__arm__) @@ -348,38 +221,6 @@ device::ABI* currentABI() { return out; } -void abi(int idx, device::ABI* abi) { - return abiByName(gContext.mSupportedABIs[idx], abi); -} - -int cpuNumCores() { return gContext.mNumCores; } - -const char* cpuName() { return ""; } - -const char* cpuVendor() { return ""; } - -device::Architecture cpuArchitecture() { return gContext.mCpuArchitecture; } - -const char* gpuName() { return ""; } - -const char* gpuVendor() { return ""; } - -const char* instanceName() { return gContext.mHardware.c_str(); } - -const char* hardwareName() { return gContext.mHardware.c_str(); } - -device::OSKind osKind() { return device::Android; } - -const char* osName() { return gContext.mOSName.c_str(); } - -const char* osBuild() { return gContext.mOSBuild.c_str(); } - -int osMajor() { return gContext.mOSVersionMajor; } - -int osMinor() { return gContext.mOSVersionMinor; } - -int osPoint() { return 0; } - device::VulkanProfilingLayers* get_vulkan_profiling_layers() { auto layers = new device::VulkanProfilingLayers(); layers->set_cpu_timing(true); diff --git a/core/os/device/deviceinfo/cc/cpu.cpp b/core/os/device/deviceinfo/cc/cpu.cpp index fc163948d6..a0e89d7ca9 100644 --- a/core/os/device/deviceinfo/cc/cpu.cpp +++ b/core/os/device/deviceinfo/cc/cpu.cpp @@ -18,13 +18,10 @@ #include "core/cc/target.h" -#if (defined(__x86_64) || defined(__i386)) && (TARGET_OS != GAPID_OS_ANDROID) -#if !defined(_MSC_VER) || defined(__GNUC__) +#if (defined(__x86_64) || defined(__i386)) #include -namespace query { - -const char* cpuName() { +bool query::queryCpu(CpuInfo* info, std::string* error) { static union { uint32_t reg[12]; char str[49]; @@ -32,41 +29,70 @@ const char* cpuName() { if (__get_cpuid(0x80000002, ®[0], ®[1], ®[2], ®[3]) && __get_cpuid(0x80000003, ®[4], ®[5], ®[6], ®[7]) && __get_cpuid(0x80000004, ®[8], ®[9], ®[10], ®[11])) { - return str; + info->name = str; + } else { + error->append("Failed to query CPUID"); + return false; } - return ""; -} -const char* cpuVendor() { - static union { - uint32_t reg[3]; - char str[13]; - }; + str[12] = 0; // In case the below 12 byte vendor name uses exactly 12 chars. uint32_t eax = 0; if (__get_cpuid(0, &eax, ®[0], ®[2], ®[1])) { - return str; + info->vendor = str; + } else { + error->append("Failed to query CPUID"); + return false; } - return ""; + + info->architecture = device::X86_64; + return true; } -device::Architecture cpuArchitecture() { return device::X86_64; } +#elif ((defined(__arm__) || defined(__aarch64__)) && \ + TARGET_OS == GAPID_OS_ANDROID) +#include +#include -} // namespace query -#else // !defined(_MSC_VER) || defined(__GNUC__) -// If we are using MSVC (rather than MSYS) we cannot use __get_cpuid -namespace query { +bool query::queryCpu(CpuInfo* info, std::string* error) { + std::fstream proc("/proc/cpuinfo", std::ios_base::in); + if (proc.is_open()) { + std::string line, processor, hardware; + while (std::getline(proc, line)) { + size_t colon = line.rfind(": "); + if (colon == std::string::npos) { + } else if (line.rfind("Hardware") == 0) { + hardware = line.substr(colon + 2); + } else if (line.rfind("Processor") == 0) { + processor = line.substr(colon + 2); + } + } + proc.close(); -const char* cpuName() { return ""; } + if (hardware != "") { + info->name = hardware; + } else if (processor != "") { + info->name = processor; + } + } -const char* cpuVendor() { return ""; } + if (info->name == "") { + char str[PROP_VALUE_MAX]; + if (__system_property_get("ro.boot.hardware.platform", str) == 0) { + error->append("Failed reading ro.boot.hardware.platform property"); + return false; + } + info->name = str; + } -device::Architecture cpuArchitecture() { -#ifdef _WIN64 - return device::X86_64; -#elif defined _WIN32 - return device::X86; + info->vendor = "ARM"; // TODO: get the implementer? +#ifdef __arm__ + info->architecture = device::ARMv7a; +#else + info->architecture = device::ARMv8a; #endif + return true; } -} // namespace query + +#else +#error Unsupported target architecture. #endif -#endif \ No newline at end of file diff --git a/core/os/device/deviceinfo/cc/linux/query.cpp b/core/os/device/deviceinfo/cc/linux/query.cpp index badb8b5484..0423fc89a0 100644 --- a/core/os/device/deviceinfo/cc/linux/query.cpp +++ b/core/os/device/deviceinfo/cc/linux/query.cpp @@ -33,83 +33,47 @@ #define STR_OR_EMPTY(x) ((x != nullptr) ? x : "") -namespace query { - -struct Context { - int mNumCores; - utsname mUbuf; - char mHostName[512]; -}; +namespace { -static Context gContext; -static int gContextRefCount = 0; - -void destroyContext() { - if (--gContextRefCount > 0) { - return; - } +device::ABI* abi(device::ABI* abi) { + abi->set_name("x86_64"); + abi->set_os(device::Linux); + abi->set_architecture(device::X86_64); + abi->set_allocated_memory_layout(query::currentMemoryLayout()); + return abi; } -bool createContext(std::string* errorMsg) { - if (gContextRefCount++ > 0) { - return true; - } +} // namespace - memset(&gContext, 0, sizeof(gContext)); +namespace query { - if (uname(&gContext.mUbuf) != 0) { - errorMsg->append("uname returned error: " + std::to_string(errno)); - destroyContext(); +bool queryPlatform(PlatformInfo* info, std::string* errorMsg) { + char hostname[HOST_NAME_MAX + 1]; + if (gethostname(hostname, sizeof(hostname)) != 0) { + errorMsg->append("gethostname returned error: " + std::to_string(errno)); return false; } + info->name = hostname; + info->abis.resize(1); + abi(&info->abis[0]); - gContext.mNumCores = sysconf(_SC_NPROCESSORS_CONF); - - if (gethostname(gContext.mHostName, sizeof(gContext.mHostName)) != 0) { - errorMsg->append("gethostname returned error: " + std::to_string(errno)); - destroyContext(); + utsname ubuf; + if (uname(&ubuf) != 0) { + errorMsg->append("uname returned error: " + std::to_string(errno)); return false; } + info->hardwareName = STR_OR_EMPTY(ubuf.machine); - return true; -} - -int numABIs() { return 1; } + info->numCpuCores = sysconf(_SC_NPROCESSORS_CONF); -void abi(int idx, device::ABI* abi) { - abi->set_name("x86_64"); - abi->set_os(device::Linux); - abi->set_architecture(device::X86_64); - abi->set_allocated_memory_layout(currentMemoryLayout()); -} + info->osKind = device::Linux; + info->osName = STR_OR_EMPTY(ubuf.release); + info->osBuild = STR_OR_EMPTY(ubuf.version); -device::ABI* currentABI() { - auto out = new device::ABI(); - abi(0, out); - return out; + return true; } -int cpuNumCores() { return gContext.mNumCores; } - -const char* gpuName() { return ""; } - -const char* gpuVendor() { return ""; } - -const char* instanceName() { return gContext.mHostName; } - -const char* hardwareName() { return STR_OR_EMPTY(gContext.mUbuf.machine); } - -device::OSKind osKind() { return device::Linux; } - -const char* osName() { return STR_OR_EMPTY(gContext.mUbuf.release); } - -const char* osBuild() { return STR_OR_EMPTY(gContext.mUbuf.version); } - -int osMajor() { return 0; } - -int osMinor() { return 0; } - -int osPoint() { return 0; } +device::ABI* currentABI() { return abi(new device::ABI()); } device::VulkanProfilingLayers* get_vulkan_profiling_layers() { auto layers = new device::VulkanProfilingLayers(); diff --git a/core/os/device/deviceinfo/cc/osx/query.mm b/core/os/device/deviceinfo/cc/osx/query.mm index 9facb434bf..7e2f60a4e6 100644 --- a/core/os/device/deviceinfo/cc/osx/query.mm +++ b/core/os/device/deviceinfo/cc/osx/query.mm @@ -25,99 +25,62 @@ #define STR_OR_EMPTY(x) ((x != nullptr) ? x : "") -namespace query { - -struct Context { - NSOperatingSystemVersion mOsVersion; - int mNumCores; - char* mHwModel; - char mHostName[512]; -}; +namespace { -static Context gContext; -static int gContextRefCount = 0; +device::ABI* abi(device::ABI* abi) { + abi->set_name("x86_64"); + abi->set_os(device::OSX); + abi->set_architecture(device::X86_64); + abi->set_allocated_memory_layout(query::currentMemoryLayout()); + return abi; +} -void destroyContext() { - if (--gContextRefCount > 0) { - return; - } +} // namespace - if (gContext.mHwModel) { - delete[] gContext.mHwModel; - } -} +namespace query { -bool createContext(std::string* errorMsg) { - if (gContextRefCount++ > 0) { - return true; +bool queryPlatform(PlatformInfo* info, std::string* errorMsg) { + char hostname[256]; + if (gethostname(hostname, sizeof(hostname)) != 0) { + errorMsg->append("gethostname returned error: " + std::to_string(errno)); + return false; } - - memset(&gContext, 0, sizeof(gContext)); + info->name = hostname; + info->abis.resize(1); + abi(&info->abis[0]); size_t len = 0; int mib[2] = {CTL_HW, HW_MODEL}; - sysctl(mib, 2, nullptr, &len, nullptr, 0); - gContext.mHwModel = new char[len]; - if (sysctl(mib, 2, gContext.mHwModel, &len, nullptr, 0) != 0) { + if (sysctl(mib, 2, nullptr, &len, nullptr, 0) != 0) { errorMsg->append("sysctl {CTL_HW, HW_MODEL} returned error: " + std::to_string(errno)); - destroyContext(); return false; } - - len = sizeof(gContext.mNumCores); - if (sysctlbyname("hw.logicalcpu_max", &gContext.mNumCores, &len, nullptr, 0) != 0) { - errorMsg->append("sysctlbyname 'hw.logicalcpu_max' returned error: " + std::to_string(errno)); - destroyContext(); + char* hwModel = new char[len]; + if (sysctl(mib, 2, hwModel, &len, nullptr, 0) != 0) { + errorMsg->append("sysctl {CTL_HW, HW_MODEL} returned error: " + std::to_string(errno)); + delete[] hwModel; return false; } + info->hardwareName = hwModel; + delete[] hwModel; - if (gethostname(gContext.mHostName, sizeof(gContext.mHostName)) != 0) { - errorMsg->append("gethostname returned error: " + std::to_string(errno)); - destroyContext(); + len = sizeof(info->numCpuCores); + if (sysctlbyname("hw.logicalcpu_max", &info->numCpuCores, &len, nullptr, 0) != 0) { + errorMsg->append("sysctlbyname 'hw.logicalcpu_max' returned error: " + std::to_string(errno)); return false; } - gContext.mOsVersion = [[NSProcessInfo processInfo] operatingSystemVersion]; + NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; + info->osKind = device::OSX; + info->osName = "OSX"; + info->osMajor = version.majorVersion; + info->osMinor = version.minorVersion; + info->osPoint = version.patchVersion; return true; } -int numABIs() { return 1; } - -void abi(int idx, device::ABI* abi) { - abi->set_name("x86_64"); - abi->set_os(device::OSX); - abi->set_architecture(device::X86_64); - abi->set_allocated_memory_layout(currentMemoryLayout()); -} - -device::ABI* currentABI() { - auto out = new device::ABI(); - abi(0, out); - return out; -} - -int cpuNumCores() { return gContext.mNumCores; } - -const char* gpuName() { return ""; } - -const char* gpuVendor() { return ""; } - -const char* instanceName() { return gContext.mHostName; } - -const char* hardwareName() { return STR_OR_EMPTY(gContext.mHwModel); } - -device::OSKind osKind() { return device::OSX; } - -const char* osName() { return "OSX"; } - -const char* osBuild() { return ""; } - -int osMajor() { return gContext.mOsVersion.majorVersion; } - -int osMinor() { return gContext.mOsVersion.minorVersion; } - -int osPoint() { return gContext.mOsVersion.patchVersion; } +device::ABI* currentABI() { return abi(new device::ABI()); } device::VulkanProfilingLayers* get_vulkan_profiling_layers() { return nullptr; } diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index 346b2b0411..8a52ea17d7 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -19,8 +19,6 @@ #include #include -#include - namespace { inline bool isLittleEndian() { @@ -80,24 +78,27 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { using namespace device; using namespace google::protobuf::io; - if (!query::createContext(error)) { + PlatformInfo osInfo; + CpuInfo cpuInfo; + if (!query::queryPlatform(&osInfo, error) || + !query::queryCpu(&cpuInfo, error)) { return nullptr; } // OS auto os = new OS(); - os->set_kind(query::osKind()); - os->set_name(query::osName()); - os->set_build(query::osBuild()); - os->set_major_version(query::osMajor()); - os->set_minor_version(query::osMinor()); - os->set_point_version(query::osPoint()); + os->set_kind(osInfo.osKind); + os->set_name(osInfo.osName); + os->set_build(osInfo.osBuild); + os->set_major_version(osInfo.osMajor); + os->set_minor_version(osInfo.osMinor); + os->set_point_version(osInfo.osPoint); // Instance.Configuration.Drivers auto drivers = new Drivers(); - const char* backupVendor = ""; // TODO: we no longer have a backup for this - const char* backupName = ""; + std::string gpuVendor = ""; + std::string gpuName = ""; // Checks if the device supports Vulkan (have Vulkan loader) first, then // populates the VulkanDriver message. @@ -109,7 +110,7 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { if (opt.vulkan.query_physical_devices()) { query::vkPhysicalDevices(vulkan_driver); if (vulkan_driver->physical_devices_size() > 0) { - backupName = vulkan_driver->physical_devices(0).device_name().c_str(); + gpuName = vulkan_driver->physical_devices(0).device_name(); } } drivers->set_allocated_vulkan(vulkan_driver); @@ -117,27 +118,19 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { // Instance.Configuration.Hardware.CPU auto cpu = new CPU(); - cpu->set_name(query::cpuName()); - cpu->set_vendor(query::cpuVendor()); - cpu->set_architecture(query::cpuArchitecture()); - cpu->set_cores(query::cpuNumCores()); + cpu->set_name(cpuInfo.name); + cpu->set_vendor(cpuInfo.vendor); + cpu->set_architecture(cpuInfo.architecture); + cpu->set_cores(osInfo.numCpuCores); // Instance.Configuration.Hardware.GPU auto gpu = new GPU(); - const char* gpuName = query::gpuName(); - const char* gpuVendor = query::gpuVendor(); - if (strlen(gpuName) == 0) { - gpuName = backupName; - } - if (strlen(gpuVendor) == 0) { - gpuVendor = backupVendor; - } gpu->set_name(gpuName); gpu->set_vendor(gpuVendor); // Instance.Configuration.Hardware auto hardware = new Hardware(); - hardware->set_name(query::hardwareName()); + hardware->set_name(osInfo.hardwareName); hardware->set_allocated_cpu(cpu); hardware->set_allocated_gpu(gpu); @@ -146,9 +139,7 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { configuration->set_allocated_os(os); configuration->set_allocated_hardware(hardware); configuration->set_allocated_drivers(drivers); - for (int i = 0, c = query::numABIs(); i < c; i++) { - query::abi(i, configuration->add_abis()); - } + *configuration->mutable_abis() = {osInfo.abis.begin(), osInfo.abis.end()}; auto perfetto_config = new PerfettoCapability(); auto vulkan_performance_layers = query::get_vulkan_profiling_layers(); @@ -161,23 +152,10 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { // Instance auto instance = new Instance(); - instance->set_name(query::instanceName()); + instance->set_name(osInfo.name); instance->set_allocated_configuration(configuration); deviceInstanceID(instance); - // Blacklist of OS/Hardware version that means we cannot safely - // destroy the context. - // https://github.com/google/gapid/issues/1867 - bool blacklist = false; - if (std::string(gpuName).find("Vega") != std::string::npos && - std::string(query::osName()).find("Windows 10") != std::string::npos) { - blacklist = true; - } - - if (!blacklist) { - query::destroyContext(); - } - return instance; } diff --git a/core/os/device/deviceinfo/cc/query.h b/core/os/device/deviceinfo/cc/query.h index f4cda39399..c04b11c7c0 100644 --- a/core/os/device/deviceinfo/cc/query.h +++ b/core/os/device/deviceinfo/cc/query.h @@ -114,37 +114,33 @@ bool hasVulkanLoader(); // The functions below are used by getDeviceInstance(), and are implemented // in the target-dependent sub-directories. -bool createContext(std::string* error); -void destroyContext(); +typedef struct { + std::string name; + std::vector abis; + std::string hardwareName; + int numCpuCores; // Fetching this is OS specific, not CPU specific. + device::OSKind osKind; + std::string osName; + std::string osBuild; + int osMajor; + int osMinor; + int osPoint; +} PlatformInfo; + +bool queryPlatform(PlatformInfo* info, std::string* error); -// The functions below require a context to be created. - -int numABIs(); -void abi(int idx, device::ABI* abi); device::ABI* currentABI(); device::MemoryLayout* currentMemoryLayout(); - -const char* hardwareName(); - -const char* cpuName(); -const char* cpuVendor(); -device::Architecture cpuArchitecture(); -int cpuNumCores(); - -const char* gpuName(); -const char* gpuVendor(); - -const char* instanceName(); - -device::OSKind osKind(); -const char* osName(); -const char* osBuild(); -int osMajor(); -int osMinor(); -int osPoint(); - bool hasAtrace(); +// in cpu.cpp +typedef struct { + std::string name; + std::string vendor; + device::Architecture architecture; +} CpuInfo; +bool queryCpu(CpuInfo* info, std::string* error); + } // namespace query #endif // DEVICEINFO_QUERY_H diff --git a/core/os/device/deviceinfo/cc/windows/query.cpp b/core/os/device/deviceinfo/cc/windows/query.cpp index d03308c6b0..ef079c4196 100644 --- a/core/os/device/deviceinfo/cc/windows/query.cpp +++ b/core/os/device/deviceinfo/cc/windows/query.cpp @@ -18,69 +18,54 @@ #include -namespace query { - -struct Context { - int mNumCores; - char mHostName[MAX_COMPUTERNAME_LENGTH * 4 + 1]; // Stored as UTF-8 - OSVERSIONINFOEX mOsVersion; - const char* mOsName; -}; - -static Context gContext; -static int gContextRefCount = 0; - -void destroyContext() { - if (--gContextRefCount > 0) { - return; - } -} - -bool createContext(std::string* errorMsg) { - if (gContextRefCount++ > 0) { - return true; - } - - gContext.mOsVersion.dwOSVersionInfoSize = sizeof(gContext.mOsVersion); - GetVersionEx((OSVERSIONINFO*)(&gContext.mOsVersion)); - int major = gContext.mOsVersion.dwMajorVersion; - int minor = gContext.mOsVersion.dwMinorVersion; - int point = gContext.mOsVersion.dwBuildNumber; - bool isNTWorkstation = - (gContext.mOsVersion.wProductType == VER_NT_WORKSTATION); +namespace { +std::string getOsName(const OSVERSIONINFOEX& version) { + bool isNTWorkstation = version.wProductType == VER_NT_WORKSTATION; + int major = version.dwMajorVersion; + int minor = version.dwMinorVersion; if (major == 10 && isNTWorkstation) { - gContext.mOsName = "Windows 10"; + return "Windows 10"; } else if (major == 10 && !isNTWorkstation) { - gContext.mOsName = "Windows Server 2016 Technical Preview"; + return "Windows Server 2016 Technical Preview"; } else if (major == 6 && minor == 3 && isNTWorkstation) { - gContext.mOsName = "Windows 8.1"; + return "Windows 8.1"; } else if (major == 6 && minor == 3 && !isNTWorkstation) { - gContext.mOsName = "Windows Server 2012 R2"; + return "Windows Server 2012 R2"; } else if (major == 6 && minor == 2 && isNTWorkstation) { - gContext.mOsName = "Windows 8"; + return "Windows 8"; } else if (major == 6 && minor == 2 && !isNTWorkstation) { - gContext.mOsName = "Windows Server 2012"; + return "Windows Server 2012"; } else if (major == 6 && minor == 1 && isNTWorkstation) { - gContext.mOsName = "Windows 7"; + return "Windows 7"; } else if (major == 6 && minor == 1 && !isNTWorkstation) { - gContext.mOsName = "Windows Server 2008 R2"; + return "Windows Server 2008 R2"; } else if (major == 6 && minor == 0 && isNTWorkstation) { - gContext.mOsName = "Windows Vista"; + return "Windows Vista"; } else if (major == 6 && minor == 0 && !isNTWorkstation) { - gContext.mOsName = "Windows Server 2008"; + return "Windows Server 2008"; } else if (major == 5 && minor == 1) { - gContext.mOsName = "Windows XP"; + return "Windows XP"; } else if (major == 5 && minor == 0) { - gContext.mOsName = "Windows 2000"; + return "Windows 2000"; } else { - gContext.mOsName = ""; + return ""; } +} - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - gContext.mNumCores = sysInfo.dwNumberOfProcessors; +device::ABI* abi(device::ABI* abi) { + abi->set_name("x86_64"); + abi->set_os(device::Windows); + abi->set_architecture(device::X86_64); + abi->set_allocated_memory_layout(query::currentMemoryLayout()); + return abi; +} + +} // namespace + +namespace query { +bool queryPlatform(PlatformInfo* info, std::string* errorMsg) { DWORD size = MAX_COMPUTERNAME_LENGTH + 1; WCHAR host_wide[MAX_COMPUTERNAME_LENGTH + 1]; if (!GetComputerNameW(host_wide, &size)) { @@ -88,55 +73,38 @@ bool createContext(std::string* errorMsg) { std::to_string(GetLastError())); return false; } + char hostName[MAX_COMPUTERNAME_LENGTH * 4 + 1]; // Stored as UTF-8 WideCharToMultiByte(CP_UTF8, // CodePage 0, // dwFlags host_wide, // lpWideCharStr -1, // cchWideChar - gContext.mHostName, // lpMultiByteStr - sizeof(gContext.mHostName), // cbMultiByte + hostName, // lpMultiByteStr + sizeof(hostName), // cbMultiByte nullptr, // lpDefaultChar nullptr // lpUsedDefaultChar ); - return true; -} + info->name = hostName; + info->abis.resize(1); + abi(&info->abis[0]); -int numABIs() { return 1; } + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + info->numCpuCores = sysInfo.dwNumberOfProcessors; -void abi(int idx, device::ABI* abi) { - abi->set_name("x86_64"); - abi->set_os(device::Windows); - abi->set_architecture(device::X86_64); - abi->set_allocated_memory_layout(currentMemoryLayout()); -} + info->osKind = device::Windows; + OSVERSIONINFOEX osVersion; + osVersion.dwOSVersionInfoSize = sizeof(osVersion); + GetVersionEx((OSVERSIONINFO*)(&osVersion)); + info->osName = getOsName(osVersion); + info->osMajor = osVersion.dwMajorVersion; + info->osMinor = osVersion.dwMinorVersion; + info->osPoint = osVersion.dwBuildNumber; -device::ABI* currentABI() { - auto out = new device::ABI(); - abi(0, out); - return out; + return true; } -int cpuNumCores() { return gContext.mNumCores; } - -const char* gpuName() { return ""; } - -const char* gpuVendor() { return ""; } - -const char* instanceName() { return gContext.mHostName; } - -const char* hardwareName() { return ""; } - -device::OSKind osKind() { return device::Windows; } - -const char* osName() { return gContext.mOsName; } - -const char* osBuild() { return ""; } - -int osMajor() { return gContext.mOsVersion.dwMajorVersion; } - -int osMinor() { return gContext.mOsVersion.dwMinorVersion; } - -int osPoint() { return gContext.mOsVersion.dwBuildNumber; } +device::ABI* currentABI() { return abi(new device::ABI()); } device::VulkanProfilingLayers* get_vulkan_profiling_layers() { return nullptr; } From 252b02c7112b4a41a6e6f76f66fc20c246feb70d Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 15 Apr 2020 19:07:37 -0700 Subject: [PATCH 0237/1218] Remove GLES layer setup functionality. --- core/os/android/layers.go | 34 +++++---------------------------- gapidapk/deviceinfo.go | 2 +- gapii/client/adb.go | 2 +- gapis/perfetto/android/trace.go | 4 ++-- 4 files changed, 9 insertions(+), 33 deletions(-) diff --git a/core/os/android/layers.go b/core/os/android/layers.go index 588f413dac..817634b062 100644 --- a/core/os/android/layers.go +++ b/core/os/android/layers.go @@ -22,20 +22,6 @@ import ( "github.com/google/gapid/core/log" ) -const eglLayersExt = "EGL_ANDROID_GLES_layers" - -// SupportsGLESLayersViaSystemSettings returns whether the given device supports -// loading GLES layers via the system settings. -func SupportsGLESLayersViaSystemSettings(d Device) bool { - exts := d.Instance().GetConfiguration().GetDrivers().GetOpengl().GetExtensions() - for _, ext := range exts { - if ext == eglLayersExt { - return true - } - } - return false -} - // SupportsVulkanLayersViaSystemSettings returns whether the given device supports // loading Vulkan layers via the system settings. func SupportsVulkanLayersViaSystemSettings(d Device) bool { @@ -44,10 +30,10 @@ func SupportsVulkanLayersViaSystemSettings(d Device) bool { return apiVersion >= 28 } -// SetupLayer initializes d to use either a Vulkan or GLES layer from layerPkgs +// SetupLayer initializes d to use Vulkan layers from layerPkgs // limited to the app with package appPkg using the system settings and returns // a cleanup to remove the layer settings. -func SetupLayers(ctx context.Context, d Device, appPkg string, layerPkgs []string, layers []string, vulkan bool) (app.Cleanup, error) { +func SetupLayers(ctx context.Context, d Device, appPkg string, layerPkgs []string, layers []string) (app.Cleanup, error) { var cleanup app.Cleanup // pushSetting changes a device property for the duration of the trace. pushSetting := func(ns, key, val string) error { @@ -68,21 +54,11 @@ func SetupLayers(ctx context.Context, d Device, appPkg string, layerPkgs []strin return cleanup.Invoke(ctx), err } if len(layers) > 0 { - if vulkan { - if err := pushSetting("global", "gpu_debug_layers", "\""+strings.Join(layers, ":")+"\""); err != nil { - return cleanup.Invoke(ctx), err - } - } else { - if err := pushSetting("global", "gpu_debug_layers_gles", "\""+strings.Join(layers, ":")+"\""); err != nil { - return cleanup.Invoke(ctx), err - } + if err := pushSetting("global", "gpu_debug_layers", "\""+strings.Join(layers, ":")+"\""); err != nil { + return cleanup.Invoke(ctx), err } } else { - if vulkan { - d.DeleteSystemSetting(ctx, "global", "gpu_debug_layers") - } else { - d.DeleteSystemSetting(ctx, "global", "gpu_debug_layers_gles") - } + d.DeleteSystemSetting(ctx, "global", "gpu_debug_layers") } return cleanup, nil diff --git a/gapidapk/deviceinfo.go b/gapidapk/deviceinfo.go index 0e99fe98ed..bf370c3ea7 100644 --- a/gapidapk/deviceinfo.go +++ b/gapidapk/deviceinfo.go @@ -127,7 +127,7 @@ func fetchDeviceInfo(ctx context.Context, d adb.Device) error { } // Set driver package - nextCleanup, err = android.SetupLayers(ctx, d, apk.Name, []string{driver.Package}, []string{}, true) + nextCleanup, err = android.SetupLayers(ctx, d, apk.Name, []string{driver.Package}, []string{}) cleanup = cleanup.Then(nextCleanup) if err != nil { cleanup.Invoke(ctx) diff --git a/gapii/client/adb.go b/gapii/client/adb.go index a0c4459cbb..80fe9a9500 100644 --- a/gapii/client/adb.go +++ b/gapii/client/adb.go @@ -132,7 +132,7 @@ func Start(ctx context.Context, p *android.InstalledPackage, a *android.Activity } log.I(ctx, "Setting up Layer") - cu, err := android.SetupLayers(ctx, d, p.Name, []string{gapidapk.PackageName(abi)}, []string{gapidapk.LayerName(true)}, true) + cu, err := android.SetupLayers(ctx, d, p.Name, []string{gapidapk.PackageName(abi)}, []string{gapidapk.LayerName(true)}) if err != nil { return nil, cleanup.Invoke(ctx), log.Err(ctx, err, "Setting up the layer") } diff --git a/gapis/perfetto/android/trace.go b/gapis/perfetto/android/trace.go index 1ad8625b13..cd51327bce 100644 --- a/gapis/perfetto/android/trace.go +++ b/gapis/perfetto/android/trace.go @@ -82,7 +82,7 @@ func SetupProfileLayersSource(ctx context.Context, d adb.Device, apk *android.In packages = append(packages, gapidapk.PackageName(abi)) } - nextCleanup, err := android.SetupLayers(ctx, d, apk.Name, packages, []string{}, true) + nextCleanup, err := android.SetupLayers(ctx, d, apk.Name, packages, []string{}) cleanup = cleanup.Then(nextCleanup) if err != nil { return cleanup.Invoke(ctx), log.Err(ctx, err, "Failed to setup gpu.renderstages layer packages.") @@ -106,7 +106,7 @@ func setupProfileLayers(ctx context.Context, d adb.Device, driver adb.Driver, pa enabledLayers = append(enabledLayers, renderStageVulkanLayerName) } - cleanup, err := android.SetupLayers(ctx, d, packageName, packages, enabledLayers, true) + cleanup, err := android.SetupLayers(ctx, d, packageName, packages, enabledLayers) if err != nil { return cleanup.Invoke(ctx), log.Err(ctx, err, "Failed to setup gpu.renderstages environment.") } From 1d485d163151f4fff1b4fdb75552873642ab0603 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Wed, 15 Apr 2020 19:10:27 -0700 Subject: [PATCH 0238/1218] Remove the GLES info from the device proto. --- core/os/device/device.proto | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/core/os/device/device.proto b/core/os/device/device.proto index ba0dd871e8..ab994ee7d7 100644 --- a/core/os/device/device.proto +++ b/core/os/device/device.proto @@ -210,32 +210,10 @@ message Instance { // Drivers describes the drivers available on a device. message Drivers { - // The OpenGL or OpenGL ES driver support. - OpenGLDriver opengl = 1; // The Vulkan driver support. VulkanDriver vulkan = 2; } -// OpenGLDriver describes the device driver support for the OpenGL or OpenGL ES -// APIs. -message OpenGLDriver { - // Supported extensions. e.g. "GL_KHR_debug", "GL_EXT_sRGB [...]". - repeated string extensions = 1; - // Driver name. e.g. "Adreno (TM) 320". - string renderer = 2; - // Driver vendor name. e.g. "Qualcomm". - string vendor = 3; - // Renderer version. e.g. "OpenGL ES 3.0 V@53.0 AU@ (CL@)". - string version = 4; - // Value returned by glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT) - uint32 uniform_buffer_alignment = 5; - // Value returned by glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS) - uint32 max_transform_feedback_separate_attribs = 6; - // Value returned by - // glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS) - uint32 max_transform_feedback_interleaved_components = 7; -} - // VulkanDriver describes the device driver support for the Vulkan API. message VulkanDriver { // Enumerated instance layers. From eddecce7858c4512591c3a2eafd9055ef6439a13 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Thu, 16 Apr 2020 12:34:01 -0700 Subject: [PATCH 0239/1218] Get the GPU vendor from the PCI vendor ID. At least for some devices... --- core/os/device/deviceinfo/cc/query.cpp | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/core/os/device/deviceinfo/cc/query.cpp b/core/os/device/deviceinfo/cc/query.cpp index 8a52ea17d7..b7adcb6ac9 100644 --- a/core/os/device/deviceinfo/cc/query.cpp +++ b/core/os/device/deviceinfo/cc/query.cpp @@ -70,6 +70,31 @@ void deviceInstanceID(device::Instance* instance) { delete[] proto_data; } +std::string getVendorName(uint32_t vendorId) { + // A tiny little PCI-ID database. + // (https://pcisig.com/membership/member-companies) + switch (vendorId) { + case 0x1022: + return "AMD"; + case 0x10DE: + return "NVIDIA"; + case 0x13B5: + return "ARM"; + case 0x1AE0: + return "Google"; + case 0x144D: + return "Samsung"; + case 0x14E4: + return "Broadcom"; + case 0x1F96: + return "Intel"; + case 0x5143: + return "Qualcomm"; + default: + return ""; + } +} + } // anonymous namespace namespace query { @@ -110,6 +135,8 @@ device::Instance* getDeviceInstance(const Option& opt, std::string* error) { if (opt.vulkan.query_physical_devices()) { query::vkPhysicalDevices(vulkan_driver); if (vulkan_driver->physical_devices_size() > 0) { + gpuVendor = + getVendorName(vulkan_driver->physical_devices(0).vendor_id()); gpuName = vulkan_driver->physical_devices(0).device_name(); } } From 8dec19fa3575e1dc7f93f85cd0347002218d7b6e Mon Sep 17 00:00:00 2001 From: Hugues Evrard Date: Fri, 17 Apr 2020 14:21:06 +0100 Subject: [PATCH 0240/1218] Update LUCI to recent version (#222) This is needed to get the latest format for Swarming results, and fit with the detection of e.g. expired tasks in test/swarming/collect.sh Bug: b/154297215 --- kokoro/linux/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/linux/build.sh b/kokoro/linux/build.sh index efec0639e5..891155c898 100755 --- a/kokoro/linux/build.sh +++ b/kokoro/linux/build.sh @@ -93,7 +93,7 @@ $SRC/kokoro/linux/package.sh $BUILD_ROOT/out ## # Install LUCI -curl -fsSL -o luci-py.tar.gz https://chromium.googlesource.com/infra/luci/luci-py.git/+archive/0b027452e658080df1f174c403946914443d2aa6.tar.gz +curl -fsSL -o luci-py.tar.gz https://chromium.googlesource.com/infra/luci/luci-py.git/+archive/2128d8d9c36a0e2839afa200cf3da5e6f6ea845a.tar.gz mkdir luci-py tar xzf luci-py.tar.gz --directory luci-py export LUCI_CLIENT_ROOT="$PWD/luci-py/client" From 51801dadfe3f99588571b2171b5e80187fee2058 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Thu, 16 Apr 2020 09:02:38 -0700 Subject: [PATCH 0241/1218] Fix format definition of single and double precision floats --- core/stream/datatype.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/stream/datatype.go b/core/stream/datatype.go index ca3da9463f..fd577333ba 100644 --- a/core/stream/datatype.go +++ b/core/stream/datatype.go @@ -69,9 +69,9 @@ var ( // F16 represents a 16-bit signed, floating-point number. F16 = DataType{Signed: true, Kind: &DataType_Float{&Float{ExponentBits: 5, MantissaBits: 10}}} // F32 represents a 32-bit signed, floating-point number. - F32 = DataType{Signed: true, Kind: &DataType_Float{&Float{ExponentBits: 7, MantissaBits: 24}}} + F32 = DataType{Signed: true, Kind: &DataType_Float{&Float{ExponentBits: 8, MantissaBits: 23}}} // F64 represents a 64-bit signed, floating-point number. - F64 = DataType{Signed: true, Kind: &DataType_Float{&Float{ExponentBits: 10, MantissaBits: 53}}} + F64 = DataType{Signed: true, Kind: &DataType_Float{&Float{ExponentBits: 11, MantissaBits: 52}}} // S16_16 represents a 16.16 bit signed, fixed-point number. S16_16 = DataType{Signed: true, Kind: &DataType_Fixed{&Fixed{IntegerBits: 15, FractionalBits: 16}}} ) From 2eb5f66ee85e350aefbe9e846525671c466242e5 Mon Sep 17 00:00:00 2001 From: Adithya Srinivasan <33076811+silence-do-good@users.noreply.github.com> Date: Fri, 17 Apr 2020 11:19:28 -0700 Subject: [PATCH 0242/1218] Framelifecycle polishes (Updated Perfetto) (#199) Add Framelifecycle polishes --- .../com/google/gapid/models/Perfetto.java | 29 ++- .../perfetto/models/FrameEventsTrack.java | 191 ++++++++++++++---- .../gapid/perfetto/models/FrameInfo.java | 104 ++++++++++ .../google/gapid/perfetto/models/GpuInfo.java | 75 ++----- .../google/gapid/perfetto/models/Track.java | 8 + .../google/gapid/perfetto/models/Tracks.java | 29 +-- .../views/FrameEventsMultiSelectionView.java | 2 +- .../views/FrameEventsSelectionView.java | 36 +++- .../views/FrameEventsSummaryPanel.java | 44 ++-- tools/build/workspace.bzl | 4 +- 10 files changed, 388 insertions(+), 134 deletions(-) create mode 100644 gapic/src/main/com/google/gapid/perfetto/models/FrameInfo.java diff --git a/gapic/src/main/com/google/gapid/models/Perfetto.java b/gapic/src/main/com/google/gapid/models/Perfetto.java index 34acfe5402..1e1ee3e922 100644 --- a/gapic/src/main/com/google/gapid/models/Perfetto.java +++ b/gapic/src/main/com/google/gapid/models/Perfetto.java @@ -33,6 +33,7 @@ import com.google.gapid.perfetto.TimeSpan; import com.google.gapid.perfetto.models.CounterInfo; import com.google.gapid.perfetto.models.CpuInfo; +import com.google.gapid.perfetto.models.FrameInfo; import com.google.gapid.perfetto.models.GpuInfo; import com.google.gapid.perfetto.models.ProcessInfo; import com.google.gapid.perfetto.models.QueryEngine; @@ -92,9 +93,10 @@ protected ListenableFuture doLoad(Path.Capture source) { transformAsync(withStatus("Examining the trace...", examineTrace(data)), $1 -> transformAsync(withStatus("Querying threads...", queryThreads(data)), $2 -> transformAsync(withStatus("Querying GPU info...", queryGpu(data)), $3 -> - transformAsync(withStatus("Querying counters...", queryCounters(data)), $4 -> - transform(withStatus("Enumerating tracks...", enumerateTracks(data)), $5 -> - data.build()))))); + transformAsync(withStatus("Querying Frame info...", queryFrame(data)), $4 -> + transformAsync(withStatus("Querying counters...", queryCounters(data)), $5 -> + transform(withStatus("Enumerating tracks...", enumerateTracks(data)), $6 -> + data.build())))))); } private static ListenableFuture examineTrace(Data.Builder data) { @@ -112,6 +114,10 @@ private static ListenableFuture queryGpu(Data.Builder data) { return GpuInfo.listGpus(data); } + private static ListenableFuture queryFrame(Data.Builder data) { + return FrameInfo.listFrames(data); + } + private static ListenableFuture queryCounters(Data.Builder data) { return CounterInfo.listCounters(data); } @@ -176,19 +182,22 @@ public static class Data { public final ImmutableMap processes; public final ImmutableMap threads; public final GpuInfo gpu; + public final FrameInfo frame; public final ImmutableMap counters; public final VSync vsync; public final TrackConfig tracks; public Data(QueryEngine queries, TimeSpan traceTime, CpuInfo cpu, ImmutableMap processes, ImmutableMap threads, - GpuInfo gpu, ImmutableMap counters, VSync vsync, TrackConfig tracks) { + GpuInfo gpu, FrameInfo frame, ImmutableMap counters, VSync vsync, + TrackConfig tracks) { this.qe = queries; this.traceTime = traceTime; this.cpu = cpu; this.processes = processes; this.threads = threads; this.gpu = gpu; + this.frame = frame; this.counters = counters; this.vsync = vsync; this.tracks = tracks; @@ -201,6 +210,7 @@ public static class Builder { private ImmutableMap processes; private ImmutableMap threads; private GpuInfo gpu = GpuInfo.NONE; + private FrameInfo frame = FrameInfo.NONE; private ImmutableMap counters; private Map> countersByName; private VSync vsync = VSync.EMPTY; @@ -255,6 +265,15 @@ public Builder setGpu(GpuInfo gpu) { return this; } + public FrameInfo getFrame() { + return frame; + } + + public Builder setFrame(FrameInfo frame) { + this.frame = frame; + return this; + } + public ImmutableMap getCounters() { return counters; } @@ -282,7 +301,7 @@ public Builder setVSync(VSync vsync) { public Data build() { return new Data( - qe, traceTime, cpu, processes, threads, gpu, counters, vsync, tracks.build()); + qe, traceTime, cpu, processes, threads, gpu, frame, counters, vsync, tracks.build()); } } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java index 790b169361..d43a35858a 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/FrameEventsTrack.java @@ -25,22 +25,25 @@ import static com.google.gapid.util.MoreFutures.transform; import static com.google.gapid.util.MoreFutures.transformAsync; import static java.lang.String.format; +import static java.util.concurrent.TimeUnit.MICROSECONDS; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gapid.perfetto.TimeSpan; import com.google.gapid.perfetto.views.FrameEventsMultiSelectionView; import com.google.gapid.perfetto.views.FrameEventsSelectionView; import com.google.gapid.perfetto.views.State; -import java.util.Arrays; import org.eclipse.swt.widgets.Composite; +import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.function.Consumer; @@ -51,11 +54,12 @@ // TODO: dedupe code with SliceTrack. public class FrameEventsTrack extends Track.WithQueryEngine{ private static final String BASE_COLUMNS = - "id, ts, dur, category, name, depth, stack_id, parent_stack_id, arg_set_id"; + "id, ts, dur, name, depth, stack_id, parent_stack_id, arg_set_id, " + + "frame_numbers, layer_names"; private static final String SLICES_VIEW = - "select " + BASE_COLUMNS + " from gpu_slice where track_id = %d"; + "select " + BASE_COLUMNS + " from frame_slice where track_id = %d"; private static final String SLICE_SQL = - "select " + BASE_COLUMNS + " from gpu_slice where id = %d"; + "select " + BASE_COLUMNS + " from frame_slice where id = %d"; private static final String SLICES_SQL = "select " + BASE_COLUMNS + " from %s " + "where ts >= %d - dur and ts <= %d order by ts"; @@ -68,8 +72,15 @@ public class FrameEventsTrack extends Track.WithQueryEngine= %d and depth >= %d and depth <= %d"; private static final String RANGE_FOR_IDS_SQL = "select " + BASE_COLUMNS + " from %s where id in (%s)"; + private static final String STAT_TABLE_SQL = + "select frame_numbers, layer_names, queue_to_acquire_time, " + + "acquire_to_latch_time, latch_to_present_time " + + "from frame_slice left join frame_stats " + + "on frame_slice.id = frame_stats.slice_id " + + "where frame_stats.slice_id = %d"; private static final long SIGNAL_MARGIN_NS = 10000; + private static final long FRAMELIFECYCLE_QUANTIZE_CUTOFF = MICROSECONDS.toNanos(500); private final long trackId; @@ -78,7 +89,7 @@ public FrameEventsTrack(QueryEngine qe, long trackId) { this.trackId = trackId; } - public static FrameEventsTrack forBuffer(QueryEngine qe, GpuInfo.Buffer buffer) { + public static FrameEventsTrack forBuffer(QueryEngine qe, FrameInfo.Buffer buffer) { return new FrameEventsTrack(qe, buffer.trackId); } @@ -98,26 +109,28 @@ protected ListenableFuture initialize() { @Override public ListenableFuture computeData(DataRequest req) { - Window window = Window.compute(req, 5); + Window window = Window.compute(req, 5, FRAMELIFECYCLE_QUANTIZE_CUTOFF); return transformAsync(window.update(qe, tableName("window")), $ -> window.quantized ? computeSummary(req, window) : computeSlices(req)); } private ListenableFuture computeSlices(DataRequest req) { return transformAsync(qe.query(slicesSql(req)), res -> - transform(qe.getAllArgs(res.stream().mapToLong(r -> r.getLong(8))), args -> { + transform(qe.getAllArgs(res.stream().mapToLong(r -> r.getLong(7))), args -> { int rows = res.getNumRows(); - Data data = new Data(req, new long[rows], new long[rows], new long[rows], new int[rows], - new String[rows], new String[rows], new ArgSet[rows]); + Data data = new Data(req, new long[rows], new long[rows], new long[rows], + new String[rows], new long[rows][], new String[rows][], new ArgSet[rows]); res.forEachRow((i, row) -> { long start = row.getLong(1); data.ids[i] = row.getLong(0); data.starts[i] = start; data.ends[i] = start + row.getLong(2); - data.categories[i] = row.getString(3); - data.titles[i] = row.getString(4); - data.depths[i] = row.getInt(5); - data.args[i] = args.getOrDefault(row.getLong(8), ArgSet.EMPTY); + data.titles[i] = row.getString(3); + data.args[i] = args.getOrDefault(row.getLong(7), ArgSet.EMPTY); + data.frameNumbers[i] = Arrays.stream(row.getString(8).split(", ")) + .mapToLong(s -> s.isEmpty() ? 0 : Long.parseLong(s)) + .toArray(); + data.layerNames[i] = row.getString(9).split(", ");; }); return data; })); @@ -147,11 +160,31 @@ private String summarySql() { public ListenableFuture getSlice(long id) { return transformAsync(expectOneRow(qe.query(sliceSql(id))), r -> - transform(qe.getArgs(r.getLong(8)), args -> buildSlice(r, args))); + transformAsync(qe.getArgs(r.getLong(7)), args -> + transform(getStats(id, r.getLong(2)), stats -> buildSlice(r, args, stats)))); + } + + private ListenableFuture> getStats(long id, long dur) { + if (dur == 0) { // No stats for instant events + return Futures.immediateFuture(null); + } + return transform(qe.query(statSql(id)), result -> { + Map stats = Maps.newHashMap(); + result.forEachRow((i, row) -> { + stats.put(row.getString(1).split(", ")[i], + new FrameStats(Long.parseLong(row.getString(0).split(", ")[i]), + row.getLong(2), row.getLong(3), row.getLong(4))); + }); + return stats; + }); + } + + private static String statSql(long sliceId) { + return format(STAT_TABLE_SQL, sliceId); } - protected Slice buildSlice(QueryEngine.Row row, ArgSet args) { - return new Slice(row, args, trackId); + protected Slice buildSlice(QueryEngine.Row row, ArgSet args, Map frameStats) { + return new Slice(row, args, frameStats); } private static String sliceSql(long id) { @@ -160,7 +193,7 @@ private static String sliceSql(long id) { public ListenableFuture> getSlices(TimeSpan ts, int minDepth, int maxDepth) { return transform(qe.query(sliceRangeSql(ts, minDepth, maxDepth)), - res -> res.list(($, row) -> buildSlice(row, ArgSet.EMPTY))); + res -> res.list(($, row) -> buildSlice(row, ArgSet.EMPTY, null))); } private String sliceRangeSql(TimeSpan ts, int minDepth, int maxDepth) { @@ -169,7 +202,7 @@ private String sliceRangeSql(TimeSpan ts, int minDepth, int maxDepth) { public ListenableFuture> getSlices(String ids) { return transform(qe.query(sliceRangeForIdsSql(ids)), - res -> res.list(($, row) -> buildSlice(row, ArgSet.EMPTY))); + res -> res.list(($, row) -> buildSlice(row, ArgSet.EMPTY, null))); } private String sliceRangeForIdsSql(String ids) { @@ -186,9 +219,9 @@ public static class Data extends Track.Data { public final long[] ids; public final long[] starts; public final long[] ends; - public final int[] depths; public final String[] titles; - public final String[] categories; + public final long[][] frameNumbers; + public final String[][] layerNames; public final ArgSet[] args; public static enum Kind { @@ -205,14 +238,14 @@ public Data(DataRequest request, long bucketSize, String[] concatedIds, long[] n this.ids = null; this.starts = null; this.ends = null; - this.depths = null; this.titles = null; - this.categories = null; + this.frameNumbers = null; + this.layerNames = null; this.args = null; } - public Data(DataRequest request, long[] ids, long[] starts, long[] ends, int[] depths, - String[] titles, String[] categories, ArgSet[] args) { + public Data(DataRequest request, long[] ids, long[] starts, long[] ends, + String[] titles, long[][] frameNumbers, String[][] layerNames, ArgSet[] args) { super(request); this.kind = Kind.slices; this.bucketSize = 0; @@ -221,9 +254,9 @@ public Data(DataRequest request, long[] ids, long[] starts, long[] ends, int[] d this.ids = ids; this.starts = starts; this.ends = ends; - this.depths = depths; this.titles = titles; - this.categories = categories; + this.frameNumbers = frameNumbers; + this.layerNames = layerNames; this.args = args; } } @@ -234,32 +267,51 @@ public static class Slice implements Selection { public final long dur; public final String name; public final ArgSet args; - public final long trackId; - - public Slice(long id, long time, long dur, String name, long trackId) { + public final long[] frameNumbers; + public final String[] layerNames; + // Map of each buffer(layerName) that contributed to the displayed frame, to + // its corresponding FrameStats + public final Map frameStats; + public final FrameSelection frameSelection; + + public Slice(long id, long time, long dur, String name, String frameNumbers, + String layerNames, Map frameStats) { this.id = id; this.time = time; this.dur = dur; this.name = name; this.args = ArgSet.EMPTY; - this.trackId = trackId; + this.frameNumbers = Arrays.stream(frameNumbers.split(", ")) + .mapToLong(Long::parseLong) + .toArray(); + this.layerNames = layerNames.split(", "); + this.frameStats = frameStats; + this.frameSelection = new FrameSelection(this.frameNumbers, this.layerNames); } - public Slice(long id, long time, long dur, String name, ArgSet args, long trackId) { + public Slice(long id, long time, long dur, String name, ArgSet args, String frameNumbers, + String layerNames, Map frameStats) { this.id = id; this.time = time; this.dur = dur; this.name = name; this.args = args; - this.trackId = trackId; + this.frameNumbers = Arrays.stream(frameNumbers.split(", ")) + .mapToLong(Long::parseLong) + .toArray(); + this.layerNames = layerNames.split(", "); + this.frameStats = frameStats; + this.frameSelection = new FrameSelection(this.frameNumbers, this.layerNames); } - public Slice(QueryEngine.Row row, ArgSet args, long trackId) { - this(row.getLong(0), row.getLong(1), row.getLong(2), row.getString(4), args, trackId); + public Slice(QueryEngine.Row row, ArgSet args, Map frameStats) { + this(row.getLong(0), row.getLong(1), row.getLong(2), row.getString(3), args, + row.getString(8), row.getString(9), frameStats); } - public Slice(QueryEngine.Row row, long trackId) { - this(row.getLong(0), row.getLong(1), row.getLong(2), row.getString(4), trackId); + public Slice(QueryEngine.Row row, Map frameStats) { + this(row.getLong(0), row.getLong(1), row.getLong(2), row.getString(3), + row.getString(8), row.getString(9), frameStats); } @Override @@ -291,6 +343,9 @@ public void getRange(Consumer span) { } } + public FrameSelection getSelection() { + return frameSelection; + } } public static class Slices implements Selection { @@ -298,6 +353,7 @@ public static class Slices implements Selection { private final String title; public final ImmutableList nodes; public final ImmutableSet sliceKeys; + public final FrameSelection frameSelection; public Slices(List slices, String title, ImmutableList nodes, ImmutableSet sliceKeys) { @@ -305,6 +361,8 @@ public Slices(List slices, String title, ImmutableList nodes, this.title = title; this.nodes = nodes; this.sliceKeys = sliceKeys; + this.frameSelection = new FrameSelection(); + slices.forEach(s -> frameSelection.combine(s.getSelection())); } @Override @@ -333,6 +391,59 @@ public void getRange(Consumer span) { slice.getRange(span); } } + + public FrameSelection getSelection() { + return frameSelection; + } + } + + public static class FrameSelection { + public static FrameSelection EMPTY = new FrameSelection(); + // key = concat(layerName, '_', frameNumber) + private Set keys; + + public FrameSelection() { + keys = Sets.newHashSet(); + } + + public FrameSelection(long[] f, String[] l) { + keys = Sets.newHashSet(); + for (int i = 0; i < l.length; i++) { + keys.add(l[i] + "_" + f[i]); + } + } + + public boolean contains(long[] f, String[] l) { + for (int i = 0; i < f.length; i++) { + if (keys.contains(l[i] + "_" + f[i])) { + return true; + } + } + return false; + } + + public void combine(FrameSelection other) { + keys.addAll(other.keys); + } + + public boolean isEmpty() { + return keys.isEmpty(); + } + } + + public static class FrameStats { + public final long frameNumber; + public final long queueToAcquireTime; + public final long acquireToLatchTime; + public final long latchToPresentTime; + + public FrameStats(long frameNumber, long queueToAcquireTime, long acquireToLatchTime, + long latchToPresentTime) { + this.frameNumber = frameNumber; + this.queueToAcquireTime = queueToAcquireTime; + this.acquireToLatchTime = acquireToLatchTime; + this.latchToPresentTime = latchToPresentTime; + } } public static class SlicesBuilder implements Selection.Builder { @@ -346,7 +457,7 @@ public SlicesBuilder(List slices) { String ti = ""; for (Slice slice : slices) { ti = slice.getTitle(); - roots.put(slice.id, new Node(slice.name, slice.dur, slice.dur, slice.trackId)); + roots.put(slice.id, new Node(slice.name, slice.dur, slice.dur, slice.layerNames)); sliceKeys.add(slice.id); } this.title = ti; @@ -375,13 +486,13 @@ public static class Node { public final String name; public final long dur; public final long self; - public final long trackId; + public final String[] layers; - public Node(String name, long dur, long self, long id) { + public Node(String name, long dur, long self, String[] layers) { this.name = name; this.dur = dur; this.self = self; - this.trackId = id; + this.layers = layers; } } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/FrameInfo.java b/gapic/src/main/com/google/gapid/perfetto/models/FrameInfo.java new file mode 100644 index 0000000000..daa4082d7e --- /dev/null +++ b/gapic/src/main/com/google/gapid/perfetto/models/FrameInfo.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.gapid.perfetto.models; + +import static com.google.gapid.util.MoreFutures.transform; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.gapid.models.Perfetto; + +import java.util.Collections; +import java.util.List; + +/** + * Data about a GPU in the trace. + */ +public class FrameInfo { + public static final FrameInfo NONE = new FrameInfo(Collections.emptyList()); + + private static final String FRAME_SLICE_QUERY = + "select t.id, t.name, t.scope, max(depth) + 1 " + + "from gpu_track t join frame_slice s on (t.id = s.track_id) " + + "group by t.id " + + "order by t.id"; + private static final String DISPLAYED_FRAME_TRACK_NAME = "Displayed Frame"; + + private final List buffers; + + private FrameInfo(List buffers) { + this.buffers = buffers; + } + + public boolean isEmpty() { + return buffers.isEmpty(); + } + + public int bufferCount() { + return buffers.size(); + } + + public Iterable buffers() { + return Iterables.unmodifiableIterable(buffers); + } + + public static ListenableFuture listFrames(Perfetto.Data.Builder data) { + return transform(info(data.qe), frame -> data.setFrame(frame)); + } + + private static ListenableFuture info(QueryEngine qe) { + return + transform(qe.queries(FRAME_SLICE_QUERY), frame -> { + List buffers = Lists.newArrayList(); + frame.forEachRow(($, r) -> { + buffers.add(new Buffer(r)); + }); + + // Sort buffers by name, the query is sorted by track id. + buffers.sort((b1, b2) -> { + // Displayed Frame track should always be at top + if (b1.name.equals(DISPLAYED_FRAME_TRACK_NAME)) { + return -1; + } else if(b2.name.equals(DISPLAYED_FRAME_TRACK_NAME)) { + return 1; + } + return b1.name.compareTo(b2.name); + }); + return new FrameInfo(buffers); + }); + } + + public static class Buffer { + public final long trackId; + public final String name; + public final int maxDepth; + + public Buffer(long trackId, String name, int maxDepth) { + this.trackId = trackId; + this.name = name; + this.maxDepth = maxDepth; + } + + public Buffer(QueryEngine.Row row) { + this(row.getLong(0), row.getString(1), row.getInt(3)); + } + + public String getDisplay() { + return name; + } + } +} diff --git a/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java b/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java index 747fcb177d..b69f155870 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/GpuInfo.java @@ -29,8 +29,7 @@ * Data about a GPU in the trace. */ public class GpuInfo { - public static final GpuInfo NONE = new GpuInfo(Collections.emptyList(), Collections.emptyList(), - Collections.emptyList()); + public static final GpuInfo NONE = new GpuInfo(Collections.emptyList(), Collections.emptyList()); private static final String MAX_DEPTH_QUERY = "select t.id, t.name, t.scope, max(depth) + 1 " + @@ -40,16 +39,14 @@ public class GpuInfo { private final List queues; private final List vkApiEvents; - private final List buffers; - private GpuInfo(List queues, List vkApiEvents, List buffers) { + private GpuInfo(List queues, List vkApiEvents) { this.queues = queues; this.vkApiEvents = vkApiEvents; - this.buffers = buffers; } public boolean isEmpty() { - return queues.isEmpty() && buffers.isEmpty(); + return queues.isEmpty(); } public int queueCount() { @@ -68,41 +65,27 @@ public Iterable vkApiEvents() { return Iterables.unmodifiableIterable(vkApiEvents); } - public int bufferCount() { - return buffers.size(); - } - - public Iterable buffers() { - return Iterables.unmodifiableIterable(buffers); - } - public static ListenableFuture listGpus(Perfetto.Data.Builder data) { return transform(info(data.qe), gpu -> data.setGpu(gpu)); } private static ListenableFuture info(QueryEngine qe) { - return transform(qe.queries(MAX_DEPTH_QUERY), res -> { - List queues = Lists.newArrayList(); - List vkApiEvents = Lists.newArrayList(); - List buffers = Lists.newArrayList(); - res.forEachRow(($, r) -> { - switch (r.getString(2)) { - case "gpu_render_stage": - queues.add(new Queue(r)); - break; - case "vulkan_events": - vkApiEvents.add(new VkApiEvent(r)); - break; - case "graphics_frame_event": - buffers.add(new Buffer(r)); - break; - } - }); - - // Sort buffers by name, the query is sorted by track id for the queues. - buffers.sort((b1, b2) -> b1.name.compareTo(b2.name)); - return new GpuInfo(queues, vkApiEvents, buffers); - }); + return + transform(qe.queries(MAX_DEPTH_QUERY), res -> { + List queues = Lists.newArrayList(); + List vkApiEvents = Lists.newArrayList(); + res.forEachRow(($, r) -> { + switch (r.getString(2)) { + case "gpu_render_stage": + queues.add(new Queue(r)); + break; + case "vulkan_events": + vkApiEvents.add(new VkApiEvent(r)); + break; + } + }); + return new GpuInfo(queues, vkApiEvents); + }); } public static class Queue { @@ -144,24 +127,4 @@ public String getDisplay() { return name; } } - - public static class Buffer { - public final long trackId; - public final String name; - public final int maxDepth; - - public Buffer(long trackId, String name, int maxDepth) { - this.trackId = trackId; - this.name = name; - this.maxDepth = maxDepth; - } - - public Buffer(QueryEngine.Row row) { - this(row.getLong(0), row.getString(1), row.getInt(3)); - } - - public String getDisplay() { - return name; - } - } } diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Track.java b/gapic/src/main/com/google/gapid/perfetto/models/Track.java index a2cb22689d..23d9b0df9a 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/Track.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/Track.java @@ -235,6 +235,14 @@ public static Window compute(DataRequest request, int bucketSizePx) { } } + public static Window compute(DataRequest request, int bucketSizePx, long cutoff) { + if (request.resolution >= cutoff) { + return quantized(request, bucketSizePx); + } else { + return compute(request); + } + } + public static Window quantized(DataRequest request, int bucketSizePx) { long quantum = request.resolution * bucketSizePx; long start = (request.range.start / quantum) * quantum; diff --git a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java index 2b485afdb0..d695d0a03b 100644 --- a/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java +++ b/gapic/src/main/com/google/gapid/perfetto/models/Tracks.java @@ -64,6 +64,7 @@ public static ListenableFuture enumerate(Perfetto.Data.Bu enumerateCpu(data); enumerateCounters(data); enumerateGpu(data); + enumerateFrame(data); enumerateProcesses(data); enumerateVSync(data); return data; @@ -149,20 +150,6 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) { } } - if (data.getGpu().bufferCount() > 0) { - String parent = "gpu"; - if (data.getGpu().bufferCount() > 1) { - data.tracks.addLabelGroup("gpu", "sf_events", "Surface Flinger Events", - group(state -> new TitlePanel("Surface Flinger Events"), true)); - parent = "sf_events"; - } - for (GpuInfo.Buffer buffer : data.getGpu().buffers()) { - FrameEventsTrack track = FrameEventsTrack.forBuffer(data.qe, buffer); - data.tracks.addTrack(parent, track.getId(), buffer.getDisplay(), - single(state -> new FrameEventsSummaryPanel(state, buffer, track), true, false)); - } - } - if (!counters.isEmpty()) { String parent = "gpu"; if (counters.size() > 1) { @@ -180,6 +167,20 @@ public static Perfetto.Data.Builder enumerateGpu(Perfetto.Data.Builder data) { return data; } + public static Perfetto.Data.Builder enumerateFrame(Perfetto.Data.Builder data) { + if (data.getFrame().bufferCount() > 0) { + data.tracks.addLabelGroup(null, "sf_events", "Surface Flinger Events", + group(state -> new TitlePanel("Surface Flinger Events"), true)); + String parent = "sf_events"; + for (FrameInfo.Buffer buffer : data.getFrame().buffers()) { + FrameEventsTrack track = FrameEventsTrack.forBuffer(data.qe, buffer); + data.tracks.addTrack(parent, track.getId(), buffer.getDisplay(), + single(state -> new FrameEventsSummaryPanel(state, buffer, track), true, false)); + } + } + return data; + } + public static Perfetto.Data.Builder enumerateProcesses(Perfetto.Data.Builder data) { List processes = Lists.newArrayList(data.getProcesses().values()); Collections.sort(processes, (p1, p2) -> Long.compare(p2.totalDur, p1.totalDur)); diff --git a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsMultiSelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsMultiSelectionView.java index 470a57051b..869273a218 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsMultiSelectionView.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsMultiSelectionView.java @@ -63,8 +63,8 @@ public Object[] getChildren(Object element) { viewer.setLabelProvider(new LabelProvider()); createTreeColumn(viewer, "Name", e -> n(e).name); - createTreeColumn(viewer, "TrackId", e -> Long.toString(n(e).trackId)); createTreeColumn(viewer, "Self Time", e -> timeToString(n(e).self)); + createTreeColumn(viewer, "Layers", e -> String.join(", ", n(e).layers)); viewer.setInput(sel); packColumns(viewer.getTree()); } diff --git a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSelectionView.java b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSelectionView.java index 2660d661b1..a3ddd43f03 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSelectionView.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSelectionView.java @@ -32,6 +32,9 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; +import java.util.Arrays; +import java.util.stream.Collectors; + /** * Displays information about a selected Frame event. */ @@ -41,7 +44,7 @@ public class FrameEventsSelectionView extends Composite { public FrameEventsSelectionView(Composite parent, State state, FrameEventsTrack.Slice slice) { super(parent, SWT.NONE); - setLayout(withMargin(new GridLayout(2, false), 0, 0)); + setLayout(withMargin(new GridLayout(3, false), 0, 0)); Composite main = withLayoutData(createComposite(this, new GridLayout(2, false)), new GridData(SWT.LEFT, SWT.TOP, false, false)); @@ -56,6 +59,37 @@ public FrameEventsSelectionView(Composite parent, State state, FrameEventsTrack. createLabel(main, "Duration:"); createLabel(main, timeToString(slice.dur)); + if (slice.frameStats != null) { + // If the selected event is a displayed frame slice, show the frame stats + Composite stats = withLayoutData(createComposite(this, new GridLayout(2, false)), + withIndents(new GridData(SWT.LEFT, SWT.TOP, false, false), PANEL_INDENT, 0)); + withLayoutData(createBoldLabel(stats, "Frame Stats:"), + withSpans(new GridData(), 2, 1)); + + slice.frameStats.forEach((k, v) -> { + withLayoutData(createBoldLabel(stats, k.toString()), + withSpans(new GridData(), 2, 1)); + + createLabel(stats, "Frame number: "); + createLabel(stats, Long.toString(v.frameNumber)); + + createLabel(stats, "Queue to Acquire: "); + createLabel(stats, timeToString(v.queueToAcquireTime)); + + createLabel(stats, "Acquire to Latch: "); + createLabel(stats, timeToString(v.acquireToLatchTime)); + + createLabel(stats, "Latch to Present: "); + createLabel(stats, timeToString(v.latchToPresentTime)); + }); + } else { + // Show the frame number associated with the event + createLabel(main, "Frame Number:"); + createLabel(main, Arrays.stream(slice.frameNumbers) + .mapToObj(Long::toString) + .collect(Collectors.joining(", "))); + } + if (!slice.args.isEmpty()) { String[] keys = Iterables.toArray(slice.args.keys(), String.class); int panels = (keys.length + PROPERTIES_PER_PANEL - 1) / PROPERTIES_PER_PANEL; diff --git a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java index 16bfc6ea1a..e01073c8e4 100644 --- a/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java +++ b/gapic/src/main/com/google/gapid/perfetto/views/FrameEventsSummaryPanel.java @@ -19,7 +19,6 @@ import static com.google.gapid.perfetto.views.StyleConstants.SELECTION_THRESHOLD; import static com.google.gapid.perfetto.views.StyleConstants.TRACK_MARGIN; import static com.google.gapid.perfetto.views.StyleConstants.colors; -import static com.google.gapid.perfetto.views.StyleConstants.gradient; import static com.google.gapid.perfetto.views.StyleConstants.mainGradient; import static com.google.gapid.util.MoreFutures.transform; @@ -31,12 +30,12 @@ import com.google.gapid.perfetto.canvas.Size; import com.google.gapid.perfetto.models.ArgSet; import com.google.gapid.perfetto.models.FrameEventsTrack; -import com.google.gapid.perfetto.models.FrameEventsTrack.Slice; -import com.google.gapid.perfetto.models.GpuInfo; +import com.google.gapid.perfetto.models.FrameEventsTrack.FrameSelection; +import com.google.gapid.perfetto.models.FrameInfo; import com.google.gapid.perfetto.models.Selection; import com.google.gapid.perfetto.models.Selection.CombiningBuilder; - import com.google.gapid.util.Arrays; + import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.RGBA; @@ -55,7 +54,7 @@ public class FrameEventsSummaryPanel extends TrackPanel private static final double CURSOR_SIZE = 5; private static final int BOUNDING_BOX_LINE_WIDTH = 3; - private final GpuInfo.Buffer buffer; + private final FrameInfo.Buffer buffer; protected final FrameEventsTrack track; protected double mouseXpos, mouseYpos; @@ -64,13 +63,12 @@ public class FrameEventsSummaryPanel extends TrackPanel protected Size hoveredSize = Size.ZERO; protected HoverCard hovered; - public FrameEventsSummaryPanel(State state, GpuInfo.Buffer buffer, FrameEventsTrack track) { + public FrameEventsSummaryPanel(State state, FrameInfo.Buffer buffer, FrameEventsTrack track) { super(state); this.buffer = buffer; this.track = track; } - @Override public String getTitle() { return buffer.getDisplay(); @@ -164,10 +162,11 @@ public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { Selection selected = state.getSelection(Selection.Kind.FrameEvents); List visibleSelected = Lists.newArrayList(); + FrameSelection selectedFrames = getSelectedFrames(state); + for (int i = 0; i < data.starts.length; i++) { long tStart = data.starts[i]; long tEnd = data.ends[i]; - int depth = data.depths[i]; String title = buildSliceTitle(data.titles[i], data.args[i]); if (tEnd <= visible.start || tStart >= visible.end) { @@ -176,10 +175,16 @@ public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { double rectStart = state.timeToPx(tStart); StyleConstants.Gradient color = getSliceColor(data.titles[i]); color.applyBase(ctx); + if (!selectedFrames.isEmpty()) { + ctx.setBackgroundColor(color.disabled); + if (selectedFrames.contains(data.frameNumbers[i], data.layerNames[i])) { + color.applyBase(ctx); + } + } if (tEnd - tStart > 3 ) { double rectWidth = Math.max(1, state.timeToPx(tEnd) - rectStart); - double y = depth * SLICE_HEIGHT; + double y = 0; ctx.fillRect(rectStart, y, rectWidth, SLICE_HEIGHT); if (selected.contains(data.ids[i])) { @@ -196,13 +201,13 @@ public void renderSlices(RenderContext ctx, FrameEventsTrack.Data data) { Fonts.Style.Normal, title, rectStart + 2, y + 2, rectWidth - 4, SLICE_HEIGHT - 4); } else { double rectWidth = 20; - double y = depth * SLICE_HEIGHT; + double y = 0; double[] diamondX = { rectStart - (rectWidth / 2), rectStart, rectStart + (rectWidth / 2), rectStart}; double[] diamondY = { y + (SLICE_HEIGHT / 2), y, y + (SLICE_HEIGHT / 2), SLICE_HEIGHT }; ctx.fillPolygon(diamondX, diamondY, 4); if (selected.contains(data.ids[i])) { - visibleSelected.add(Highlight.diamond(color.border, diamondX, diamondY)); + visibleSelected.add(Highlight.diamond(color.highlight, diamondX, diamondY)); } ctx.setForegroundColor(colors().textMain); @@ -285,7 +290,7 @@ public Area getRedraw() { public void stop() { hovered = null; } - + @Override public Cursor getCursor(Display display) { return p == 0 ? null : display.getSystemCursor(SWT.CURSOR_HAND); @@ -323,14 +328,13 @@ private Hover sliceHover(FrameEventsTrack.Data data, Fonts.TextMeasurer m, doubl endts = ts + 12; ts -= 12; } - if (data.depths[i] == depth && x >= ts && x<= endts) { + if (x >= ts && x<= endts) { hoveredTitle = data.titles[i]; - hoveredCategory = data.categories[i]; + hoveredCategory = ""; if (hoveredTitle.isEmpty()) { if (hoveredCategory.isEmpty()) { return Hover.NONE; } - hoveredTitle = hoveredCategory; hoveredCategory = ""; } hoveredTitle = buildSliceTitle(hoveredTitle, data.args[i]); @@ -403,6 +407,16 @@ public void computeSelection(CombiningBuilder builder, Area area, TimeSpan ts) { } } + private static FrameSelection getSelectedFrames(State state) { + Selection selection = state.getSelection(Selection.Kind.FrameEvents); + if (selection instanceof FrameEventsTrack.Slice) { + return ((FrameEventsTrack.Slice) selection).getSelection(); + } else if (selection instanceof FrameEventsTrack.Slices) { + return ((FrameEventsTrack.Slices) selection).getSelection(); + } + return FrameSelection.EMPTY; + } + private static class HoverCard { public final int bucket; public final long numEvents; diff --git a/tools/build/workspace.bzl b/tools/build/workspace.bzl index 75687c6558..e1d74b12fd 100644 --- a/tools/build/workspace.bzl +++ b/tools/build/workspace.bzl @@ -173,8 +173,8 @@ def gapid_dependencies(android = True, mingw = True, locals = {}): name = "perfetto", locals = locals, remote = "https://android.googlesource.com/platform/external/perfetto", - commit = "f447425f9f7f676bf22d3c5e4a78f30d43c92c95", - shallow_since = "1582916230 +0000", + commit = "4d9bf4234b682c2ec79ab925c028d8c033c9c409", + shallow_since = "1585081996 -0700", ) maybe_repository( From 21ee35892397d60cb66bdd4a9e8ea138d2b20488 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Thu, 16 Apr 2020 16:47:14 -0700 Subject: [PATCH 0243/1218] Goodbye robot, beep, beep, bloop. --- BUILD.bazel | 2 - cmd/lingo/BUILD.bazel | 32 - cmd/lingo/main.go | 43 -- cmd/robot/BUILD.bazel | 78 --- cmd/robot/actions.go | 89 --- cmd/robot/build.go | 377 ------------ cmd/robot/job.go | 140 ----- cmd/robot/main.go | 26 - cmd/robot/master.go | 242 -------- cmd/robot/replay.go | 59 -- cmd/robot/report.go | 59 -- cmd/robot/stash.go | 79 --- cmd/robot/subject.go | 188 ------ cmd/robot/trace.go | 83 --- cmd/robot/upload.go | 96 --- cmd/robot/web.go | 94 --- cmd/stash/BUILD.bazel | 44 -- cmd/stash/main.go | 64 -- cmd/stash/search.go | 63 -- cmd/stash/server.go | 66 --- cmd/stash/upload.go | 57 -- test/robot/README.md | 91 --- test/robot/build/BUILD.bazel | 70 --- test/robot/build/artifact.go | 168 ------ test/robot/build/build.go | 58 -- test/robot/build/build.proto | 197 ------- test/robot/build/doc.go | 16 - test/robot/build/local.go | 106 ---- test/robot/build/package.go | 209 ------- test/robot/build/remote.go | 96 --- test/robot/build/server.go | 92 --- test/robot/build/track.go | 144 ----- test/robot/go_robot_go.sh | 300 ---------- test/robot/job/BUILD.bazel | 71 --- test/robot/job/device.go | 119 ---- test/robot/job/device_listener.go | 109 ---- test/robot/job/doc.go | 19 - test/robot/job/job.go | 30 - test/robot/job/job.proto | 92 --- test/robot/job/local.go | 110 ---- test/robot/job/manager.go | 38 -- test/robot/job/remote.go | 65 -- test/robot/job/server.go | 59 -- test/robot/job/worker/BUILD.bazel | 56 -- test/robot/job/worker/action.go | 163 ----- test/robot/job/worker/doc.go | 18 - test/robot/job/worker/local.go | 59 -- test/robot/job/worker/worker.go | 170 ------ test/robot/job/worker/worker.proto | 36 -- test/robot/lingo/BUILD.bazel | 30 - test/robot/lingo/error.go | 117 ---- test/robot/lingo/examples/calc/BUILD.bazel | 42 -- .../robot/lingo/examples/calc/constants.lingo | 43 -- test/robot/lingo/examples/calc/main.go | 51 -- test/robot/lingo/examples/calc/nodes.lingo | 127 ---- test/robot/lingo/examples/calc/parser.lingo | 110 ---- test/robot/lingo/examples/cstcalc/BUILD.bazel | 42 -- test/robot/lingo/examples/cstcalc/doc.go | 21 - test/robot/lingo/examples/cstcalc/main.lingo | 186 ------ .../lingo/examples/simplecalc/BUILD.bazel | 42 -- test/robot/lingo/examples/simplecalc/doc.go | 21 - .../lingo/examples/simplecalc/main.lingo | 138 ----- test/robot/lingo/generator/BUILD.bazel | 33 -- test/robot/lingo/generator/doc.go | 19 - test/robot/lingo/generator/generator.go | 95 --- test/robot/lingo/generator/introspect.go | 203 ------- test/robot/lingo/generator/rewrite.go | 341 ----------- test/robot/lingo/generator/wrap.go | 125 ---- test/robot/lingo/node.go | 77 --- test/robot/lingo/scanner.go | 175 ------ test/robot/master/BUILD.bazel | 61 -- test/robot/master/client.go | 108 ---- test/robot/master/doc.go | 20 - test/robot/master/local.go | 169 ------ test/robot/master/master.go | 36 -- test/robot/master/master.proto | 106 ---- test/robot/master/remote.go | 62 -- test/robot/master/satellite.go | 78 --- test/robot/master/server.go | 59 -- test/robot/monitor/BUILD.bazel | 48 -- test/robot/monitor/build.go | 123 ---- test/robot/monitor/doc.go | 23 - test/robot/monitor/generation.go | 87 --- test/robot/monitor/job.go | 87 --- test/robot/monitor/monitor.go | 173 ------ test/robot/monitor/replay.go | 70 --- test/robot/monitor/report.go | 70 --- test/robot/monitor/subject.go | 60 -- test/robot/monitor/trace.go | 81 --- test/robot/record/BUILD.bazel | 55 -- test/robot/record/doc.go | 17 - test/robot/record/file.go | 128 ---- test/robot/record/json.go | 74 --- test/robot/record/ledger.go | 85 --- test/robot/record/library.go | 62 -- test/robot/record/null.go | 38 -- test/robot/record/pb.go | 99 ---- test/robot/record/pbtxt.go | 96 --- test/robot/record/record.go | 23 - test/robot/record/record.proto | 32 - test/robot/record/shelf.go | 63 -- test/robot/replay/BUILD.bazel | 78 --- test/robot/replay/client.go | 212 ------- test/robot/replay/doc.go | 17 - test/robot/replay/local.go | 75 --- test/robot/replay/manager.go | 41 -- test/robot/replay/remote.go | 75 --- test/robot/replay/replay.proto | 122 ---- test/robot/replay/server.go | 66 --- test/robot/report/BUILD.bazel | 78 --- test/robot/report/client.go | 189 ------ test/robot/report/doc.go | 17 - test/robot/report/local.go | 75 --- test/robot/report/manager.go | 41 -- test/robot/report/remote.go | 75 --- test/robot/report/report.proto | 114 ---- test/robot/report/server.go | 66 --- test/robot/scheduler/BUILD.bazel | 37 -- test/robot/scheduler/doc.go | 18 - test/robot/scheduler/replay.go | 64 -- test/robot/scheduler/report.go | 61 -- test/robot/scheduler/scheduler.go | 169 ------ test/robot/scheduler/trace.go | 56 -- test/robot/search/BUILD.bazel | 38 -- test/robot/search/doc.go | 17 - test/robot/search/eval/BUILD.bazel | 30 - test/robot/search/eval/doc.go | 18 - test/robot/search/eval/eval.go | 294 --------- test/robot/search/query/BUILD.bazel | 31 - test/robot/search/query/builder.go | 128 ---- test/robot/search/query/doc.go | 18 - test/robot/search/query/expression.go | 176 ------ test/robot/search/query/replace.go | 68 --- test/robot/search/script/BUILD.bazel | 36 -- test/robot/search/script/constants.lingo | 74 --- test/robot/search/script/doc.go | 21 - test/robot/search/script/expression.lingo | 131 ----- test/robot/search/script/literal.lingo | 58 -- test/robot/search/script/parse.lingo | 90 --- test/robot/search/search.proto | 67 --- test/robot/stash/BUILD.bazel | 53 -- test/robot/stash/client.go | 112 ---- test/robot/stash/doc.go | 17 - test/robot/stash/factory.go | 62 -- test/robot/stash/grpc/BUILD.bazel | 79 --- test/robot/stash/grpc/client.go | 303 ---------- test/robot/stash/grpc/doc.go | 17 - test/robot/stash/grpc/grpc_test.go | 229 -------- test/robot/stash/grpc/server.go | 146 ----- test/robot/stash/grpc/stash.proto | 69 --- test/robot/stash/local/BUILD.bazel | 37 -- test/robot/stash/local/doc.go | 16 - test/robot/stash/local/entity.go | 69 --- test/robot/stash/local/file.go | 167 ------ test/robot/stash/local/memory.go | 114 ---- test/robot/stash/stash.go | 74 --- test/robot/stash/stash.proto | 55 -- test/robot/stash/upload.go | 94 --- test/robot/subject/BUILD.bazel | 66 --- test/robot/subject/doc.go | 17 - test/robot/subject/local.go | 136 ----- test/robot/subject/remote.go | 65 -- test/robot/subject/server.go | 62 -- test/robot/subject/subject.go | 34 -- test/robot/subject/subject.proto | 91 --- test/robot/trace/BUILD.bazel | 81 --- test/robot/trace/client.go | 219 ------- test/robot/trace/doc.go | 16 - test/robot/trace/local.go | 74 --- test/robot/trace/manager.go | 41 -- test/robot/trace/remote.go | 74 --- test/robot/trace/server.go | 65 -- test/robot/trace/trace.proto | 115 ---- test/robot/web/BUILD.bazel | 66 --- test/robot/web/action.go | 76 --- test/robot/web/build.go | 106 ---- test/robot/web/client/client.go | 556 ------------------ test/robot/web/client/data.go | 474 --------------- test/robot/web/client/dom/a.go | 21 - test/robot/web/client/dom/button.go | 21 - test/robot/web/client/dom/canvas.go | 37 -- test/robot/web/client/dom/context2d.go | 397 ------------- test/robot/web/client/dom/div.go | 21 - test/robot/web/client/dom/document.go | 38 -- test/robot/web/client/dom/element.go | 109 ---- test/robot/web/client/dom/events.go | 111 ---- test/robot/web/client/dom/node.go | 47 -- test/robot/web/client/dom/paragraph.go | 21 - test/robot/web/client/dom/select.go | 68 --- test/robot/web/client/dom/span.go | 21 - test/robot/web/client/dom/style.go | 365 ------------ test/robot/web/client/dom/table.go | 43 -- test/robot/web/client/dom/text.go | 28 - test/robot/web/client/dom/video.go | 64 -- test/robot/web/client/dom/window.go | 137 ----- .../robot/web/client/widgets/button/button.go | 23 - .../web/client/widgets/grid/click_ripple.go | 48 -- test/robot/web/client/widgets/grid/data.go | 339 ----------- test/robot/web/client/widgets/grid/draw.go | 355 ----------- test/robot/web/client/widgets/grid/events.go | 90 --- test/robot/web/client/widgets/grid/grid.go | 109 ---- test/robot/web/client/widgets/grid/layout.go | 73 --- test/robot/web/client/widgets/grid/style.go | 76 --- .../web/client/widgets/grid/transition.go | 203 ------- .../web/client/widgets/objview/objview.go | 240 -------- test/robot/web/doc.go | 16 - test/robot/web/entity.go | 100 ---- test/robot/web/grid.go | 120 ---- test/robot/web/job.go | 55 -- test/robot/web/master.go | 39 -- test/robot/web/requests.go | 37 -- test/robot/web/static.go | 85 --- test/robot/web/status.go | 42 -- test/robot/web/subject.go | 39 -- test/robot/web/web.go | 101 ---- test/robot/web/www/css/grid.css | 79 --- test/robot/web/www/favicon.png | Bin 1716 -> 0 bytes test/robot/web/www/grid.html | 22 - test/robot/web/www/grid/.gitignore | 2 - test/robot/web/www/grid2.html | 37 -- test/robot/web/www/images/os/android.png | Bin 4912 -> 0 bytes test/robot/web/www/images/os/linux.png | Bin 17842 -> 0 bytes test/robot/web/www/images/os/osx.png | Bin 5265 -> 0 bytes test/robot/web/www/images/os/windows.png | Bin 12026 -> 0 bytes test/robot/web/www/index.html | 10 - test/robot/web/www/js/actions.js | 79 --- test/robot/web/www/js/devices.js | 36 -- test/robot/web/www/js/draw.js | 122 ---- test/robot/web/www/js/grid-main.js | 205 ------- test/robot/web/www/js/griddata.js | 100 ---- test/robot/web/www/js/packages.js | 44 -- test/robot/web/www/js/queriable.js | 66 --- test/robot/web/www/js/replays.js | 32 - test/robot/web/www/js/reports.js | 32 - test/robot/web/www/js/selection.js | 112 ---- test/robot/web/www/js/subjects.js | 34 -- test/robot/web/www/js/traces.js | 39 -- test/robot/web/www/js/tracks.js | 36 -- test/robot/web/www/js/viewer.js | 101 ---- test/robot/web/www/js/xhr.js | 51 -- 240 files changed, 21239 deletions(-) delete mode 100644 cmd/lingo/BUILD.bazel delete mode 100644 cmd/lingo/main.go delete mode 100644 cmd/robot/BUILD.bazel delete mode 100644 cmd/robot/actions.go delete mode 100644 cmd/robot/build.go delete mode 100644 cmd/robot/job.go delete mode 100644 cmd/robot/main.go delete mode 100644 cmd/robot/master.go delete mode 100644 cmd/robot/replay.go delete mode 100644 cmd/robot/report.go delete mode 100644 cmd/robot/stash.go delete mode 100644 cmd/robot/subject.go delete mode 100644 cmd/robot/trace.go delete mode 100644 cmd/robot/upload.go delete mode 100644 cmd/robot/web.go delete mode 100644 cmd/stash/BUILD.bazel delete mode 100644 cmd/stash/main.go delete mode 100644 cmd/stash/search.go delete mode 100644 cmd/stash/server.go delete mode 100644 cmd/stash/upload.go delete mode 100644 test/robot/README.md delete mode 100644 test/robot/build/BUILD.bazel delete mode 100644 test/robot/build/artifact.go delete mode 100644 test/robot/build/build.go delete mode 100644 test/robot/build/build.proto delete mode 100644 test/robot/build/doc.go delete mode 100644 test/robot/build/local.go delete mode 100644 test/robot/build/package.go delete mode 100644 test/robot/build/remote.go delete mode 100644 test/robot/build/server.go delete mode 100644 test/robot/build/track.go delete mode 100755 test/robot/go_robot_go.sh delete mode 100644 test/robot/job/BUILD.bazel delete mode 100644 test/robot/job/device.go delete mode 100644 test/robot/job/device_listener.go delete mode 100644 test/robot/job/doc.go delete mode 100644 test/robot/job/job.go delete mode 100644 test/robot/job/job.proto delete mode 100644 test/robot/job/local.go delete mode 100644 test/robot/job/manager.go delete mode 100644 test/robot/job/remote.go delete mode 100644 test/robot/job/server.go delete mode 100644 test/robot/job/worker/BUILD.bazel delete mode 100644 test/robot/job/worker/action.go delete mode 100644 test/robot/job/worker/doc.go delete mode 100644 test/robot/job/worker/local.go delete mode 100644 test/robot/job/worker/worker.go delete mode 100644 test/robot/job/worker/worker.proto delete mode 100644 test/robot/lingo/BUILD.bazel delete mode 100644 test/robot/lingo/error.go delete mode 100644 test/robot/lingo/examples/calc/BUILD.bazel delete mode 100644 test/robot/lingo/examples/calc/constants.lingo delete mode 100644 test/robot/lingo/examples/calc/main.go delete mode 100644 test/robot/lingo/examples/calc/nodes.lingo delete mode 100644 test/robot/lingo/examples/calc/parser.lingo delete mode 100644 test/robot/lingo/examples/cstcalc/BUILD.bazel delete mode 100644 test/robot/lingo/examples/cstcalc/doc.go delete mode 100644 test/robot/lingo/examples/cstcalc/main.lingo delete mode 100644 test/robot/lingo/examples/simplecalc/BUILD.bazel delete mode 100644 test/robot/lingo/examples/simplecalc/doc.go delete mode 100644 test/robot/lingo/examples/simplecalc/main.lingo delete mode 100644 test/robot/lingo/generator/BUILD.bazel delete mode 100644 test/robot/lingo/generator/doc.go delete mode 100644 test/robot/lingo/generator/generator.go delete mode 100644 test/robot/lingo/generator/introspect.go delete mode 100644 test/robot/lingo/generator/rewrite.go delete mode 100644 test/robot/lingo/generator/wrap.go delete mode 100644 test/robot/lingo/node.go delete mode 100644 test/robot/lingo/scanner.go delete mode 100644 test/robot/master/BUILD.bazel delete mode 100644 test/robot/master/client.go delete mode 100644 test/robot/master/doc.go delete mode 100644 test/robot/master/local.go delete mode 100644 test/robot/master/master.go delete mode 100644 test/robot/master/master.proto delete mode 100644 test/robot/master/remote.go delete mode 100644 test/robot/master/satellite.go delete mode 100644 test/robot/master/server.go delete mode 100644 test/robot/monitor/BUILD.bazel delete mode 100644 test/robot/monitor/build.go delete mode 100644 test/robot/monitor/doc.go delete mode 100644 test/robot/monitor/generation.go delete mode 100644 test/robot/monitor/job.go delete mode 100644 test/robot/monitor/monitor.go delete mode 100644 test/robot/monitor/replay.go delete mode 100644 test/robot/monitor/report.go delete mode 100644 test/robot/monitor/subject.go delete mode 100644 test/robot/monitor/trace.go delete mode 100644 test/robot/record/BUILD.bazel delete mode 100644 test/robot/record/doc.go delete mode 100644 test/robot/record/file.go delete mode 100644 test/robot/record/json.go delete mode 100644 test/robot/record/ledger.go delete mode 100644 test/robot/record/library.go delete mode 100644 test/robot/record/null.go delete mode 100644 test/robot/record/pb.go delete mode 100644 test/robot/record/pbtxt.go delete mode 100644 test/robot/record/record.go delete mode 100644 test/robot/record/record.proto delete mode 100644 test/robot/record/shelf.go delete mode 100644 test/robot/replay/BUILD.bazel delete mode 100644 test/robot/replay/client.go delete mode 100644 test/robot/replay/doc.go delete mode 100644 test/robot/replay/local.go delete mode 100644 test/robot/replay/manager.go delete mode 100644 test/robot/replay/remote.go delete mode 100644 test/robot/replay/replay.proto delete mode 100644 test/robot/replay/server.go delete mode 100644 test/robot/report/BUILD.bazel delete mode 100644 test/robot/report/client.go delete mode 100644 test/robot/report/doc.go delete mode 100644 test/robot/report/local.go delete mode 100644 test/robot/report/manager.go delete mode 100644 test/robot/report/remote.go delete mode 100644 test/robot/report/report.proto delete mode 100644 test/robot/report/server.go delete mode 100644 test/robot/scheduler/BUILD.bazel delete mode 100644 test/robot/scheduler/doc.go delete mode 100644 test/robot/scheduler/replay.go delete mode 100644 test/robot/scheduler/report.go delete mode 100644 test/robot/scheduler/scheduler.go delete mode 100644 test/robot/scheduler/trace.go delete mode 100644 test/robot/search/BUILD.bazel delete mode 100644 test/robot/search/doc.go delete mode 100644 test/robot/search/eval/BUILD.bazel delete mode 100644 test/robot/search/eval/doc.go delete mode 100644 test/robot/search/eval/eval.go delete mode 100644 test/robot/search/query/BUILD.bazel delete mode 100644 test/robot/search/query/builder.go delete mode 100644 test/robot/search/query/doc.go delete mode 100644 test/robot/search/query/expression.go delete mode 100644 test/robot/search/query/replace.go delete mode 100644 test/robot/search/script/BUILD.bazel delete mode 100644 test/robot/search/script/constants.lingo delete mode 100644 test/robot/search/script/doc.go delete mode 100644 test/robot/search/script/expression.lingo delete mode 100644 test/robot/search/script/literal.lingo delete mode 100644 test/robot/search/script/parse.lingo delete mode 100644 test/robot/search/search.proto delete mode 100644 test/robot/stash/BUILD.bazel delete mode 100644 test/robot/stash/client.go delete mode 100644 test/robot/stash/doc.go delete mode 100644 test/robot/stash/factory.go delete mode 100644 test/robot/stash/grpc/BUILD.bazel delete mode 100644 test/robot/stash/grpc/client.go delete mode 100644 test/robot/stash/grpc/doc.go delete mode 100644 test/robot/stash/grpc/grpc_test.go delete mode 100644 test/robot/stash/grpc/server.go delete mode 100644 test/robot/stash/grpc/stash.proto delete mode 100644 test/robot/stash/local/BUILD.bazel delete mode 100644 test/robot/stash/local/doc.go delete mode 100644 test/robot/stash/local/entity.go delete mode 100644 test/robot/stash/local/file.go delete mode 100644 test/robot/stash/local/memory.go delete mode 100644 test/robot/stash/stash.go delete mode 100644 test/robot/stash/stash.proto delete mode 100644 test/robot/stash/upload.go delete mode 100644 test/robot/subject/BUILD.bazel delete mode 100644 test/robot/subject/doc.go delete mode 100644 test/robot/subject/local.go delete mode 100644 test/robot/subject/remote.go delete mode 100644 test/robot/subject/server.go delete mode 100644 test/robot/subject/subject.go delete mode 100644 test/robot/subject/subject.proto delete mode 100644 test/robot/trace/BUILD.bazel delete mode 100644 test/robot/trace/client.go delete mode 100644 test/robot/trace/doc.go delete mode 100644 test/robot/trace/local.go delete mode 100644 test/robot/trace/manager.go delete mode 100644 test/robot/trace/remote.go delete mode 100644 test/robot/trace/server.go delete mode 100644 test/robot/trace/trace.proto delete mode 100644 test/robot/web/BUILD.bazel delete mode 100644 test/robot/web/action.go delete mode 100644 test/robot/web/build.go delete mode 100644 test/robot/web/client/client.go delete mode 100644 test/robot/web/client/data.go delete mode 100644 test/robot/web/client/dom/a.go delete mode 100644 test/robot/web/client/dom/button.go delete mode 100644 test/robot/web/client/dom/canvas.go delete mode 100644 test/robot/web/client/dom/context2d.go delete mode 100644 test/robot/web/client/dom/div.go delete mode 100644 test/robot/web/client/dom/document.go delete mode 100644 test/robot/web/client/dom/element.go delete mode 100644 test/robot/web/client/dom/events.go delete mode 100644 test/robot/web/client/dom/node.go delete mode 100644 test/robot/web/client/dom/paragraph.go delete mode 100644 test/robot/web/client/dom/select.go delete mode 100644 test/robot/web/client/dom/span.go delete mode 100644 test/robot/web/client/dom/style.go delete mode 100644 test/robot/web/client/dom/table.go delete mode 100644 test/robot/web/client/dom/text.go delete mode 100644 test/robot/web/client/dom/video.go delete mode 100644 test/robot/web/client/dom/window.go delete mode 100644 test/robot/web/client/widgets/button/button.go delete mode 100644 test/robot/web/client/widgets/grid/click_ripple.go delete mode 100644 test/robot/web/client/widgets/grid/data.go delete mode 100644 test/robot/web/client/widgets/grid/draw.go delete mode 100644 test/robot/web/client/widgets/grid/events.go delete mode 100644 test/robot/web/client/widgets/grid/grid.go delete mode 100644 test/robot/web/client/widgets/grid/layout.go delete mode 100644 test/robot/web/client/widgets/grid/style.go delete mode 100644 test/robot/web/client/widgets/grid/transition.go delete mode 100644 test/robot/web/client/widgets/objview/objview.go delete mode 100644 test/robot/web/doc.go delete mode 100644 test/robot/web/entity.go delete mode 100644 test/robot/web/grid.go delete mode 100644 test/robot/web/job.go delete mode 100644 test/robot/web/master.go delete mode 100644 test/robot/web/requests.go delete mode 100644 test/robot/web/static.go delete mode 100644 test/robot/web/status.go delete mode 100644 test/robot/web/subject.go delete mode 100644 test/robot/web/web.go delete mode 100644 test/robot/web/www/css/grid.css delete mode 100644 test/robot/web/www/favicon.png delete mode 100644 test/robot/web/www/grid.html delete mode 100644 test/robot/web/www/grid/.gitignore delete mode 100644 test/robot/web/www/grid2.html delete mode 100644 test/robot/web/www/images/os/android.png delete mode 100644 test/robot/web/www/images/os/linux.png delete mode 100644 test/robot/web/www/images/os/osx.png delete mode 100644 test/robot/web/www/images/os/windows.png delete mode 100644 test/robot/web/www/index.html delete mode 100644 test/robot/web/www/js/actions.js delete mode 100644 test/robot/web/www/js/devices.js delete mode 100644 test/robot/web/www/js/draw.js delete mode 100644 test/robot/web/www/js/grid-main.js delete mode 100644 test/robot/web/www/js/griddata.js delete mode 100644 test/robot/web/www/js/packages.js delete mode 100644 test/robot/web/www/js/queriable.js delete mode 100644 test/robot/web/www/js/replays.js delete mode 100644 test/robot/web/www/js/reports.js delete mode 100644 test/robot/web/www/js/selection.js delete mode 100644 test/robot/web/www/js/subjects.js delete mode 100644 test/robot/web/www/js/traces.js delete mode 100644 test/robot/web/www/js/tracks.js delete mode 100644 test/robot/web/www/js/viewer.js delete mode 100644 test/robot/web/www/js/xhr.js diff --git a/BUILD.bazel b/BUILD.bazel index 2a58c3c57f..8060405b34 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -355,7 +355,6 @@ test_suite( tests = [ "//test/integration/replay:go_default_test", "//test/integration/service:go_default_test", - "//test/robot/stash/grpc:go_default_test", ], ) @@ -451,7 +450,6 @@ test_suite( "//gapis/vertex:go_default_test", "//test/integration/replay:go_default_test", "//test/integration/service:go_default_test", - "//test/robot/stash/grpc:go_default_test", # __END_TESTS ], ) diff --git a/cmd/lingo/BUILD.bazel b/cmd/lingo/BUILD.bazel deleted file mode 100644 index 5938680ee8..0000000000 --- a/cmd/lingo/BUILD.bazel +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = ["main.go"], - importpath = "github.com/google/gapid/cmd/lingo", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//test/robot/lingo/generator:go_default_library", - ], -) - -go_binary( - name = "lingo", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/cmd/lingo/main.go b/cmd/lingo/main.go deleted file mode 100644 index a29c72c186..0000000000 --- a/cmd/lingo/main.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The syntax command is used to rewrite recursive descent parser syntax declaration files. -package main - -import ( - "context" - "flag" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/test/robot/lingo/generator" -) - -var ( - base string -) - -func main() { - app.ShortHelp = "syntax: A recursive descent parser generator." - flag.StringVar(&base, "base", base, "don't update the copyright if it's just old") - app.Run(run) -} - -func run(ctx context.Context) error { - args := flag.Args() - if len(args) < 1 { - app.Usage(ctx, "Expect at least one lingo file") - return nil - } - return generator.RewriteFiles(ctx, base, args...) -} diff --git a/cmd/robot/BUILD.bazel b/cmd/robot/BUILD.bazel deleted file mode 100644 index 10362b322c..0000000000 --- a/cmd/robot/BUILD.bazel +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "actions.go", - "build.go", - "job.go", - "main.go", - "master.go", - "replay.go", - "report.go", - "stash.go", - "subject.go", - "trace.go", - "upload.go", - "web.go", - ], - importpath = "github.com/google/gapid/cmd/robot", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//core/app/crash:go_default_library", - "//core/git:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/host:go_default_library", - "//core/os/file:go_default_library", - "//core/os/flock:go_default_library", - "//test/robot/build:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/master:go_default_library", - "//test/robot/monitor:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/replay:go_default_library", - "//test/robot/report:go_default_library", - "//test/robot/scheduler:go_default_library", - "//test/robot/search/script:go_default_library", - "//test/robot/stash:go_default_library", - "//test/robot/stash/grpc:go_default_library", - "//test/robot/stash/local:go_default_library", - "//test/robot/subject:go_default_library", - "//test/robot/trace:go_default_library", - "//test/robot/web:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@org_golang_google_grpc//:go_default_library", - ], -) - -go_binary( - name = "robot", - data = select({ - "//tools/build:no-android": [], - "//conditions:default": [ - "//gapidapk/android/apk:arm64-v8a.apk", - "//gapidapk/android/apk:armeabi-v7a.apk", - "//gapidapk/android/apk:x86.apk", - ], - }), - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/cmd/robot/actions.go b/cmd/robot/actions.go deleted file mode 100644 index b285c3aadb..0000000000 --- a/cmd/robot/actions.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/master" - "google.golang.org/grpc" -) - -type RobotOptions struct { - ServerAddress string `help:"The master server address"` -} - -var ( - startVerb = app.AddVerb(&app.Verb{ - Name: "start", - ShortHelp: "Start a server", - }) - searchVerb = app.AddVerb(&app.Verb{ - Name: "search", - ShortHelp: "Search for content in the server", - }) - uploadVerb = app.AddVerb(&app.Verb{ - Name: "upload", - ShortHelp: "Upload a file to a server", - }) - setVerb = app.AddVerb(&app.Verb{ - Name: "set", - ShortHelp: "Sets a value in a server", - }) - defaultRobotOptions = RobotOptions{ServerAddress: defaultMasterAddress} -) - -func init() { - app.AddVerb(&app.Verb{ - Name: "stop", - ShortHelp: "Stop a server", - Action: &stopVerb{RobotOptions: defaultRobotOptions}, - }) - app.AddVerb(&app.Verb{ - Name: "restart", - ShortHelp: "Restart a server", - Action: &restartVerb{RobotOptions: defaultRobotOptions}, - }) -} - -type stopVerb struct { - RobotOptions - - Now bool `help:"Immediate shutdown"` -} - -func (v *stopVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - client := master.NewClient(ctx, master.NewRemoteMaster(ctx, conn)) - if v.Now { - return client.Kill(ctx, flags.Args()...) - } - return client.Shutdown(ctx, flags.Args()...) - }, grpc.WithInsecure()) -} - -type restartVerb struct { - RobotOptions -} - -func (v *restartVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - client := master.NewClient(ctx, master.NewRemoteMaster(ctx, conn)) - return client.Restart(ctx, flags.Args()...) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/build.go b/cmd/robot/build.go deleted file mode 100644 index a941b10199..0000000000 --- a/cmd/robot/build.go +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "context" - "errors" - "flag" - "os" - "os/user" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/git" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/host" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/search/script" - "google.golang.org/grpc" -) - -type UploadOptions struct { - RobotOptions - CL string `help:"The build CL, will be guessed if not set"` - Description string `help:"An optional build description"` - Tag string `help:"The optional build tag"` - Track string `help:"The package's track, will be guessed if not set"` - Uploader string `help:"The uploading entity, will be guessed if not set"` - BuilderAbi string `help:"The abi of the builder device, will assume this device if not set"` - BuildBot bool `help:"Whether this package was built by a build bot"` -} - -func init() { - uploadVerb.Add(&app.Verb{ - Name: "build", - ShortHelp: "Upload a build to the server", - ShortUsage: "", - Action: &buildUploadVerb{UploadOptions: UploadOptions{RobotOptions: defaultRobotOptions}}, - }) - searchVerb.Add(&app.Verb{ - Name: "artifact", - ShortHelp: "List build artifacts in the server", - ShortUsage: "", - Action: &artifactSearchVerb{RobotOptions: defaultRobotOptions}, - }) - searchVerb.Add(&app.Verb{ - Name: "package", - ShortHelp: "List build packages in the server", - ShortUsage: "", - Action: &packageSearchVerb{RobotOptions: defaultRobotOptions}, - }) - searchVerb.Add(&app.Verb{ - Name: "track", - ShortHelp: "List build tracks in the server", - ShortUsage: "", - Action: &trackSearchVerb{RobotOptions: defaultRobotOptions}, - }) - setVerb.Add(&app.Verb{ - Name: "track", - ShortHelp: "Sets values on a track", - ShortUsage: "", - Action: &trackUpdateVerb{RobotOptions: defaultRobotOptions}, - }) - setVerb.Add(&app.Verb{ - Name: "package", - ShortHelp: "Sets values on a package", - ShortUsage: "", - Action: &packageUpdateVerb{RobotOptions: defaultRobotOptions}, - }) -} - -type buildUploadVerb struct { - UploadOptions - - store build.Store - info *build.Information -} - -func (v *buildUploadVerb) Run(ctx context.Context, flags flag.FlagSet) (err error) { - if flags.NArg() != 1 { - err = errors.New("Missing expected argument") - return log.Err(ctx, err, "build upload expects a single filepath as argument") - } - - p := file.Abs(flags.Arg(0)) - u := make([]uploadable, 1) - if p.IsDir() { - b, err := zip(p) - if err != nil { - return log.Err(ctx, err, "failed to create artifact zip") - } - u[0] = data(b.Bytes(), p.Basename()+".zip", false) - } else { - u[0] = path(p.System()) - } - - return upload(ctx, u, v.ServerAddress, v) -} - -func (v *buildUploadVerb) prepare(ctx context.Context, conn *grpc.ClientConn) (err error) { - v.store = build.NewRemote(ctx, conn) - v.info, err = v.UploadOptions.createBuildInfo(ctx) - return -} - -func (v *buildUploadVerb) process(ctx context.Context, id string) error { - return storeBuild(ctx, v.store, v.info, id) -} - -func storeBuild(ctx context.Context, store build.Store, info *build.Information, id string) error { - id, merged, err := store.Add(ctx, id, info) - if err != nil { - return log.Err(ctx, err, "Failed processing build") - } - if merged { - log.I(ctx, "Merged with build set %s", id) - } else { - log.I(ctx, "New build set %s", id) - } - return nil -} - -func (o *UploadOptions) createBuildInfo(ctx context.Context) (*build.Information, error) { - // see if we can find a git cl in the cwd - var typ build.Type - if o.BuildBot { - typ = build.BuildBot - if o.CL == "" || o.Description == "" || o.BuilderAbi == "" { - err := errors.New("Missing expected argument") - return nil, log.Err(ctx, err, "build bot packages require the CL, desciption and builder ABI") - } - if o.Track == "" { - o.Track = "master" - } - } else { - typ = o.initFromGit(ctx) - } - - if o.Uploader == "" { - // guess uploader from environment - if user, err := user.Current(); err == nil { - o.Uploader = user.Username - log.I(ctx, "Detected uploader %s", o.Uploader) - } - } - log.I(ctx, "Detected build type %s", typ) - builder := &device.Instance{Configuration: &device.Configuration{}} - if o.BuilderAbi != "" { - if typ == build.BuildBot { - builder.Name = "BuildBot" - } - builder.Configuration.ABIs = []*device.ABI{device.ABIByName(o.BuilderAbi)} - } - if len(builder.Configuration.ABIs) == 0 { - builder = host.Instance(ctx) - } - return &build.Information{ - Type: typ, - Branch: o.Track, - Cl: o.CL, - Tag: o.Tag, - Description: o.Description, - Builder: builder, - Uploader: o.Uploader, - }, nil -} - -func (o *UploadOptions) initFromGit(ctx context.Context) (typ build.Type) { - // Assume not clean, until we can verify. - typ = build.Local - - g, err := git.New(".") - if err != nil { - log.E(ctx, "Git failed. Error: %v", err) - return - } - - if cl, err := g.HeadCL(ctx, o.CL); err != nil { - log.E(ctx, "CL failed. Error: %v", err) - } else { - if o.CL == "" { - // guess cl from git - o.CL = cl.SHA.String() - log.I(ctx, "Detected CL %s", o.CL) - } - if o.Description == "" { - // guess description from git - o.Description = cl.Subject - log.I(ctx, "Detected description %s", o.Description) - } - } - - if status, err := g.Status(ctx); err != nil { - log.E(ctx, "Status failed. Error: %v", err) - } else if status.Clean() { - typ = build.User - } - - if o.Track == "" { - // guess branch from git - if branch, err := g.CurrentBranch(ctx); err != nil { - log.E(ctx, "Branch failed. Error: %v", err) - o.Track = "auto" - } else { - o.Track = branch - log.I(ctx, "Detected track %s", o.Track) - } - } - return -} - -func zip(in file.Path) (*bytes.Buffer, error) { - buf := new(bytes.Buffer) - if err := file.ZIP(buf, in); err != nil { - return nil, err - } - return buf, nil -} - -type artifactSearchVerb struct { - RobotOptions -} - -func (v *artifactSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - b := build.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return b.SearchArtifacts(ctx, expr.Query(), func(ctx context.Context, entry *build.Artifact) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -type packageSearchVerb struct { - RobotOptions -} - -func (v *packageSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - b := build.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return b.SearchPackages(ctx, expr.Query(), func(ctx context.Context, entry *build.Package) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -type trackSearchVerb struct { - RobotOptions -} - -func (v *trackSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - b := build.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return b.SearchTracks(ctx, expr.Query(), func(ctx context.Context, entry *build.Track) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -var idOrName = script.MustParse("Id == $ or Name == $").Using("$") - -type trackUpdateVerb struct { - RobotOptions - Name string `help:"The new name for the track"` - Description string `help:"A description of the track"` - Pkg string `help:"The id of the package at the head of the track"` -} - -func (v *trackUpdateVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - b := build.NewRemote(ctx, conn) - args := flags.Args() - track := &build.Track{ - Name: v.Name, - Description: v.Description, - Head: v.Pkg, - } - if len(args) != 0 { - // Updating an existing track, find it first - err := b.SearchTracks(ctx, idOrName(args[0]).Query(), func(ctx context.Context, entry *build.Track) error { - if track.Id != "" { - return log.Err(ctx, nil, "Multiple tracks matched") - } - track.Id = entry.Id - return nil - }) - if err != nil { - return err - } - if track.Id == "" { - return log.Err(ctx, nil, "No tracks matched") - } - } - track, err := b.UpdateTrack(ctx, track) - if err != nil { - return err - } - log.I(ctx, track.String()) - return nil - }, grpc.WithInsecure()) -} - -type packageUpdateVerb struct { - RobotOptions - Description string `help:"A description of the track"` - Parent string `help:"The id of the package that will be the new parent"` -} - -func (v *packageUpdateVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - b := build.NewRemote(ctx, conn) - args := flags.Args() - pkg := &build.Package{ - Information: &build.Information{Description: v.Description}, - Parent: v.Parent, - } - if len(args) == 0 { - return log.Err(ctx, nil, "Missing argument, must specify a package to update") - } - err := b.SearchPackages(ctx, script.MustParse("Id == $").Using("$")(args[0]).Query(), func(ctx context.Context, entry *build.Package) error { - if pkg.Id != "" { - return log.Err(ctx, nil, "Multiple packages matched") - } - pkg.Id = entry.Id - return nil - }) - if err != nil { - return err - } - if pkg.Id == "" { - return log.Err(ctx, nil, "No packages matched") - } - pkg, err = b.UpdatePackage(ctx, pkg) - if err != nil { - return err - } - log.I(ctx, pkg.String()) - return nil - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/job.go b/cmd/robot/job.go deleted file mode 100644 index 7e90ebbd70..0000000000 --- a/cmd/robot/job.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "io/ioutil" - "os" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/master" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/report" - "github.com/google/gapid/test/robot/search/script" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "github.com/google/gapid/test/robot/trace" - "google.golang.org/grpc" -) - -func init() { - searchVerb.Add(&app.Verb{ - Name: "device", - ShortHelp: "List the devices", - ShortUsage: "", - Action: &deviceSearchFlags{RobotOptions: defaultRobotOptions}, - }) - searchVerb.Add(&app.Verb{ - Name: "worker", - ShortHelp: "List the workers", - ShortUsage: "", - Action: &workerSearchFlags{RobotOptions: defaultRobotOptions}, - }) - startVerb.Add(&app.Verb{ - Name: "worker", - ShortHelp: "Starts a robot worker", - Action: &workerStartFlags{RobotOptions: defaultRobotOptions}, - }) -} - -type deviceSearchFlags struct { - RobotOptions -} - -func (v *deviceSearchFlags) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - w := job.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return w.SearchDevices(ctx, expr.Query(), func(ctx context.Context, entry *job.Device) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -type workerSearchFlags struct { - RobotOptions -} - -func (v *workerSearchFlags) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - w := job.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return w.SearchWorkers(ctx, expr.Query(), func(ctx context.Context, entry *job.Worker) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -type workerStartFlags struct { - RobotOptions -} - -func (v *workerStartFlags) Run(ctx context.Context, flags flag.FlagSet) error { - tempName, err := ioutil.TempDir("", "robot") - if err != nil { - return err - } - tempDir := file.Abs(tempName) - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - m := master.NewClient(ctx, master.NewRemoteMaster(ctx, conn)) - managers := monitor.Managers{ - Stash: stashgrpc.MustConnect(ctx, conn), - Trace: trace.NewRemote(ctx, conn), - Report: report.NewRemote(ctx, conn), - Replay: replay.NewRemote(ctx, conn), - } - if err := startAllWorkers(ctx, managers, tempDir); err != nil { - return err - } - shutdown, err := m.Orbit(ctx, master.ServiceList{Worker: true}) - if err != nil { - return err - } - if shutdown.Restart { - return app.Restart - } - return nil - }, grpc.WithInsecure()) -} - -func startAllWorkers(ctx context.Context, managers monitor.Managers, tempDir file.Path) error { - ctx = job.BindRegistry(ctx) - // TODO: not just ignore all the errors... - crash.Go(func() { trace.Run(ctx, managers.Stash, managers.Trace, tempDir) }) - crash.Go(func() { report.Run(ctx, managers.Stash, managers.Report, tempDir) }) - crash.Go(func() { replay.Run(ctx, managers.Stash, managers.Replay, tempDir) }) - return nil -} diff --git a/cmd/robot/main.go b/cmd/robot/main.go deleted file mode 100644 index 467ee2a6e4..0000000000 --- a/cmd/robot/main.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "github.com/google/gapid/core/app" - _ "github.com/google/gapid/test/robot/stash/grpc" - _ "github.com/google/gapid/test/robot/stash/local" -) - -func main() { - app.ShortHelp = "Robot is a command line tool for interacting with gapid automatic test servers." - app.Run(app.VerbMain) -} diff --git a/cmd/robot/master.go b/cmd/robot/master.go deleted file mode 100644 index 652f32fb73..0000000000 --- a/cmd/robot/master.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "fmt" - "io/ioutil" - "net" - "net/url" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/core/os/flock" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/master" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/report" - "github.com/google/gapid/test/robot/scheduler" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/stash" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "github.com/google/gapid/test/robot/subject" - "github.com/google/gapid/test/robot/trace" - "github.com/google/gapid/test/robot/web" - "google.golang.org/grpc" -) - -const defaultMasterPort = 8081 - -var defaultMasterAddress = fmt.Sprintf("localhost:%v", defaultMasterPort) - -func init() { - startVerb.Add(&app.Verb{ - Name: "master", - ShortHelp: "Starts a robot master server", - Action: &masterVerb{ - BaseAddr: file.Abs("."), - StashAddr: "", - ShelfAddr: "", - Port: defaultMasterPort, - StartWorkers: true, - StartWeb: true, - WebPort: 8080, - }, - }) - searchVerb.Add(&app.Verb{ - Name: "master", - ShortHelp: "List satellites registered with the master", - ShortUsage: "", - Action: &masterSearchVerb{RobotOptions: defaultRobotOptions}, - }) -} - -type masterVerb struct { - BaseAddr file.Path `help:"The base path for all robot files"` - StashAddr string `help:"The address of the stash, defaults to a directory below base"` - ShelfAddr string `help:"The path to the persisted data, defaults to a directory below base"` - Port int `help:"The port to serve the master on"` - StartWorkers bool `help:"Enables local workers"` - StartWeb bool `help:"Enables serving the web client"` - WebPort int `help:"The port to serve the website on"` - Root file.Path `help:"The directory to use as the root of static content"` -} - -func (v *masterVerb) Run(ctx context.Context, flags flag.FlagSet) error { - tempName, err := ioutil.TempDir("", "robot") - if err != nil { - return err - } - tempDir := file.Abs(tempName) - restart := false - serverAddress := fmt.Sprintf(":%v", v.Port) - err = grpcutil.Serve(ctx, serverAddress, func(ctx context.Context, listener net.Listener, server *grpc.Server) error { - managers := monitor.Managers{} - err := error(nil) - var stashURL *url.URL - var shelfURL *url.URL - if v.StashAddr == "" { - stashURL = v.BaseAddr.Join("stash").URL() - } else if shelfURL, err = url.Parse(v.StashAddr); err != nil { - return log.Errf(ctx, err, "Invalid server location", v.StashAddr) - } - if v.ShelfAddr == "" { - shelfURL = v.BaseAddr.Join("shelf").URL() - } else if stashURL, err = url.Parse(v.ShelfAddr); err != nil { - return log.Errf(ctx, err, "Invalid record shelf location", v.ShelfAddr) - } - library := record.NewLibrary(ctx) - shelf, err := record.NewShelf(ctx, shelfURL) - if err != nil { - return log.Errf(ctx, err, "Could not open shelf: %v", shelfURL) - } - library.Add(ctx, shelf) - if managers.Stash, err = stash.Dial(ctx, stashURL); err != nil { - return log.Errf(ctx, err, "Could not open stash: %v", stashURL) - } - managers.Master = master.NewLocal(ctx) - if managers.Subject, err = subject.NewLocal(ctx, library, managers.Stash); err != nil { - return err - } - if managers.Build, err = build.NewLocal(ctx, managers.Stash, library); err != nil { - return err - } - if managers.Job, err = job.NewLocal(ctx, library); err != nil { - return err - } - if managers.Trace, err = trace.NewLocal(ctx, library, managers.Job); err != nil { - return err - } - if managers.Report, err = report.NewLocal(ctx, library, managers.Job); err != nil { - return err - } - if managers.Replay, err = replay.NewLocal(ctx, library, managers.Job); err != nil { - return err - } - if err := serveAll(ctx, server, managers); err != nil { - return err - } - if err := flock.ReleaseAllLocks(); err != nil { - return log.Errf(ctx, err, "Could not remove FLock files for all devices") - } - if v.StartWorkers { - if err := startAllWorkers(ctx, managers, tempDir); err != nil { - return err - } - } - crash.Go(func() { - if err := monitor.Run(ctx, managers, monitor.NewDataOwner(), scheduler.Tick); err != nil { - log.E(ctx, "Scheduler died. Error: %v", err) - } - }) - - if v.StartWeb { - config := web.Config{ - Port: v.WebPort, - StaticRoot: v.Root, - Managers: managers, - } - w, err := web.Create(ctx, config) - if err != nil { - return err - } - crash.Go(func() { w.Serve(ctx) }) - } - - c := master.NewClient(ctx, managers.Master) - services := master.ServiceList{ - Master: true, - Worker: v.StartWorkers, - Web: v.StartWeb, - } - crash.Go(func() { - shutdown, err := c.Orbit(ctx, services) - if err != nil { - log.I(ctx, "Orbit failed") - server.Stop() - return - } - restart = shutdown.Restart - if shutdown.Now { - log.I(ctx, "Kill now") - server.Stop() - } else { - log.I(ctx, "Graceful stop") - server.GracefulStop() - } - }) - return nil - }) - if restart { - return app.Restart - } - return err -} - -func serveAll(ctx context.Context, server *grpc.Server, managers monitor.Managers) error { - if err := master.Serve(ctx, server, managers.Master); err != nil { - return err - } - if err := stashgrpc.Serve(ctx, server, managers.Stash); err != nil { - return err - } - if err := subject.Serve(ctx, server, managers.Subject); err != nil { - return err - } - if err := build.Serve(ctx, server, managers.Build); err != nil { - return err - } - if err := job.Serve(ctx, server, managers.Job); err != nil { - return err - } - if err := trace.Serve(ctx, server, managers.Trace); err != nil { - return err - } - if err := report.Serve(ctx, server, managers.Report); err != nil { - return err - } - if err := replay.Serve(ctx, server, managers.Replay); err != nil { - return err - } - return nil -} - -type masterSearchVerb struct { - RobotOptions -} - -func (v *masterSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - m := master.NewRemoteMaster(ctx, conn) - expression := strings.Join(flags.Args(), " ") - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return m.Search(ctx, expr.Query(), func(ctx context.Context, entry *master.Satellite) error { - log.I(ctx, "%s", entry.String()) - return nil - }) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/replay.go b/cmd/robot/replay.go deleted file mode 100644 index e4c36018a6..0000000000 --- a/cmd/robot/replay.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/search/script" - "google.golang.org/grpc" -) - -func init() { - searchVerb.Add(&app.Verb{ - Name: "replay", - ShortHelp: "List build replays in the server", - ShortUsage: "", - Action: &replaySearchFlags{RobotOptions: defaultRobotOptions}, - }) -} - -type replaySearchFlags struct { - RobotOptions -} - -func (v *replaySearchFlags) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - replays := replay.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return replays.Search(ctx, expr.Query(), func(ctx context.Context, entry *replay.Action) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/report.go b/cmd/robot/report.go deleted file mode 100644 index 83d6183d1f..0000000000 --- a/cmd/robot/report.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/report" - "github.com/google/gapid/test/robot/search/script" - "google.golang.org/grpc" -) - -func init() { - searchVerb.Add(&app.Verb{ - Name: "report", - ShortHelp: "List build reports in the server", - ShortUsage: "", - Action: &reportSearchFlags{RobotOptions: defaultRobotOptions}, - }) -} - -type reportSearchFlags struct { - RobotOptions -} - -func (v *reportSearchFlags) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - reports := report.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return reports.Search(ctx, expr.Query(), func(ctx context.Context, entry *report.Action) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/stash.go b/cmd/robot/stash.go deleted file mode 100644 index aca6bb63dd..0000000000 --- a/cmd/robot/stash.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/stash" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "google.golang.org/grpc" -) - -func init() { - uploadVerb.Add(&app.Verb{ - Name: "stash", - ShortHelp: "Upload a file to the stash", - ShortUsage: "", - Action: &stashUploadVerb{RobotOptions: defaultRobotOptions}, - }) - searchVerb.Add(&app.Verb{ - Name: "stash", - ShortHelp: "List entries in the stash", - ShortUsage: "", - Action: &stashSearchVerb{RobotOptions: defaultRobotOptions}, - }) -} - -type stashUploadVerb struct { - RobotOptions -} - -func (v *stashUploadVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return upload(ctx, paths(flags.Args()), v.ServerAddress, v) -} -func (stashUploadVerb) prepare(context.Context, *grpc.ClientConn) error { return nil } -func (stashUploadVerb) process(context.Context, string) error { return nil } - -type stashSearchVerb struct { - RobotOptions -} - -func (v *stashSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - store, err := stashgrpc.Connect(ctx, conn) - if err != nil { - return err - } - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return store.Search(ctx, expr.Query(), func(ctx context.Context, entry *stash.Entity) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/subject.go b/cmd/robot/subject.go deleted file mode 100644 index 0d25fe5236..0000000000 --- a/cmd/robot/subject.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - "time" - - "github.com/google/gapid/core/os/file" - - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/subject" - "google.golang.org/grpc" -) - -func init() { - uploadVerb.Add(&app.Verb{ - Name: "subject", - ShortHelp: "Upload a traceable application to the server", - ShortUsage: "", - Action: &subjectUploadVerb{RobotOptions: defaultRobotOptions, API: GLESAPI, ObserveFrames: 0}, - }) - searchVerb.Add(&app.Verb{ - Name: "subject", - ShortHelp: "List traceable applications in the server", - ShortUsage: "", - Action: &subjectSearchVerb{RobotOptions: defaultRobotOptions}, - }) - setVerb.Add(&app.Verb{ - Name: "subject", - ShortHelp: "Sets values on a subject", - ShortUsage: "", - Action: &subjectUpdateVerb{RobotOptions: defaultRobotOptions}, - }) -} - -const ( - GLESAPI APIType = iota - VulkanAPI -) - -type APIType uint8 - -var apiTypeToName = map[APIType]string{ - GLESAPI: "gles", - VulkanAPI: "vulkan", -} - -func (a *APIType) Choose(c interface{}) { - *a = c.(APIType) -} -func (a APIType) String() string { - return apiTypeToName[a] -} - -type subjectUploadVerb struct { - RobotOptions - API APIType `help:"the api to capture, can be either gles or vulkan (default:gles)"` - TraceTime time.Duration `help:"trace time override (if non-zero)"` - OBB file.Path `help:"path of the subject's obb file"` - obbID string - ObserveFrames uint `help:"Observe the given number of frames. 0 for all (default:0)"` - subjects subject.Subjects -} - -func (v *subjectUploadVerb) Run(ctx context.Context, flags flag.FlagSet) error { - if !v.OBB.IsEmpty() { - if len(flags.Args()) != 1 { - return log.Err(ctx, nil, "Cannot specify multiple subjects with OBB flag") - } - log.I(ctx, "Uploading OBB: %s", v.OBB) - return upload(ctx, []uploadable{path(v.OBB.String()), path(flags.Arg(0))}, v.ServerAddress, v) - } - return upload(ctx, paths(flags.Args()), v.ServerAddress, v) -} -func (v *subjectUploadVerb) prepare(ctx context.Context, conn *grpc.ClientConn) error { - v.subjects = subject.NewRemote(ctx, conn) - return nil -} -func (v *subjectUploadVerb) process(ctx context.Context, id string) error { - if !v.OBB.IsEmpty() && v.obbID == "" { - // obbID always comes first so just set it here. - log.I(ctx, "Uploaded OBB, ID: %s", id) - v.obbID = id - return nil - } - hints := &subject.Hints{} - if v.TraceTime != 0 { - hints.TraceTime = ptypes.DurationProto(v.TraceTime) - } - hints.ObserveFrames = uint32(v.ObserveFrames) - hints.API = v.API.String() - subject, created, err := v.subjects.Add(ctx, id, v.obbID, hints) - if err != nil { - return log.Err(ctx, err, "Failed processing subject") - } - if created { - log.I(ctx, "Added new subject") - } else { - log.I(ctx, "Already existing subject") - } - - log.I(ctx, "Subject info %s", subject) - return nil -} - -type subjectSearchVerb struct { - RobotOptions -} - -func (v *subjectSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - subjects := subject.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return subjects.Search(ctx, expr.Query(), func(ctx context.Context, entry *subject.Subject) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} - -var idOrApkName = script.MustParse("Id == $ or Information.APK.Name == $").Using("$") - -type subjectUpdateVerb struct { - RobotOptions - API APIType `help:"the new api to capture, can be either gles or vulkan"` - TraceTime time.Duration `help:"the new trace time override"` -} - -func (v *subjectUpdateVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - s := subject.NewRemote(ctx, conn) - args := flags.Args() - subj := &subject.Subject{ - Hints: &subject.Hints{ - TraceTime: ptypes.DurationProto(v.TraceTime), - API: v.API.String(), - }, - } - if len(args) == 0 { - return log.Err(ctx, nil, "Missing argument, must specify a subject to update") - } - err := s.Search(ctx, idOrApkName(args[0]).Query(), func(ctx context.Context, entry *subject.Subject) error { - if subj.Id != "" { - return log.Err(ctx, nil, "Multiple subjects matched") - } - subj.Id = entry.Id - return nil - }) - if err != nil { - return err - } - if subj.Id == "" { - return log.Err(ctx, nil, "No packages matched") - } - subj, err = s.Update(ctx, subj) - if err != nil { - return err - } - log.I(ctx, subj.String()) - return nil - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/trace.go b/cmd/robot/trace.go deleted file mode 100644 index 9801d97425..0000000000 --- a/cmd/robot/trace.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/trace" - "google.golang.org/grpc" -) - -func init() { - uploadVerb.Add(&app.Verb{ - Name: "trace", - ShortHelp: "Upload a gfx trace to the server", - ShortUsage: "", - Action: &traceUploadVerb{RobotOptions: defaultRobotOptions}, - }) - searchVerb.Add(&app.Verb{ - Name: "trace", - ShortHelp: "List build traces in the server", - ShortUsage: "", - Action: &traceSearchVerb{RobotOptions: defaultRobotOptions}, - }) -} - -type traceUploadVerb struct { - RobotOptions - - traces trace.Manager -} - -func (v *traceUploadVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return upload(ctx, paths(flags.Args()), v.ServerAddress, v) -} -func (v *traceUploadVerb) prepare(ctx context.Context, conn *grpc.ClientConn) error { - v.traces = trace.NewRemote(ctx, conn) - return nil -} -func (v *traceUploadVerb) process(ctx context.Context, id string) error { - return v.traces.Update(ctx, "", job.Succeeded, &trace.Output{Trace: id}) -} - -type traceSearchVerb struct { - RobotOptions -} - -func (v *traceSearchVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - traces := trace.NewRemote(ctx, conn) - expression := strings.Join(flags.Args(), " ") - out := os.Stdout - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - return traces.Search(ctx, expr.Query(), func(ctx context.Context, entry *trace.Action) error { - proto.MarshalText(out, entry) - return nil - }) - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/upload.go b/cmd/robot/upload.go deleted file mode 100644 index 54400c0d16..0000000000 --- a/cmd/robot/upload.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/stash" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "google.golang.org/grpc" -) - -type uploader interface { - prepare(context.Context, *grpc.ClientConn) error - process(context.Context, string) error -} - -type uploadable interface { - upload(ctx context.Context, client *stash.Client) (string, error) -} - -type path string - -func (p path) upload(ctx context.Context, client *stash.Client) (string, error) { - return client.UploadFile(ctx, file.Abs(string(p))) -} - -func paths(paths []string) []uploadable { - r := make([]uploadable, len(paths)) - for i, p := range paths { - r[i] = path(p) - } - return r -} - -type slice struct { - data []byte - info stash.Upload -} - -func (s slice) upload(ctx context.Context, client *stash.Client) (string, error) { - return client.UploadBytes(ctx, s.info, s.data) -} - -func data(data []byte, name string, executable bool) slice { - return slice{ - data: data, - info: stash.Upload{ - Name: []string{name}, - Executable: executable, - }, - } -} - -func upload(ctx context.Context, uploadables []uploadable, serverAddress string, u uploader) error { - if len(uploadables) == 0 { - app.Usage(ctx, "No files given") - return nil - } - return grpcutil.Client(ctx, serverAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - client, err := stashgrpc.Connect(ctx, conn) - if err != nil { - return err - } - if err := u.prepare(ctx, conn); err != nil { - return err - } - for _, partial := range uploadables { - id, err := partial.upload(ctx, client) - if err != nil { - return log.Err(ctx, err, "Failed calling Upload") - } - log.I(ctx, "Uploaded %s", id) - if err := u.process(ctx, id); err != nil { - return err - } - } - return nil - }, grpc.WithInsecure()) -} diff --git a/cmd/robot/web.go b/cmd/robot/web.go deleted file mode 100644 index 22f147f1d7..0000000000 --- a/cmd/robot/web.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/master" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/report" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "github.com/google/gapid/test/robot/subject" - "github.com/google/gapid/test/robot/trace" - "github.com/google/gapid/test/robot/web" - "google.golang.org/grpc" -) - -func init() { - startVerb.Add(&app.Verb{ - Name: "web", - ShortHelp: "Starts a robot web server", - Action: &webVerb{ - RobotOptions: defaultRobotOptions, - Port: 8080, - }, - }) -} - -type webVerb struct { - RobotOptions - - Port int `help:"The port to serve the website on"` - Root file.Path `help:"The directory to use as the root of static content"` -} - -func (v *webVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return grpcutil.Client(ctx, v.ServerAddress, func(ctx context.Context, conn *grpc.ClientConn) error { - config := web.Config{ - Port: v.Port, - StaticRoot: v.Root, - Managers: monitor.Managers{ - Master: master.NewRemoteMaster(ctx, conn), - Stash: stashgrpc.MustConnect(ctx, conn), - Build: build.NewRemote(ctx, conn), - Subject: subject.NewRemote(ctx, conn), - Job: job.NewRemote(ctx, conn), - Trace: trace.NewRemote(ctx, conn), - Replay: replay.NewRemote(ctx, conn), - Report: report.NewRemote(ctx, conn), - }, - } - w, err := web.Create(ctx, config) - if err != nil { - return err - } - m := master.NewClient(ctx, config.Master) - restart := false - crash.Go(func() { - shutdown, err := m.Orbit(ctx, master.ServiceList{Worker: true}) - if err != nil { - return - } - restart = shutdown.Restart - w.Close() - }) - log.I(ctx, "Starting web server") - err = w.Serve(ctx) - if restart { - return app.Restart - } - return err - }, grpc.WithInsecure()) -} diff --git a/cmd/stash/BUILD.bazel b/cmd/stash/BUILD.bazel deleted file mode 100644 index 1cca79239f..0000000000 --- a/cmd/stash/BUILD.bazel +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "main.go", - "search.go", - "server.go", - "upload.go", - ], - importpath = "github.com/google/gapid/cmd/stash", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/file:go_default_library", - "//test/robot/search/script:go_default_library", - "//test/robot/stash:go_default_library", - "//test/robot/stash/grpc:go_default_library", - "//test/robot/stash/local:go_default_library", - "@org_golang_google_grpc//:go_default_library", - ], -) - -go_binary( - name = "stash", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/cmd/stash/main.go b/cmd/stash/main.go deleted file mode 100644 index 8fb5c85282..0000000000 --- a/cmd/stash/main.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "net/url" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/stash" - _ "github.com/google/gapid/test/robot/stash/grpc" - _ "github.com/google/gapid/test/robot/stash/local" -) - -var ( - stashAddr = "" - defaultStash = "." - defaultStashServer = "//localhost:8091" -) - -func init() { - flag.StringVar(&stashAddr, "stash", "", "The address of the stash") -} - -func main() { - app.ShortHelp = "Stash is a command line tool for interacting with gapid stash servers." - app.Run(app.VerbMain) -} - -type storeTask func(context.Context, *stash.Client) error - -func withStore(ctx context.Context, isServer bool, task storeTask) error { - if stashAddr == "" { - if isServer { - stashAddr = defaultStash - } else { - stashAddr = defaultStashServer - } - } - stashURL, err := url.Parse(stashAddr) - if err != nil { - return log.Errf(ctx, err, "Invalid shash address %s", stashAddr) - } - client, err := stash.Dial(ctx, stashURL) - if err != nil { - return err - } - defer client.Close() - return task(ctx, client) -} diff --git a/cmd/stash/search.go b/cmd/stash/search.go deleted file mode 100644 index 429a66da84..0000000000 --- a/cmd/stash/search.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "os" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/stash" -) - -func init() { - verb := &app.Verb{ - Name: "search", - ShortHelp: "Prints information about stash entries", - Action: &infoVerb{}, - } - app.AddVerb(verb) -} - -type infoVerb struct { - Monitor bool `help:"Monitor for changes"` -} - -func (v *infoVerb) Run(ctx context.Context, flags flag.FlagSet) error { - return withStore(ctx, false, func(ctx context.Context, client *stash.Client) error { - return getInfo(ctx, client, strings.Join(flags.Args(), " "), v.Monitor) - }) -} - -func getInfo(ctx context.Context, client *stash.Client, expression string, monitor bool) error { - expr, err := script.Parse(ctx, expression) - if err != nil { - return log.Err(ctx, err, "Malformed search query") - } - query := expr.Query() - query.Monitor = monitor - err = client.Search(ctx, query, func(ctx context.Context, entry *stash.Entity) error { - log.I(ctx, "%s", entry) - return nil - }) - if err == nil && monitor { - os.Stdin.Read([]byte{0}) - } - return err -} diff --git a/cmd/stash/server.go b/cmd/stash/server.go deleted file mode 100644 index 958276aaa0..0000000000 --- a/cmd/stash/server.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "net" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/stash" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "google.golang.org/grpc" -) - -func init() { - verb := &app.Verb{ - Name: "server", - ShortHelp: "Starts a stash server", - Action: &serverVerb{}, - } - app.AddVerb(verb) -} - -type serverVerb struct{} - -func (v *serverVerb) Run(ctx context.Context, flags flag.FlagSet) error { - serveAt := "" - switch flags.NArg() { - case 0: - serveAt = defaultStashServer - case 1: - serveAt = flags.Arg(0) - default: - app.Usage(ctx, "Expected at most 1 arg (the address to server on)") - return nil - } - log.I(ctx, "Starting server on %s", serveAt) - return withStore(ctx, true, func(ctx context.Context, client *stash.Client) error { - return serveStore(ctx, client, serveAt) - }) -} - -func serveStore(ctx context.Context, client *stash.Client, address string) error { - log.I(ctx, "Serving on %s", address) - return grpcutil.Serve(ctx, address, func(ctx context.Context, listener net.Listener, server *grpc.Server) error { - if err := stashgrpc.Serve(ctx, server, client); err != nil { - return err - } - return nil - }) -} diff --git a/cmd/stash/upload.go b/cmd/stash/upload.go deleted file mode 100644 index 5b966610ef..0000000000 --- a/cmd/stash/upload.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/stash" -) - -func init() { - verb := &app.Verb{ - Name: "upload", - ShortHelp: "Upload a file to the stash", - Action: &uploadVerb{}, - } - app.AddVerb(verb) -} - -type uploadVerb struct{} - -func (v *uploadVerb) Run(ctx context.Context, flags flag.FlagSet) error { - if flags.NArg() == 0 { - app.Usage(ctx, "No files to upload given") - return nil - } - return withStore(ctx, false, func(ctx context.Context, client *stash.Client) error { - return sendFiles(ctx, client, flags.Args()) - }) -} - -func sendFiles(ctx context.Context, client *stash.Client, filenames []string) error { - for _, partial := range filenames { - id, err := client.UploadFile(ctx, file.Abs(partial)) - if err != nil { - return log.Err(ctx, err, "Failed calling Upload") - } - log.I(ctx, "Uploaded %s as %s", partial, id) - } - return nil -} diff --git a/test/robot/README.md b/test/robot/README.md deleted file mode 100644 index 10a94256e7..0000000000 --- a/test/robot/README.md +++ /dev/null @@ -1,91 +0,0 @@ -# Robot - automated integration testing system. - -## Components - -### Master - -The master is a process that controls the entire, distributed Robot system. - -The master is the main coordination point, all other service are discovered -through the master. -It's main job is to manage and control the set of satellites. -A satellite is a server that offers any of the other robot services. - -A master instance can be started with: - -```./do run robot start master``` - -By default, this verb will also start a local satellite for locally attached devices. - -### Satellite - -An instance running on a host machine (Windows / MacOS / Linux) that connects to a master -and runs workers. - -A satellite instance can be started with: - -```./do run robot start worker``` - -TODO: Rename verb or satellite! - -### Worker - -A worker runs on a satellite and executes task for a given target device. - -Trace, Report, Replay are all workers. - - -### Package - -A package is a zip file containing GAPID build artifacts (`gapis`, `gapir`, etc.) - -A package can be complete (as in it contains binaries for all hosts, all Android ABIs), or sparse. -Obviously Robot will only be able to execute tasks on devices it has binaries for. - -Packages can be uploaded to the master with: - -```./do run robot upload``` - -or with - -```./do upload``` - -#### TODO: -`./do upload` is supposed to generate the .zip for you, but it seems this functionality [was removed by this CL](https://github.com/google/gapid/commit/8c7d48133268cfdf458e24b6f0622d3d3d8a271f). - -We need some way of regenerating the zip files, locally and on the build machines. - -The layout for a package much match the expected layout in [test/robot/build/artifact.go](https://github.com/google/gapid/blob/cfde04afa4d6f4c384412b669d1aa85f608c9b02/test/robot/build/artifact.go#L83-L107). - -### Subject - -A subject is a tracable application (currently only APKs are supported). - -They can be uploaded to the master with: - -```./do upload subject``` - - -### Tracks - -A track is a sequence of packages, usually ordered by changelist SHA. -There doesn't however need to be a 1:1 package <-> CL mapping in a track. This allows a track to -have entries for Gerrit-style patch-sets. - -There can be multiple tracks and each track has a HEAD package which allows for track forking, much like branches in a git repository. - - -## Running guide - -* Craft a package zip file (see above). -* Attach an Android device, make sure it shows up with `adb devices`. -* In the terminal type: - -``` -./do run robot --log-level verbose start master -./do run robot upload build package.zip -./do run robot upload subject my-app.apk -``` - - - diff --git a/test/robot/build/BUILD.bazel b/test/robot/build/BUILD.bazel deleted file mode 100644 index 1838f5c498..0000000000 --- a/test/robot/build/BUILD.bazel +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "artifact.go", - "build.go", - "doc.go", - "local.go", - "package.go", - "remote.go", - "server.go", - "track.go", - ], - embed = [":build_go_proto"], - importpath = "github.com/google/gapid/test/robot/build", - visibility = ["//visibility:public"], - deps = [ - "//core/app/layout:go_default_library", - "//core/data/id:go_default_library", - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/device:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "//test/robot/stash:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "build_proto", - srcs = ["build.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:device_proto", - "//test/robot/search:search_proto", - ], -) - -go_proto_library( - name = "build_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/build", - proto = ":build_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/build/artifact.go b/test/robot/build/artifact.go deleted file mode 100644 index 7b2a046085..0000000000 --- a/test/robot/build/artifact.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "archive/zip" - "bytes" - "context" - "io/ioutil" - "reflect" - "sync" - - "github.com/google/gapid/core/app/layout" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" - "github.com/google/gapid/test/robot/stash" -) - -type artifacts struct { - mu sync.Mutex - store *stash.Client - ledger record.Ledger - entries []*Artifact - byID map[string]*Artifact - onAdd event.Broadcast -} - -func (a *artifacts) init(ctx context.Context, store *stash.Client, library record.Library) error { - ledger, err := library.Open(ctx, "artifacts", &Artifact{}) - if err != nil { - return err - } - a.store = store - a.ledger = ledger - a.byID = map[string]*Artifact{} - apply := event.AsHandler(ctx, a.apply) - if err := ledger.Read(ctx, apply); err != nil { - return err - } - ledger.Watch(ctx, apply) - return nil -} - -// apply is called with items coming out of the ledger -// it should be called with the mutation lock already held. -func (a *artifacts) apply(ctx context.Context, artifact *Artifact) error { - old := a.byID[artifact.Id] - if old == nil { - a.entries = append(a.entries, artifact) - a.byID[artifact.Id] = artifact - } else { - *old = *artifact - } - a.onAdd.Send(ctx, artifact) - return nil -} - -func (a *artifacts) search(ctx context.Context, query *search.Query, handler ArtifactHandler) error { - filter := eval.Filter(ctx, query, reflect.TypeOf(&Artifact{}), event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, a.entries) - if query.Monitor { - return event.Monitor(ctx, &a.mu, a.onAdd.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -func (a *artifacts) getID(ctx context.Context, getter func(ctx context.Context) (*zip.File, error), name string) (string, error) { - f, err := getter(ctx) - if err != nil { - return "", log.Err(ctx, err, name+" not in zip file") - } - - // we need to upload the content to stash to get an ID - r, err := f.Open() - if err != nil { - return "", log.Err(ctx, err, "failed to open zip entry for "+name) - } - defer r.Close() - b, err := ioutil.ReadAll(r) - if err != nil { - return "", log.Err(ctx, err, "failed to read zip entry for "+name) - } - - info := stash.Upload{ - Name: []string{f.Name}, - Executable: f.Mode()&0111 != 0, - } - id, err := a.store.UploadBytes(ctx, info, b) - if err != nil { - return "", log.Err(ctx, err, "failed to upload "+name) - } - return id, nil -} - -func (a *artifacts) get(ctx context.Context, id string, builderAbi *device.ABI) (*Artifact, error) { - a.mu.Lock() - defer a.mu.Unlock() - if entry := a.byID[id]; entry != nil { - return entry, nil - } - data, err := a.store.Read(ctx, id) - if err != nil { - return nil, err - } - if len(data) == 0 { - return nil, log.Err(ctx, nil, "Build not in the stash") - } - zipFile, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) - if err != nil { - return nil, log.Err(ctx, nil, "File is not a build artifact.") - } - l := layout.NewZipLayout(zipFile, builderAbi.OS) - - toolSet := ToolSet{Abi: builderAbi, Host: new(HostToolSet)} - if toolSet.Host.Gapir, err = a.getID(ctx, func(ctx context.Context) (*zip.File, error) { - return l.Gapir(ctx, nil) - }, "gapir"); err != nil { - return nil, err - } - if toolSet.Host.Gapis, err = a.getID(ctx, l.Gapis, "gapis"); err != nil { - return nil, err - } - if toolSet.Host.Gapit, err = a.getID(ctx, l.Gapit, "gapit"); err != nil { - return nil, err - } - if toolSet.Host.VirtualSwapChainLib, err = a.getID(ctx, func(ctx context.Context) (*zip.File, error) { - return l.Library(ctx, layout.LibVirtualSwapChain, nil) - }, "libVirtualSwapChain"); err != nil { - return nil, err - } - if toolSet.Host.VirtualSwapChainJson, err = a.getID(ctx, func(ctx context.Context) (*zip.File, error) { - return l.Json(ctx, layout.LibVirtualSwapChain) - }, "libVirtualSwapChain JSON"); err != nil { - return nil, err - } - for _, abi := range []*device.ABI{device.AndroidARMv7a, device.AndroidARM64v8a, device.AndroidX86} { - id, err := a.getID(ctx, func(ctx context.Context) (*zip.File, error) { - return l.GapidApk(ctx, abi) - }, abi.Name+"gapid APK") - if err != nil { - return nil, err - } - toolSet.Android = append(toolSet.Android, &AndroidToolSet{ - Abi: abi, - GapidApk: id, - }) - } - - entry := &Artifact{Id: id, Tool: &toolSet} - a.ledger.Add(ctx, entry) - return entry, nil -} diff --git a/test/robot/build/build.go b/test/robot/build/build.go deleted file mode 100644 index fdbb19b4e3..0000000000 --- a/test/robot/build/build.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - - "github.com/google/gapid/test/robot/search" -) - -// ArtifactHandler is a function used to consume a stream of Artifacts. -type ArtifactHandler func(context.Context, *Artifact) error - -// PackageHandler is a function used to consume a stream of Packages. -type PackageHandler func(context.Context, *Package) error - -// TrackHandler is a function used to consume a stream of Tracks. -type TrackHandler func(context.Context, *Track) error - -// Store is the abstract interface to the storage of build artifacts. -type Store interface { - // SearchArtifacts delivers matching build artifacts to the supplied handler. - SearchArtifacts(ctx context.Context, query *search.Query, handler ArtifactHandler) error - - // SearchPackages delivers matching build packages to the supplied handler. - SearchPackages(ctx context.Context, query *search.Query, handler PackageHandler) error - - // SearchTracks delivers matching build tracks to the supplied handler. - SearchTracks(ctx context.Context, query *search.Query, handler TrackHandler) error - - // Add adds a new build artifact to the store. - Add(ctx context.Context, id string, info *Information) (string, bool, error) - - // UpdateTrack updates track information. - UpdateTrack(ctx context.Context, track *Track) (*Track, error) - - // UpdatePackage updates package information. - UpdatePackage(ctx context.Context, pkg *Package) (*Package, error) -} - -const ( - UnknownType = Type_UnknownType - BuildBot = Type_BuildBot - User = Type_User - Local = Type_Local -) diff --git a/test/robot/build/build.proto b/test/robot/build/build.proto deleted file mode 100644 index dcadc4b9e7..0000000000 --- a/test/robot/build/build.proto +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package build; -option go_package = "github.com/google/gapid/test/robot/build"; - -import "core/os/device/device.proto"; -import "test/robot/search/search.proto"; - -// Type represents a build type. -enum Type { - // UnknownType is the default (invalid) type. - UnknownType = 0; - // BuildBot is the type for builds from the official build bots. - // For these types of builds, the cl must be set and will be used for merging. - BuildBot = 1; - // User is the type for a user built build but without local modifications. - User = 2; - // Local is the type for local modified source builds. - Local = 3; -} - -// Information holds the non inferable meta inforamtion about a build. -message Information { - // Type is the build type. - Type type = 1; - // The branch id if known of this build. This will normally be the git branch - // in the main gapid repository. - string branch = 2; - // Cl is the gapid repository cl at the time of the build if known. - // There may be multiple distinct builds at the same cl if the build is - // allowed local modifications. - string cl = 3; - // Tag is the external tag of the build if known. - // This is most often set by the build bot's, where it is common across all - // the bots for a specific build. - // Build uploads with the same tag will be merged. - string tag = 4; - // Description is a user assigned description of the build. - string description = 5; - // Builder is the device information for the machine that made the build. - device.Instance builder = 6; - // Uploader is the (optional) user name of the uploading entity. - string uploader = 7; -} - -// Artifact holds information about a single uploaded build artifact. -message Artifact { - // Id is the id in the stash of the build artifact. - string id = 1; - // Tool is the set of tools in this artifact - ToolSet tool = 2; -} - -// ToolSet is the information for all of the tools extracted from a particular -// package or artifact. -message ToolSet { - // Abi is the host system this toolset was built on. - device.ABI abi = 1; - // The tools provided from a particular host. - HostToolSet host = 2; - // The tools provided for each supported android abi. - repeated AndroidToolSet android = 3; -} - -// HostToolSet is the information for the tools extracted from a package for a -// particular host device. -message HostToolSet { - // The stash id of the replay daemon. - string gapir = 1; - // The stash id of the graphics analysis server. - string gapis = 2; - // The stash id of the graphics analysis command line tool. - string gapit = 3; - // VirtualSwapChainLib is the stash id of the vulkan virtual-swap-chain loader - // library. - string virtual_swap_chain_lib = 4; - // VirtualSwapChainLib is the stash id of the vulkan virtual-swap-chain loader - // json file. - string virtual_swap_chain_json = 5; -} - -// AndroidToolSet is the information for the tools extracted from a package for -// a particular android ABI. -message AndroidToolSet { - // The Android ABI this tool set runs on. - device.ABI abi = 1; - // The stash id of the gapid.apk. - string gapid_apk = 2; -} - -// Package represents an entry in a build track. -// It contains the merged set of build entries that all represent a single point -// in a tracks history. This allows multiple build outputs, from different build -// machines to be merged into a single package. -message Package { - // Id is the unique id of the package. - string id = 1; - // Parent is the id of the package that precedes this one in the timeline. - string parent = 2; - // Information holds the build metadata. - Information information = 3; - // Artifact is the set of build artifacts that have been added to the package. - repeated string artifact = 4; - // Tool is the set of tools the package supports. - repeated ToolSet tool = 5; -} - -// Track represents a historical timeline of packages. -message Track { - // Id is the unique id of the track. - string id = 1; - // Name is a human readable name for the track, it should still be unique, but - // may change. - string name = 2; - // Head is the id of the package at the head of this track. - string head = 3; - // Description is a human readable explanation for the tracks existance. - string description = 4; -} - -// Service is the api to the robot app storage. -service Service { - // SearchArtifacts is used to find build artifacts that match the given query. - rpc SearchArtifacts(search.Query) returns (stream Artifact) { - }; - // SearchPackages is used to find build packages that match the given query. - rpc SearchPackages(search.Query) returns (stream Package) { - }; - // SearchTracks is used to find build tracks that match the given query. - rpc SearchTracks(search.Query) returns (stream Track) { - }; - // Add pulls the build from the stash, analyzes it and adds it to the service. - // The build may be merged with an existing build set, see Information for - // more details about merging. - rpc Add(AddRequest) returns (AddResponse) { - }; - // UpdateTrack creates or updates a track entry. - rpc UpdateTrack(UpdateTrackRequest) returns (UpdateTrackResponse) { - }; - // UpdatePackage modifies a package entry. - rpc UpdatePackage(UpdatePackageRequest) returns (UpdatePackageResponse) { - }; -} - -message AddRequest { - // Id is the id in the stash of the uploaded build. - string id = 1; - // Information holds the metadata for this entry. - Information information = 2; -} - -message AddResponse { - // Id is the unique id of the build package. - string id = 1; - // Merged will be true if the upload was merged into an existing package. - bool merged = 2; -} - -message UpdateTrackRequest { - // Track contains the information to merge into the track. - // If the id is present, it must match an existing track. - // If only a name is present, and it does not match an existing track, a new - // one will be created. Missing fields will be left alone, present fields will - // be replaced. - Track track = 1; -} - -message UpdateTrackResponse { - // Track is the updated track information. - Track track = 1; -} - -message UpdatePackageRequest { - // Package contains the information to merge into the package. - // If the id is present, it must match an existing package. - // Only updates the Parent and Information.Description fields, only if present - Package package = 1; -} - -message UpdatePackageResponse { - // Package is the updated package information. - Package package = 1; -} diff --git a/test/robot/build/doc.go b/test/robot/build/doc.go deleted file mode 100644 index 6a77bed91d..0000000000 --- a/test/robot/build/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package build holds build package and artifact managment for robot. -package build diff --git a/test/robot/build/local.go b/test/robot/build/local.go deleted file mode 100644 index d78dc692ae..0000000000 --- a/test/robot/build/local.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/stash" -) - -type local struct { - store *stash.Client - - artifacts artifacts - packages packages - tracks tracks -} - -// NewLocal builds a new build artifact manager that persists its data in the -// supplied library, and the artifacts in the supplied stash. -func NewLocal(ctx context.Context, store *stash.Client, library record.Library) (Store, error) { - s := &local{store: store} - if err := s.artifacts.init(ctx, store, library); err != nil { - return nil, err - } - if err := s.packages.init(ctx, library); err != nil { - return nil, err - } - if err := s.tracks.init(ctx, library); err != nil { - return nil, err - } - return s, nil -} - -// SearchArtifacts implements Store.SearchArtifacts -// It searches the set of persisted artifacts, and supports monitoring of artifacts as they arrive. -func (s *local) SearchArtifacts(ctx context.Context, query *search.Query, handler ArtifactHandler) error { - return s.artifacts.search(ctx, query, handler) -} - -// SearchPackages implements Store.SearchPackages -// It searches the set of persisted packages, and supports monitoring of packages as they arrive. -func (s *local) SearchPackages(ctx context.Context, query *search.Query, handler PackageHandler) error { - return s.packages.search(ctx, query, handler) -} - -// SearchTracks implements Store.SearchTracks -// It searches the set of persisted tracks, and supports monitoring of tracks as they arrive. -func (s *local) SearchTracks(ctx context.Context, query *search.Query, handler TrackHandler) error { - return s.tracks.search(ctx, query, handler) -} - -// Add implements Store.Add -// It adds the package to the persisten store, and attempts to add it into the track it should be part of. -func (s *local) Add(ctx context.Context, id string, info *Information) (string, bool, error) { - a, err := s.artifacts.get(ctx, id, info.Builder.Configuration.ABIs[0]) - if err != nil { - return "", false, err - } - pkg, merged, err := s.packages.addArtifact(ctx, a, info) - if err != nil { - return "", false, err - } - if merged { - return pkg.Id, true, nil - } - parent, err := s.tracks.addPackage(ctx, pkg) - if err != nil { - return "", false, err - } - if parent != "" { - if _, err := s.packages.update(ctx, &Package{Id: pkg.Id, Parent: parent}); err != nil { - return "", false, err - } - } - return pkg.Id, false, nil -} - -// UpdateTrack implements store.UpdateTrack -// if the track identified by the track id exists, it modifies the track head pointer, name -// and description, otherwise it creates a new track. -func (s *local) UpdateTrack(ctx context.Context, entry *Track) (*Track, error) { - track, _, err := s.tracks.createOrUpdate(ctx, entry) - return track, err -} - -// UpdatePackage implements store.UpdatePackage -// if the package identified by the package id exists, it modifies the package parent pointer, -// and description. -func (s *local) UpdatePackage(ctx context.Context, entry *Package) (*Package, error) { - return s.packages.update(ctx, entry) -} diff --git a/test/robot/build/package.go b/test/robot/build/package.go deleted file mode 100644 index 8a7c290fae..0000000000 --- a/test/robot/build/package.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - "reflect" - "sync" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -var packageClass = reflect.TypeOf(&Package{}) - -type packages struct { - mu sync.Mutex - ledger record.Ledger - entries []*Package - byID map[string]*Package - byName map[string]*Package - onChange event.Broadcast -} - -func (p *packages) init(ctx context.Context, library record.Library) error { - ledger, err := library.Open(ctx, "packages", &Package{}) - if err != nil { - return err - } - p.ledger = ledger - p.byID = map[string]*Package{} - apply := event.AsHandler(ctx, p.apply) - if err := ledger.Read(ctx, apply); err != nil { - return err - } - ledger.Watch(ctx, apply) - return nil -} - -// apply is called with items coming out of the ledger -// it should be called with the mutation lock already held. -func (p *packages) apply(ctx context.Context, pkg *Package) error { - old := p.byID[pkg.Id] - if old == nil { - p.entries = append(p.entries, pkg) - p.byID[pkg.Id] = pkg - p.onChange.Send(ctx, pkg) - return nil - } - if pkg.Parent != "" { - old.Parent = pkg.Parent - } - if pkg.Information != nil { - // description is the only thing we allow to be edited - if pkg.Information.Description != "" { - old.Information.Description = pkg.Information.Description - } - } - if len(pkg.Artifact) > 0 { - old.Artifact = append(old.Artifact, pkg.Artifact...) - } - for _, t := range pkg.Tool { - old.mergeTool(ctx, t) - } - p.onChange.Send(ctx, old) - return nil -} - -func (p *packages) search(ctx context.Context, query *search.Query, handler PackageHandler) error { - filter := eval.Filter(ctx, query, packageClass, event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, p.entries) - if query.Monitor { - return event.Monitor(ctx, &p.mu, p.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -func (p *packages) update(ctx context.Context, pkg *Package) (*Package, error) { - p.mu.Lock() - defer p.mu.Unlock() - if _, found := p.byID[pkg.Id]; !found { - return nil, log.Err(ctx, nil, "Package not found") - } - if err := p.ledger.Add(ctx, pkg); err != nil { - return nil, err - } - return p.byID[pkg.Id], nil -} - -func (p *packages) addArtifact(ctx context.Context, a *Artifact, info *Information) (*Package, bool, error) { - p.mu.Lock() - defer p.mu.Unlock() - - old := p.findArtifactPackage(ctx, a, info) - pkg := &Package{ - Information: info, - Artifact: []string{a.Id}, - Tool: []*ToolSet{a.Tool}, - } - merged := false - if old != nil { - pkg.Id = old.Id - merged = true - } else { - pkg.Id = id.Unique().String() - } - if err := p.ledger.Add(ctx, pkg); err != nil { - return nil, false, err - } - return p.byID[pkg.Id], merged, nil -} - -func (p *packages) findArtifactPackage(ctx context.Context, a *Artifact, info *Information) *Package { - // Search for a set to merge into - if info.Tag != "" { - // if we have a tag, that's the only thing that matters - for _, pkg := range p.entries { - if pkg.Information.Tag == info.Tag { - return pkg - } - } - } - // Only BuildBot packages can be merged based on CL. - if info.Type == BuildBot && info.Cl != "" { - for _, pkg := range p.entries { - if pkg.Information.Type == BuildBot && pkg.Information.Cl == info.Cl { - return pkg - } - } - } - // No match, cannot merge - return nil -} - -func (pkg *Package) mergeTool(ctx context.Context, tool *ToolSet) { - for _, t := range pkg.Tool { - if t.Abi.SameAs(tool.Abi) { - // merge into existing tool - if tool.Host.Gapir != "" { - t.Host.Gapir = tool.Host.Gapir - } - if tool.Host.Gapis != "" { - t.Host.Gapis = tool.Host.Gapis - } - if tool.Host.Gapit != "" { - t.Host.Gapit = tool.Host.Gapit - } - for _, android := range tool.Android { - if android.GapidApk != "" { - if a := t.FindAndroidToolSet(android.Abi); a != nil { - a.GapidApk = android.GapidApk - } else { - t.Android = append(t.Android, android) - } - } - } - return - } - } - // no matching tool, so just append it - pkg.Tool = append(pkg.Tool, tool) -} - -// GetHostTools will return the toolset that match the abi, if there is one. -func (pkg *Package) GetHostTools(abi *device.ABI) *ToolSet { - for _, t := range pkg.Tool { - if t.Abi.SameAs(abi) { - return t - } - } - return nil -} - -// FindAndroidToolSet will return the toolset for a target ABI, if there is one. -func (t *ToolSet) FindAndroidToolSet(abi *device.ABI) *AndroidToolSet { - for _, a := range t.Android { - if a.Abi.SameAs(abi) { - return a - } - } - return nil -} - -// GetTargetTools will return the toolset for a target ABI that was build by a host ABI, if there is one. -func (pkg *Package) GetTargetTools(hostAbi *device.ABI, targetAbi *device.ABI) *AndroidToolSet { - hostTools := pkg.GetHostTools(hostAbi) - if hostTools == nil { - return nil - } - - return hostTools.FindAndroidToolSet(targetAbi) -} diff --git a/test/robot/build/remote.go b/test/robot/build/remote.go deleted file mode 100644 index f29f6a9ebf..0000000000 --- a/test/robot/build/remote.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a Store that talks to a remote grpc build service. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Store { - return &remote{client: NewServiceClient(conn)} -} - -// SearchArtifacts implements Store.SearchArtifacts -// It forwards the call through grpc to the remote implementation. -func (m *remote) SearchArtifacts(ctx context.Context, query *search.Query, handler ArtifactHandler) error { - stream, err := m.client.SearchArtifacts(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// SearchPackages implements Store.SearchPackages -// It forwards the call through grpc to the remote implementation. -func (m *remote) SearchPackages(ctx context.Context, query *search.Query, handler PackageHandler) error { - stream, err := m.client.SearchPackages(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// SearchTracks implements Store.SearchTracks -// It forwards the call through grpc to the remote implementation. -func (m *remote) SearchTracks(ctx context.Context, query *search.Query, handler TrackHandler) error { - stream, err := m.client.SearchTracks(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Add implements Store.Add -// It forwards the call through grpc to the remote implementation. -func (m *remote) Add(ctx context.Context, id string, info *Information) (string, bool, error) { - request := &AddRequest{Id: id, Information: info} - response, err := m.client.Add(ctx, request) - if err != nil { - return "", false, err - } - return response.Id, response.Merged, nil -} - -// UpdateTrack implements store.UpdateTrack -// It forwards the call through grpc to the remote implementation. -func (m *remote) UpdateTrack(ctx context.Context, entry *Track) (*Track, error) { - request := &UpdateTrackRequest{Track: entry} - response, err := m.client.UpdateTrack(ctx, request) - if err != nil { - return nil, err - } - return response.Track, nil -} - -// UpdatePackage implements store.UpdatePackage -// It forwards the call through grpc to the remote implementation. -func (m *remote) UpdatePackage(ctx context.Context, entry *Package) (*Package, error) { - request := &UpdatePackageRequest{Package: entry} - response, err := m.client.UpdatePackage(ctx, request) - if err != nil { - return nil, err - } - return response.Package, nil -} diff --git a/test/robot/build/server.go b/test/robot/build/server.go deleted file mode 100644 index ff0b2e026f..0000000000 --- a/test/robot/build/server.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - - "github.com/google/gapid/test/robot/search" - - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - store Store -} - -// Serve wraps a store in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, store Store) error { - RegisterServiceServer(grpcServer, &server{store: store}) - return nil -} - -// SearchArtifacts implements ServiceServer.SearchArtifacts -// It delegates the call to the provided Store implementation. -func (s *server) SearchArtifacts(query *search.Query, stream Service_SearchArtifactsServer) error { - ctx := stream.Context() - return s.store.SearchArtifacts(ctx, query, func(ctx context.Context, e *Artifact) error { return stream.Send(e) }) -} - -// SearchPackages implements ServiceServer.SearchPackages -// It delegates the call to the provided Store implementation. -func (s *server) SearchPackages(query *search.Query, stream Service_SearchPackagesServer) error { - ctx := stream.Context() - return s.store.SearchPackages(ctx, query, func(ctx context.Context, e *Package) error { return stream.Send(e) }) -} - -// SearchTracks implements ServiceServer.SearchTrackst -// It delegates the call to the provided Store implementation. -func (s *server) SearchTracks(query *search.Query, stream Service_SearchTracksServer) error { - ctx := stream.Context() - return s.store.SearchTracks(ctx, query, func(ctx context.Context, e *Track) error { return stream.Send(e) }) -} - -// Add implements ServiceServer.Add -// It delegates the call to the provided Store implementation. -func (s *server) Add(outer xctx.Context, request *AddRequest) (*AddResponse, error) { - ctx := outer - id, merged, err := s.store.Add(ctx, request.Id, request.Information) - if err != nil { - return nil, err - } - return &AddResponse{ - Id: id, - Merged: merged, - }, nil -} - -// UpdateTrack implements ServiceServer.UpdateTrack -// It delegates the call to the provided Store implementation. -func (s *server) UpdateTrack(outer xctx.Context, request *UpdateTrackRequest) (*UpdateTrackResponse, error) { - ctx := outer - track, err := s.store.UpdateTrack(ctx, request.Track) - if err != nil { - return nil, err - } - return &UpdateTrackResponse{Track: track}, nil -} - -// UpdatePackage implements ServiceServer.UpdatePackage -// It delegates the call to the provided Store implementation. -func (s *server) UpdatePackage(outer xctx.Context, request *UpdatePackageRequest) (*UpdatePackageResponse, error) { - ctx := outer - pkg, err := s.store.UpdatePackage(ctx, request.Package) - if err != nil { - return nil, err - } - return &UpdatePackageResponse{Package: pkg}, nil -} diff --git a/test/robot/build/track.go b/test/robot/build/track.go deleted file mode 100644 index c0232f2823..0000000000 --- a/test/robot/build/track.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package build - -import ( - "context" - "reflect" - "sync" - - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -var trackClass = reflect.TypeOf(&Track{}) - -type tracks struct { - mu sync.Mutex - ledger record.Ledger - entries []*Track - byID map[string]*Track - byName map[string]*Track - onChange event.Broadcast -} - -func (t *tracks) init(ctx context.Context, library record.Library) error { - ledger, err := library.Open(ctx, "tracks", &Track{}) - if err != nil { - return err - } - t.ledger = ledger - t.byID = map[string]*Track{} - t.byName = map[string]*Track{} - apply := event.AsHandler(ctx, t.apply) - if err := ledger.Read(ctx, apply); err != nil { - return err - } - ledger.Watch(ctx, apply) - return nil -} - -// apply is called with items coming out of the ledger -// it should be called with the mutation lock already held. -func (t *tracks) apply(ctx context.Context, track *Track) error { - old := t.byID[track.Id] - if old == nil { - t.entries = append(t.entries, track) - t.byID[track.Id] = track - if track.Name != "" { - t.byName[track.Name] = track - } - t.onChange.Send(ctx, track) - return nil - } - if track.Name != "" && old.Name != track.Name { - delete(t.byName, old.Name) - old.Name = track.Name - t.byName[old.Name] = old - } - if track.Head != "" && old.Head != track.Head { - old.Head = track.Head - } - if track.Description != "" { - old.Description = track.Description - } - t.onChange.Send(ctx, track) - return nil -} - -func (t *tracks) search(ctx context.Context, query *search.Query, handler TrackHandler) error { - filter := eval.Filter(ctx, query, trackClass, event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, t.entries) - if query.Monitor { - return event.Monitor(ctx, &t.mu, t.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -func (t *tracks) createOrUpdate(ctx context.Context, track *Track) (*Track, string, error) { - t.mu.Lock() - defer t.mu.Unlock() - parent := "" - if track.Id != "" { - // We must be updating an exiting track, and the id must be valid - old, found := t.byID[track.Id] - if !found { - return nil, "", log.Err(ctx, nil, "Track not found") - } - parent = old.Head - } else if track.Name != "" { - if old, found := t.byName[track.Name]; found { - // Matched by name, update the existing entry - track.Id = old.Id - parent = old.Head - } - } - if track.Id == "" { - // We are making a new track, pick a new unique id - track.Id = id.Unique().String() - } - if err := t.ledger.Add(ctx, track); err != nil { - return nil, "", err - } - return t.byID[track.Id], parent, nil -} - -func guessTrackName(ctx context.Context, info *Information) string { - branch := info.Branch - if info.Branch == "" { - // Branch is the primary information for track name, so we always pick one - branch = "auto" - } - if info.Type == BuildBot { - return branch - } - // For non build bot packages, we prepend a user name - user := info.Uploader - if user == "" { - user = "unknown" - } - return user + "-" + branch -} - -func (t *tracks) addPackage(ctx context.Context, pkg *Package) (string, error) { - parent := "" - track := &Track{Name: guessTrackName(ctx, pkg.Information), Head: pkg.Id} - _, parent, err := t.createOrUpdate(ctx, track) - return parent, err -} diff --git a/test/robot/go_robot_go.sh b/test/robot/go_robot_go.sh deleted file mode 100755 index bf6669c13d..0000000000 --- a/test/robot/go_robot_go.sh +++ /dev/null @@ -1,300 +0,0 @@ -#!/bin/bash -# Copyright (C) 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License - -# Script that controls robot master instance, runs a background process to -# swipe on attached devices to keep them unlocked, and manages uploading -# and clearing artifacts and subjects in robot's storage directory. -# can use '--clear' to remove all artifacts and subjects from robot on boot. -shopt -s extglob -OUTDIR="bazel-out/robot" -BUILD_BOT_DIR="${OUTDIR}/build_bot" -SWIPE_COMMAND="shell input swipe 300 300 0 0 500" - -function handle_opts() { - while true; do - case $1 in - -c|--clean) CLEAN=1; shift ;; - --) shift; break ;; - *) echo "internal error!" ; exit 1 ;; - esac - done -} - -function howmany() { echo $#; } - -function find_pid() { pgrep -f "$1" -d " "; } - -function is_device_awake() { - local STATE=`adb -s $1 shell dumpsys nfc | awk -F "=" '/mScreenState/ {print $2}'` - [[ "$STATE" = "ON_UNLOCKED" ]] - return -} - -function kill_swipe() { - local SWIPE_PID=$(find_pid "$SWIPE_COMMAND") - for spid in ${SWIPE_PID}; do - kill -9 $spid - done -} -function start_swipe() { - kill_swipe - - echo ">>> Starting swipe process..." - declare -i NUM_DEVICES=0 - for device in $(adb devices | awk '!/List/ {print $1}'); do - if is_device_awake $device; then - echo ">>> starting swipe process on $device" - nohup watch -n60 "adb -s $device $SWIPE_COMMAND" > /dev/null 2>&1 & - let NUM_DEVICES++ - fi - done - # need to sleep, else we get duplicate processes in our pid list from watch - sleep 2s - local SWIPE_PID=$(find_pid "$SWIPE_COMMAND") - echo ">>> Swiping processes started! PIDs: ${SWIPE_PID}" - if [[ $(howmany $SWIPE_PID) -ne ${NUM_DEVICES} ]]; then - echo ">>> Warning, swiping processed started does not match devices connected..." - echo " processes found: ($(howmany $SWIPE_PID))" - echo " number of devices: (${NUM_DEVICES})" - fi -} - - -function build_grid() { - gopherjs build --minify --output ./test/robot/web/www/grid/grid.js ./test/robot/web/client - bazel build //test/robot/web:embed -} - -function start_master() { - MASTER_COMMAND="bazel-bin/pkg/robot start master" - OLD_MASTER_PID=$(find_pid "$MASTER_COMMAND") - if [[ $OLD_MASTER_PID ]]; then - echo ">>> Found old master process: ${OLD_MASTER_PID}; Killing..." - kill -9 $OLD_MASTER_PID - fi - - echo ">>> Building Robot..." - build_grid - bazel build //cmd/robot:robot - cp -f bazel-bin/cmd/robot/linux_amd64_stripped/robot bazel-bin/pkg/robot - echo ">>> Waiting for master to start..." - nohup bazel-bin/pkg/robot start master -baseaddr "${OUTDIR}" > robot.log 2> roboterr.log & - while ! grep -q "Starting grpc server" < robot.log; do - sleep 1s - done - MASTER_PID=$(find_pid "$MASTER_COMMAND") - echo ">>> Master process started! PID: ${MASTER_PID}" -} - -function clean_output() { - echo ">>> Clearing output directory..." - rm -rf "${OUTDIR}"; -} - -function reset_build_bot() { - if [[ -e "${BUILD_BOT_DIR}" ]]; then - echo ">>> Clearing old build bot artifacts..." - rm -rf "${BUILD_BOT_DIR}"/* - else - echo ">>> Making build bot directory..." - mkdir -p "${BUILD_BOT_DIR}" - fi - pushd "${BUILD_BOT_DIR}" > /dev/null - mkdir gapid/ - mkdir gapid/android-armv8a/ - mkdir gapid/android-armv7a/ - mkdir gapid/android-x86/ - popd > /dev/null -} - -function pack_local() { - reset_build_bot - - echo ">>> Building local artifacts..." - bazel build pkg - echo ">>> Packaging local artifacts..." - cp bazel-bin/pkg/lib/*VirtualSwapchain* ${BUILD_BOT_DIR}/gapid/ - cp bazel-bin/pkg/gapir ${BUILD_BOT_DIR}/gapid/ - cp bazel-bin/pkg/gapis ${BUILD_BOT_DIR}/gapid/ - cp bazel-bin/pkg/gapit ${BUILD_BOT_DIR}/gapid/ - cp bazel-bin/pkg/gapid-arm64-v8a.apk ${BUILD_BOT_DIR}/gapid/android-armv8a/ - cp bazel-bin/pkg/gapid-armeabi-v7a.apk ${BUILD_BOT_DIR}/gapid/android-armv7a/ - cp bazel-bin/pkg/gapid-x86.apk ${BUILD_BOT_DIR}/gapid/android-x86/ - if [[ -z "$(git status -z | tr -d \0)" ]]; then - BUILD_BOT_CL="$(git log --pretty="format:%H" -1 .)" - BUILD_BOT_UPLOADER="$(git log --pretty="format:%an" -1 .)" - BUILD_BOT_TRACK="$(git rev-parse --abbrev-ref HEAD)" - BUILD_BOT_DESCRIPTION="$(git log --pretty="%s" -1 .)" - else - BUILD_BOT_CL="$(git log --pretty="format:%H" -1 .)⚫" - BUILD_BOT_UPLOADER="$USER" - BUILD_BOT_TRACK="$(git rev-parse --abbrev-ref HEAD)⚫" - fi - - upload_build_bot -} - -function upload_build_bot() { - pushd "${BUILD_BOT_DIR}" > /dev/null - zip gapid-build-bot.zip gapid/gapi[rst] gapid/*VirtualSwapchain* gapid/android-*/*.apk - popd > /dev/null - - bazel-bin/pkg/robot upload build $BUILD_BOT_TAG -cl="$BUILD_BOT_CL" -description="$BUILD_BOT_DESCRIPTION" -track="$BUILD_BOT_TRACK" -uploader="$BUILD_BOT_UPLOADER" "${BUILD_BOT_DIR}/gapid-build-bot.zip" > /dev/null 2> uploaderr.log - - BUILD_BOT_CL= - BUILD_BOT_UPLOADER= - BUILD_BOT_TRACK= - BUILD_BOT_DESCRIPTION= - BUILD_BOT_TAG= - - if grep -q "exit status 1" uploaderr.log; then - echo ">>> Upload failed:" - cat uploaderr.log - return 1 - fi - echo ">>> Uploaded build bot artifacts" - return 0 -} - -function test_subj() { - local SUBJ=$1 - local SUBJFILE=${SUBJ##*/} - local OBBFILE=( ${SUBJ%/*}/main.*.${SUBJFILE%%.apk}.obb ) - - echo "Choose device to test on..." - adb devices - local DEV - read DEV - - adb -s $DEV install $SUBJ - if [[ -e $OBBFILE ]]; then - adb -s $DEV push $OBBFILE /sdcard/Android/obb/${SUBJFILE%%.apk}/${OBBFILE##*/} - fi - - echo "Subject installed, press any key to continue..." - read -n 1 -s -r - - - echo "Running gapid..." - bazel-bin/pkg/gapid - echo "gapid done." - - adb -s $DEV uninstall ${SUBJFILE%%.apk} -} - -function upload_subj() { - local SUBJ=$1 - local SUBJFILE=${SUBJ##*/} - local OBBFILE=( ${SUBJ%/*}/main.*.${SUBJFILE%%.apk}.obb ) - local API - local OBB - API=gles - if [[ $* = *"vk"* || $* = *"vulkan"* ]]; then - API=vulkan - echo "vulkan apk detected..." - fi - if [[ -e "$OBBFILE" ]]; then - OBB=-obb="$OBBFILE" - echo "obb file detected \"$OBBFILE\"..." - fi - - echo ">>> Uploading subject $SUBJ" - local FRAMES - read -p ">>> Enter frames to observe [default: 30]: " FRAMES - FRAMES=${FRAMES:=30} - bazel-bin/pkg/robot upload subject -observeframes=$FRAMES -api="$API" $OBB $SUBJ > /dev/null 2>> uploaderr.log - echo ">>> Uploaded" -} - -function upload_dir() { - for subj in "$1"/*.apk; do - upload_subj "$subj" - done -} - -function runtime_usage () { - echo ">>> Now running robot, usage..." - echo ">quit - kill all processes and exit" - echo ">swipe - restart swipe processes" - echo ">restart - restart master process" - echo ">clean - remove stash and shelf, restart master process" - echo ">test - install apk on device, open client for testing, uninstall apk" - echo ">upload - upload apk" - echo ">upload - upload all of the apks in " - echo ">upload artifacts - package and reupload local artifacts" -} - -# Main process -pushd $(dirname $0/../..) > /dev/null -handle_opts $(getopt -l "clean" -o "c" -n "go_robot_go.sh" -- "$@") - -start_swipe -if [[ $CLEAN ]]; then - clean_output -fi -start_master - -QUIT=0 -while (( $QUIT == 0 )); do - runtime_usage - read -e -a COMMANDS - COMMAND=${COMMANDS[0]} - if [[ $COMMAND = "quit" ]]; then - echo ">>> Quitting..." - bazel-bin/pkg/robot stop - echo ">>> Stopped master" - kill_swipe - echo ">>> Killed swipe" - QUIT=1 - elif [[ $COMMAND = "swipe" ]]; then - start_swipe - elif [[ $COMMAND = "restart" ]]; then - bazil-bin/pkg/robot stop - start_master - elif [[ $COMMAND = "clean" ]]; then - bazil-bin/pkg/robot stop - clean_output - start_master - elif [[ $COMMAND = "test" ]]; then - UPLOAD_PATH=$(realpath ${COMMANDS[1]/#\~/$HOME}) - case $UPLOAD_PATH in - *.apk) - if [[ -e $UPLOAD_PATH ]]; then - test_subj $UPLOAD_PATH - fi ;; - *) - echo "not implemented yet" ;; - esac - elif [[ $COMMAND = "upload" ]]; then - case ${COMMANDS[1]} in - artifacts) - pack_local ;; - *) - UPLOAD_PATH=$(realpath ${COMMANDS[1]/#\~/$HOME}) - case $UPLOAD_PATH in - *.apk) - if [[ -e $UPLOAD_PATH ]]; then - upload_subj $UPLOAD_PATH - fi ;; - *) - if [[ -d $UPLOAD_PATH ]]; then - upload_dir $UPLOAD_PATH - fi ;; - esac ;; - esac - fi -done -popd > /dev/null - diff --git a/test/robot/job/BUILD.bazel b/test/robot/job/BUILD.bazel deleted file mode 100644 index f455ba897d..0000000000 --- a/test/robot/job/BUILD.bazel +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "device.go", - "device_listener.go", - "doc.go", - "job.go", - "local.go", - "manager.go", - "remote.go", - "server.go", - ], - embed = [":job_go_proto"], - importpath = "github.com/google/gapid/test/robot/job", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/android/adb:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//core/os/device/host:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "job_proto", - srcs = ["job.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:device_proto", - "//test/robot/search:search_proto", - ], -) - -go_proto_library( - name = "job_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/job", - proto = ":job_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/job/device.go b/test/robot/job/device.go deleted file mode 100644 index e2d72b4e15..0000000000 --- a/test/robot/job/device.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - "fmt" - "reflect" - "sync" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -type devices struct { - mu sync.Mutex - ledger record.Ledger - entries []*Device - byID map[string]*Device - onChange event.Broadcast -} - -func (l *devices) init(ctx context.Context, library record.Library) error { - ledger, err := library.Open(ctx, "devices", &Device{}) - if err != nil { - return err - } - l.ledger = ledger - l.byID = map[string]*Device{} - apply := event.AsHandler(ctx, l.apply) - if err := ledger.Read(ctx, apply); err != nil { - return err - } - ledger.Watch(ctx, apply) - return nil -} - -func (l *devices) apply(ctx context.Context, entry *Device) error { - l.entries = append(l.entries, entry) - l.byID[entry.Id] = entry - l.onChange.Send(ctx, entry) - return nil -} - -func (l *devices) search(ctx context.Context, query *search.Query, handler DeviceHandler) error { - filter := eval.Filter(ctx, query, reflect.TypeOf(&Device{}), event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, l.entries) - if query.Monitor { - return event.Monitor(ctx, &l.mu, l.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -func (l *devices) uniqueName(ctx context.Context, name string) string { - index := 0 - id := name - for { - if _, found := l.byID[id]; !found { - return id - } - index++ - id = fmt.Sprintf("%s-%d", name, index) - } -} - -func sameDevice(match *Device, info *device.Instance) bool { - if match == nil { - return info == nil - } - if info == nil { - return false - } - return match.Information.SameAs(info) -} - -func (l *devices) find(ctx context.Context, info *device.Instance) *Device { - for _, entry := range l.entries { - if sameDevice(entry, info) { - return entry - } - } - return nil -} - -func (l *devices) get(ctx context.Context, info *device.Instance) (*Device, error) { - if info == nil { - return nil, nil - } - l.mu.Lock() - defer l.mu.Unlock() - entry := l.find(ctx, info) - if entry == nil { - entry = &Device{ - Id: l.uniqueName(ctx, info.ID.ID().String()), - Information: info, - } - if err := l.ledger.Add(ctx, entry); err != nil { - return nil, err - } - } else { - entry.Information = info - } - return entry, nil -} diff --git a/test/robot/job/device_listener.go b/test/robot/job/device_listener.go deleted file mode 100644 index 30c6fef57f..0000000000 --- a/test/robot/job/device_listener.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - "sync" - "time" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/android/adb" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/core/os/device/host" -) - -var devReg *bind.Registry -var deviceLocks map[string]*sync.Mutex -var mu sync.Mutex - -// BindRegistry creates a new device registry to monitor new Android devices -// and returns the context which is bound to the created registry. -func BindRegistry(ctx context.Context) context.Context { - devReg = bind.NewRegistry() - ctx = bind.PutRegistry(ctx, devReg) - crash.Go(func() { - if err := adb.Monitor(ctx, devReg, 15*time.Second); err != nil { - log.E(ctx, "adb.Monitor failed: %v", err) - } - }) - return ctx -} - -type deviceListener struct { - devices map[string]bind.Device - onAdded func(ctx context.Context, host *device.Instance, target bind.Device) - registry *bind.Registry -} - -// OnDeviceAdded registers onAdded to be called whenever a new Android device is -// added. -func OnDeviceAdded(ctx context.Context, - onAdded func(ctx context.Context, host *device.Instance, target bind.Device)) { - dl := &deviceListener{ - devices: map[string]bind.Device{}, - onAdded: onAdded, - registry: bind.GetRegistry(ctx), - } - dl.registry.Listen(dl) -} - -// OnDeviceAdded implements bind.DeviceListener interface -func (l *deviceListener) OnDeviceAdded(ctx context.Context, d bind.Device) { - mu.Lock() - defer mu.Unlock() - host := host.Instance(ctx) - inst := d.Instance() - serial := inst.GetSerial() - if _, ok := l.devices[serial]; !ok { - log.I(ctx, "Device, added: %s", inst.GetName()) - l.onAdded(ctx, host, d) - } else { - l.devices[inst.GetSerial()] = d - } - if deviceLocks == nil { - deviceLocks = map[string]*sync.Mutex{} - } - if _, ok := deviceLocks[serial]; !ok { - deviceLocks[serial] = &sync.Mutex{} - } -} - -// OnDeviceRemoved implements bind.DeviceListener interface -func (l *deviceListener) OnDeviceRemoved(ctx context.Context, d bind.Device) { - log.I(ctx, "Device removed: %s", d.Instance().GetName()) - // TODO: find a more graceful way to handle this. -} - -// LockDevice reserves the given device for the requester, prevents the device -// to be used by other clients. -func LockDevice(ctx context.Context, d bind.Device) error { - if _, ok := deviceLocks[d.Instance().GetSerial()]; !ok { - return log.Errf(ctx, nil, "Lock not found for device: %v", d.Instance().GetSerial()) - } - deviceLocks[d.Instance().GetSerial()].Lock() - return nil -} - -// UnlockDevices release the given device so other clients can run tasks on it. -func UnlockDevice(ctx context.Context, d bind.Device) error { - if _, ok := deviceLocks[d.Instance().GetSerial()]; !ok { - return log.Errf(ctx, nil, "Lock not found for device: %v", d.Instance().GetSerial()) - } - deviceLocks[d.Instance().GetSerial()].Unlock() - return nil -} diff --git a/test/robot/job/doc.go b/test/robot/job/doc.go deleted file mode 100644 index 4759c37eaa..0000000000 --- a/test/robot/job/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package job holds code for managing task execution in robot. -// The primary concepts are the operations, the device on which jobs run, and the worker -// which is responsible for running jobs on a device. -// Devices are persistent, and might not be active, workers only exist for live devices. -package job diff --git a/test/robot/job/job.go b/test/robot/job/job.go deleted file mode 100644 index a93ac6b4e3..0000000000 --- a/test/robot/job/job.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -const ( - UnknownOperation = Operation_UnknownOperation - Host = Operation_Host - Trace = Operation_Trace - Report = Operation_Report - Replay = Operation_Replay -) - -const ( - UnknownStatus = Status_UnknownStatus - Running = Status_Running - Succeeded = Status_Succeeded - Failed = Status_Failed -) diff --git a/test/robot/job/job.proto b/test/robot/job/job.proto deleted file mode 100644 index 61a48ca1b4..0000000000 --- a/test/robot/job/job.proto +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package job; -option go_package = "github.com/google/gapid/test/robot/job"; - -import "core/os/device/device.proto"; -import "test/robot/search/search.proto"; - -// Operation represents the type of action being performed. -enum Operation { - // UnknownOperation is the default (invalid) operation. - UnknownOperation = 0; - // Host indicates host operations (running gapit and gapis). - Host = 1; - // Trace indicates tracing operations (gapii). - Trace = 2; - // Report indicates report generation operations (gapis gapir). - Report = 3; - // Replay indicates replay operations (gapir). - Replay = 4; -} - -// Status represents the status of an action being performed. -enum Status { - // UnknownStatus is the default not started status. - UnknownStatus = 0; - // Running indicates a worker has picked up and started the action. - Running = 1; - // Succeeded means the action finished correctly, and it's output may be - // interesting. - Succeeded = 2; - // Failed indicates the action has been abnormally terminated, and it's - // results should be ignored. - Failed = 3; -} - -// Device is the information we know about a given robot worker device. -message Device { - // Id is the unique id of the device. - string id = 1; - // Information is the device instance information. - device.Instance information = 2; -} - -// Worker is the information about a consumer of tasks. -message Worker { - // Host is the device id which hosts the worker. - string host = 1; - // Target is the device id on which the tasks will be performed. - string target = 2; - // Operation is the types of operation supported by this worker. - repeated Operation Operation = 3; -} - -// Service is the api to the robot job manager. -service Service { - // Search is used to find devices that match the given query. - rpc SearchDevices(search.Query) returns (stream Device) { - }; - // Search is used to find workers that match the given query. - rpc SearchWorkers(search.Query) returns (stream Worker) { - }; - // Get finds or adds a worker. - // The returned worker may support a superset of the operations in the - // request. - rpc GetWorker(GetWorkerRequest) returns (GetWorkerResponse) { - }; -} - -message GetWorkerRequest { - device.Instance host = 1; - device.Instance target = 2; - Operation Operation = 3; -} - -message GetWorkerResponse { - Worker worker = 1; -} diff --git a/test/robot/job/local.go b/test/robot/job/local.go deleted file mode 100644 index 8c35ccecba..0000000000 --- a/test/robot/job/local.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - "reflect" - "sync" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -type local struct { - mu sync.Mutex - devices devices - entries []*Worker - onChange event.Broadcast -} - -// NewLocal builds a new job manager that persists it's data in the -// supplied library. -func NewLocal(ctx context.Context, library record.Library) (Manager, error) { - m := &local{} - if err := m.devices.init(ctx, library); err != nil { - return nil, err - } - return m, nil -} - -// SearchDevices implements Manager.SearchDevicess -// It searches the set of persisted devices, and supports monitoring of new devices as they are added. -func (m *local) SearchDevices(ctx context.Context, query *search.Query, handler DeviceHandler) error { - return m.devices.search(ctx, query, handler) -} - -// SearchWorkers implements Manager.SearchWorkers -// It searches the set of persisted workers, and supports monitoring of workers as they are registered. -func (m *local) SearchWorkers(ctx context.Context, query *search.Query, handler WorkerHandler) error { - filter := eval.Filter(ctx, query, reflect.TypeOf(&Worker{}), event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, m.entries) - if query.Monitor { - return event.Monitor(ctx, &m.mu, m.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -// GetWorker implements Manager.GetWorker -// This attempts to find a worker on a device that matches the supplied host -// controlling a device that matches the supplied target to perform the given operation. -// If none is found, a new worker will be created. -func (m *local) GetWorker(ctx context.Context, host *device.Instance, target *device.Instance, op Operation) (*Worker, error) { - m.mu.Lock() - defer m.mu.Unlock() - h, err := m.devices.get(ctx, host) - if err != nil { - return nil, err - } - t, err := m.devices.get(ctx, target) - if err != nil { - return nil, err - } - for _, entry := range m.entries { - if entry.Host != h.Id { - continue - } - if entry.Target != t.Id { - continue - } - if !entry.Supports(op) { - entry.Operation = append(entry.Operation, op) - m.onChange.Send(ctx, entry) - return entry, nil - } - } - // Not found, add a new worker - entry := &Worker{ - Host: h.Id, - Target: t.Id, - Operation: []Operation{op}, - } - m.entries = append(m.entries, entry) - m.onChange.Send(ctx, entry) - return entry, nil -} - -// Supports is used to test if a worker supports a given operation. -func (w *Worker) Supports(op Operation) bool { - for _, e := range w.Operation { - if e == op { - return true - } - } - return false -} diff --git a/test/robot/job/manager.go b/test/robot/job/manager.go deleted file mode 100644 index 65df110539..0000000000 --- a/test/robot/job/manager.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/search" -) - -// DeviceHandler is a function used to consume a stream of Devices. -type DeviceHandler func(context.Context, *Device) error - -// WorkerHandler is a function used to consume a stream of Workers. -type WorkerHandler func(context.Context, *Worker) error - -// Manager is the abstract interface to the job manager. -type Manager interface { - // SearchDevices delivers matching workers to the supplied handler. - SearchDevices(ctx context.Context, query *search.Query, handler DeviceHandler) error - // SearchWorkers delivers matching workers to the supplied handler. - SearchWorkers(ctx context.Context, query *search.Query, handler WorkerHandler) error - // GetWorker finds or adds a worker. - GetWorker(ctx context.Context, host *device.Instance, target *device.Instance, op Operation) (*Worker, error) -} diff --git a/test/robot/job/remote.go b/test/robot/job/remote.go deleted file mode 100644 index 3e9e3df5e5..0000000000 --- a/test/robot/job/remote.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a job manager that talks to a remote grpc job manager. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Manager { - return &remote{client: NewServiceClient(conn)} -} - -// SearchDevices implements Manager.SearchDevicess -// It forwards the call through grpc to the remote implementation. -func (m *remote) SearchDevices(ctx context.Context, query *search.Query, handler DeviceHandler) error { - stream, err := m.client.SearchDevices(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// SearchWorkers implements Manager.SearchWorkers -// It forwards the call through grpc to the remote implementation. -func (m *remote) SearchWorkers(ctx context.Context, query *search.Query, handler WorkerHandler) error { - stream, err := m.client.SearchWorkers(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// GetWorker implements Manager.GetWorker -// It forwards the call through grpc to the remote implementation. -func (m *remote) GetWorker(ctx context.Context, host *device.Instance, target *device.Instance, op Operation) (*Worker, error) { - request := &GetWorkerRequest{Host: host, Target: target, Operation: op} - response, err := m.client.GetWorker(ctx, request) - if err != nil { - return nil, err - } - return response.Worker, nil -} diff --git a/test/robot/job/server.go b/test/robot/job/server.go deleted file mode 100644 index 4bf5146c40..0000000000 --- a/test/robot/job/server.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package job - -import ( - "context" - - "github.com/google/gapid/test/robot/search" - - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - manager Manager -} - -// Serve wraps a manager in a grpc server. -func Serve(ctx xctx.Context, grpcServer *grpc.Server, manager Manager) error { - RegisterServiceServer(grpcServer, &server{manager: manager}) - return nil -} - -// SearchDevices implements ServiceServer.SearchDevicess -// It delegates the call to the provided Manager implementation. -func (s *server) SearchDevices(query *search.Query, stream Service_SearchDevicesServer) error { - ctx := stream.Context() - return s.manager.SearchDevices(ctx, query, func(ctx context.Context, e *Device) error { return stream.Send(e) }) -} - -// SearchWorkers implements ServiceServer.SearchWorkers -// It delegates the call to the provided Manager implementation. -func (s *server) SearchWorkers(query *search.Query, stream Service_SearchWorkersServer) error { - ctx := stream.Context() - return s.manager.SearchWorkers(ctx, query, func(ctx context.Context, e *Worker) error { return stream.Send(e) }) -} - -// GetWorker implements ServiceServer.GetWorker -// It delegates the call to the provided Manager implementation. -func (s *server) GetWorker(ctx xctx.Context, request *GetWorkerRequest) (*GetWorkerResponse, error) { - d, err := s.manager.GetWorker(ctx, request.Host, request.Target, request.Operation) - if err != nil { - return nil, err - } - return &GetWorkerResponse{Worker: d}, nil -} diff --git a/test/robot/job/worker/BUILD.bazel b/test/robot/job/worker/BUILD.bazel deleted file mode 100644 index 085bbf44a0..0000000000 --- a/test/robot/job/worker/BUILD.bazel +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "action.go", - "doc.go", - "local.go", - "worker.go", - ], - embed = [":worker_go_proto"], - importpath = "github.com/google/gapid/test/robot/job/worker", - visibility = ["//visibility:public"], - deps = [ - "//core/data/id:go_default_library", - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/os/device:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - ], -) - -proto_library( - name = "worker_proto", - srcs = ["worker.proto"], - visibility = ["//visibility:public"], - deps = ["//core/os/device:device_proto"], -) - -go_proto_library( - name = "worker_go_proto", - importpath = "github.com/google/gapid/test/robot/job/worker", - proto = ":worker_proto", - visibility = ["//visibility:public"], - deps = ["//core/os/device:go_default_library"], -) diff --git a/test/robot/job/worker/action.go b/test/robot/job/worker/action.go deleted file mode 100644 index 676bfbbe9b..0000000000 --- a/test/robot/job/worker/action.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package worker - -import ( - "context" - "reflect" - "strings" - "sync" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/data/id" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -// Actions is a struct to manage a persistent set of actions. -type Actions struct { - mu sync.Mutex - ledger record.Ledger - onChange event.Broadcast - entries []Action - byID map[string]Action - nullAction Action - nullTask Task -} - -// Action is the interface to the specific action type for a given of the Actions store. -type Action interface { - proto.Message - // Init is called as you add input and target device pairs to the manager. - // It is invoked with the action id to use, the input the manager was given, and - // the worker that the task is going to be posted to. - Init(id string, input Input, w *job.Worker) - // JobID must return the id that was handed to Init. - JobID() string - // JobHost must return the host of the worker that was handed to Init. - JobHost() string - // JobTarget must return the target of the worker that was handed to Init. - JobTarget() string - // JobInput must return the input that was handed to Init. - JobInput() Input -} - -func (a *Actions) init(ctx context.Context, library record.Library, op job.Operation, nullAction Action, nullTask Task) error { - ctx = log.V{"operation": op}.Bind(ctx) - a.nullAction = nullAction - a.nullTask = nullTask - a.byID = map[string]Action{} - name := strings.ToLower(op.String()) - ledger, err := library.Open(ctx, name+"-actions", nullAction) - if err != nil { - return err - } - a.ledger = ledger - apply := event.AsHandler(ctx, a.apply) - if err := ledger.Read(ctx, apply); err != nil { - return err - } - ledger.Watch(ctx, apply) - return nil -} - -// apply is called with items coming out of the ledger -// it should be called with the mutation lock already held. -func (a *Actions) apply(ctx context.Context, item Action) error { - id := item.JobID() - entry := a.byID[id] - if entry == nil { - entry = item - a.entries = append(a.entries, entry) - a.byID[id] = entry - } else { - proto.Merge(entry, item) - } - a.onChange.Send(ctx, entry) - return nil -} - -func (a *Actions) do(ctx context.Context, w *Worker, input Input) (string, error) { - action, err := func() (Action, error) { - a.mu.Lock() - defer a.mu.Unlock() - action := proto.Clone(a.nullAction).(Action) - action.Init(id.Unique().String(), input, w.Info) - err := a.ledger.Add(ctx, action) - if err != nil { - return nil, err - } - return action, nil - }() - if err != nil { - return "", err - } - task := proto.Clone(a.nullTask).(Task) - task.Init(action.JobID(), input, w.Info) - if err := w.send(ctx, task); err != nil { - return "", err - } - return action.JobID(), nil -} - -// update an action, and return the merged action. -func (a *Actions) update(ctx context.Context, action Action) error { - a.mu.Lock() - defer a.mu.Unlock() - return a.ledger.Add(ctx, action) -} - -// ByID returns the action with the specified id -func (a *Actions) ByID(ctx context.Context, id string) Action { - return a.byID[id] -} - -// ByInput finds the action that matches the given input -func (a *Actions) ByInput(ctx context.Context, input proto.Message) Action { - for _, action := range a.entries { - if proto.Equal(action.JobInput(), input) { - return action - } - } - return nil -} - -// Search runs the query for each entry in the action list, and hands the matches to the action handler. -func (a *Actions) Search(ctx context.Context, query *search.Query, handler interface{}) error { - filter := eval.Filter(ctx, query, reflect.TypeOf(a.nullAction), event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, a.entries) - if query.Monitor { - return event.Monitor(ctx, &a.mu, a.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -// EquivalentAction returns true if an action is the same task being performed on the same devices. -func EquivalentAction(a, b Action) bool { - if !proto.Equal(a.JobInput(), b.JobInput()) { - return false - } - if a.JobHost() != b.JobHost() { - return false - } - if a.JobTarget() != b.JobTarget() { - return false - } - return true -} diff --git a/test/robot/job/worker/doc.go b/test/robot/job/worker/doc.go deleted file mode 100644 index 96cacdb817..0000000000 --- a/test/robot/job/worker/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package worker is a set of helpers for implementing common features of robot -// workers (see package job for more information about what a worker is). -// It is not required to use this package, but it helps for the simple cases. -package worker diff --git a/test/robot/job/worker/local.go b/test/robot/job/worker/local.go deleted file mode 100644 index 1d1bb81bf6..0000000000 --- a/test/robot/job/worker/local.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package worker - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/record" -) - -// Manager is a helper for writing local manager implementation of worker types (such as trace and replay). -// It has all the code needed to manage and persist the list of workers and actions those workers are performing. -type Manager struct { - //Actions holds the persisted list of actions the service has had added to it. - Actions Actions - // Workers holds the dynamic list of live workers for the service. - Workers Workers -} - -// Init is called to initialised the action store from the supplied library. -// It loads the action ledger and prepares the empty worker list. -// The op is the type of action this manager supports, the nullAction is the empty version of the action the manager -// holds, and the nullTask is the empty version of the task sent to the managers workers. -func (m *Manager) Init(ctx context.Context, library record.Library, jobs job.Manager, op job.Operation, nullAction Action, nullTask Task) error { - m.Workers.init(ctx, jobs, op) - return m.Actions.init(ctx, library, op, nullAction, nullTask) -} - -// Do is called to add a new action to the service. -// It is handed the id of the target device to run it on, and the inputs to the action. -// The active worker that owns the target device will be looked up, and then a new action -// created for the target worker and provided input will be added to the store. -func (m *Manager) Do(ctx context.Context, device string, input Input) (string, error) { - ctx = log.V{"device": device}.Bind(ctx) - w := m.Workers.Find(ctx, device) - if w == nil { - return "", log.Err(ctx, nil, "Could not find worker device") - } - return m.Actions.do(ctx, w, input) -} - -// Update is used to update an existing action, normally to update it status and/or set it's outputs. -func (m *Manager) Update(ctx context.Context, action Action) error { - return m.Actions.update(ctx, action) -} diff --git a/test/robot/job/worker/worker.go b/test/robot/job/worker/worker.go deleted file mode 100644 index 921d7736a8..0000000000 --- a/test/robot/job/worker/worker.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package worker - -import ( - "context" - "strings" - "sync" - "time" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" -) - -// Worker is the representation of a live object that can perform actions. -type Worker struct { - lock sync.Mutex - // Info is the persistable information about a worker. - Info *job.Worker - handler event.Handler - tasks chan taskEntry -} - -// Workers is the non persisted list of live workers. -type Workers struct { - jobs job.Manager - entries []*Worker - op job.Operation -} - -// Input is the interface that must be implemented by anything that wants to be -// the input to an action. -type Input interface { - proto.Message -} - -// Task is the interface to something that can be sent to a worker. -// It should always contain the inputs to the action, and the id of the action to attach results to. -type Task interface { - proto.Message - // Init is called as you add input and target device pairs to the manager. - // It is invoked with the action id to post results to, the input the manager was given, and - // the worker that the task is going to be posted to. - Init(id string, input Input, w *job.Worker) -} - -type taskEntry struct { - task Task - result chan error -} - -// TaskRetryError is used to communicate that an action Failed in such a way that the task should attempt a retry. -// It simply contains the reason for the retry. -type TaskRetryError struct { - Reason string -} - -// NeedsRetry is used to check if a string signals a retry attempt in a task. -// "text file busy" is the main cause for retry attempts, but if extra checks are necessary they can be passed into they -// variadic argument. -// This is the idiomatic method of creating a TaskRetryError and if no need for a retry exists it returns nil. -func NeedsRetry(reason string, retryStrings ...string) error { - if strings.Contains(reason, "text file busy") { - return TaskRetryError{Reason: reason} - } - for _, retryString := range retryStrings { - if strings.Contains(reason, retryString) { - return TaskRetryError{Reason: reason} - } - } - return nil -} - -// Error returns the reason for the retry -func (e TaskRetryError) Error() string { - return "Try again: " + e.Reason -} - -// RetryFunction wraps a function that can return TaskRetryError and handles performing a delay and retrying up to maxAttempts -func RetryFunction(ctx context.Context, maxAttempts int, delay time.Duration, task func() error) error { - numRetries := 0 - var err error - for numRetries < maxAttempts { - err = task() - if _, retry := err.(TaskRetryError); retry { - time.Sleep(delay) - numRetries++ - } else { - return err - } - } - return log.Errf(ctx, err, "Retried maximum attempts, %v", maxAttempts) -} - -func (w *Workers) init(ctx context.Context, jobs job.Manager, op job.Operation) { - w.jobs = jobs - w.op = op -} - -// Register is called to add a new worker to the active set. -// It takes the host and target device for the worker, which may be the same, and a handler that will -// be passed all the task objects that are sent to the worker. -func (w *Workers) Register(ctx context.Context, host *device.Instance, target *device.Instance, handler interface{}) error { - info, err := w.jobs.GetWorker(ctx, host, target, w.op) - if err != nil { - return err - } - entry := &Worker{ - Info: info, - handler: event.AsHandler(ctx, handler), - tasks: make(chan taskEntry), - } - go entry.run(ctx) - w.entries = append(w.entries, entry) - return nil -} - -// Find searches the live worker set to find the one that is managing a given target device. -func (w *Workers) Find(ctx context.Context, device string) *Worker { - for _, entry := range w.entries { - if entry.Info.Target == device { - return entry - } - } - return nil -} - -func (w *Worker) run(ctx context.Context) { - for e := range w.tasks { - e.result <- w.handler(ctx, e.task) - close(e.result) - } -} - -func (w *Worker) send(ctx context.Context, task Task) error { - if w == nil { - return log.Err(ctx, nil, "No worker for device") - } - result := make(chan error) - w.lock.Lock() - if w.tasks != nil { - w.tasks <- taskEntry{task: task, result: result} - } - w.lock.Unlock() - err := <-result - if err != nil { - w.lock.Lock() - if w.tasks != nil { - close(w.tasks) - w.tasks = nil - } - w.lock.Unlock() - } - return err -} diff --git a/test/robot/job/worker/worker.proto b/test/robot/job/worker/worker.proto deleted file mode 100644 index 361d5735a4..0000000000 --- a/test/robot/job/worker/worker.proto +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package worker; -option go_package = "github.com/google/gapid/test/robot/job/worker"; - -import "core/os/device/device.proto"; - -// Register request is the parameters for all worker registeration methods. -// The type of the worker is implied by the service the request is sent to. -message RegisterRequest { - device.Instance host = 1; - device.Instance target = 2; -} - -// DoResponse is the common response to any task execution rpc method. -message DoResponse { - // Id is the id of the action generated. - string id = 1; -} - -message UpdateResponse { -} diff --git a/test/robot/lingo/BUILD.bazel b/test/robot/lingo/BUILD.bazel deleted file mode 100644 index 571cae2926..0000000000 --- a/test/robot/lingo/BUILD.bazel +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "error.go", - "node.go", - "scanner.go", - ], - importpath = "github.com/google/gapid/test/robot/lingo", - visibility = ["//visibility:public"], - deps = [ - "//core/fault:go_default_library", - "//core/log:go_default_library", - ], -) diff --git a/test/robot/lingo/error.go b/test/robot/lingo/error.go deleted file mode 100644 index cc97382347..0000000000 --- a/test/robot/lingo/error.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package lingo - -import ( - "bytes" - "fmt" - "strings" - - "github.com/google/gapid/core/fault" - "github.com/google/gapid/core/log" -) - -type scanError struct { - scanner *Scanner - offset int - cause interface{} - message string - watermark error -} - -const scanFailure = fault.Const("No match") - -func WasScannerError(v interface{}) error { - if v == scanFailure { - return scanFailure - } - if err, ok := v.(scanError); ok { - return err - } - return nil -} - -// Error wraps an error and message into a new error that knows the scanner stream position. -func (s *Scanner) Error(err error, msg string) error { - result := scanError{ - scanner: s, - offset: s.offset, - message: msg, - cause: err, - } - se, found := err.(scanError) - if found { - if strings.HasPrefix(se.message, result.message) { - // repeated message, just add > for brevity - result.message += ">" + se.message[len(result.message):] - } else if result.message == "" { - // first message in the chain - result.message = se.message - } else { - // chaining a message - result.message += "->" + se.message - } - result.cause = se.cause - if result.offset < se.offset { - result.offset = se.offset - } - } - switch { - case s.skipping: - result.watermark = s.watermark - case s.watermark.offset <= result.offset: - s.watermark = result - case s.watermark == se: - // wrapping - s.watermark = result - default: - // include watermark - result.watermark = s.watermark - } - return result -} - -func positionOf(data []byte, offset int) (line, column int) { - last := 0 - line = 1 - for { - count := bytes.IndexRune(data[last:], '\n') - if count < 0 || last+count >= offset { - return line, offset + 1 - last - } - last += count + 1 - line++ - } -} - -// Error is to make scanError conform to the error interface. -// It returns a message that includes the scan stream position and associated messages/errors. -func (err scanError) Error() string { - line, col := positionOf(err.scanner.data, err.offset) - result := fmt.Sprintf("%s:%d:%d:%s", err.scanner.name, line, col, err.message) - if err.cause != nil { - result = fmt.Sprintf("%s:%s", result, err.cause) - } - if err.watermark != nil { - result += fmt.Sprintf("\n @%s", err.watermark) - } - return result -} - -// Trace writes a message to the context at info level -func (s *Scanner) Trace(msg string) { - line, col := positionOf(s.data, s.offset) - log.I(s.ctx, "%s:%d:%d:%s", s.name, line, col, msg) -} diff --git a/test/robot/lingo/examples/calc/BUILD.bazel b/test/robot/lingo/examples/calc/BUILD.bazel deleted file mode 100644 index 5da95c7171..0000000000 --- a/test/robot/lingo/examples/calc/BUILD.bazel +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") -load("//tools/build:rules.bzl", "lingo") - -lingo( - name = "lingo", - srcs = glob(["*.lingo"]), -) - -go_library( - name = "go_default_library", - srcs = [ - "main.go", - ":lingo", # keep - ], - importpath = "github.com/google/gapid/test/robot/lingo/examples/calc", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", - "//core/log:go_default_library", - "//test/robot/lingo:go_default_library", - ], -) - -go_binary( - name = "calc", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/test/robot/lingo/examples/calc/constants.lingo b/test/robot/lingo/examples/calc/constants.lingo deleted file mode 100644 index 40a484eb57..0000000000 --- a/test/robot/lingo/examples/calc/constants.lingo +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "regexp" - - "github.com/google/gapid/test/robot/lingo" -) - -type _ lingo.Scanner -type _ regexp.Regexp - -const ( - space = Whitespace(`\s*`) - intDigits = Digits(`[0-9]+`) - floatDigits = Digits(`[0-9]+\.[0-9]+([eE][-+]?[0-9]+)?`) - - opAdd = Operator('+') - opSubtract = Operator('-') - opMultiply = Operator('*') - opDivide = Operator('/') - opRemainder = Operator('%') - - openParenthesis = Bracket('(') - closeParenthesis = Bracket(')') -) - -const ( - ErrorParenOrNumber = "Expected parenthesis or number" -) diff --git a/test/robot/lingo/examples/calc/main.go b/test/robot/lingo/examples/calc/main.go deleted file mode 100644 index f54e666347..0000000000 --- a/test/robot/lingo/examples/calc/main.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The calc command implements a simple calculator. -// This is an example of using the lingo system to generate an ast, and -// then evaluating the ast afterwards. -// This is the most complete of the examples, and also the pattern that most -// parsers would follow. - -package main - -import ( - "context" - "flag" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - _ "github.com/google/gapid/test/robot/lingo" -) - -func main() { - app.ShortHelp = "calc: A simple calculator." - app.Run(run) -} - -func run(ctx context.Context) error { - args := flag.Args() - if len(args) < 1 { - app.Usage(ctx, "Missing expression") - return nil - } - input := strings.Join(args, " ") - value, err := Parse(ctx, "command_line", input) - if err != nil { - return err - } - log.I(ctx, "%v = %v\n", value, value.Eval()) - return nil -} diff --git a/test/robot/lingo/examples/calc/nodes.lingo b/test/robot/lingo/examples/calc/nodes.lingo deleted file mode 100644 index af330c6838..0000000000 --- a/test/robot/lingo/examples/calc/nodes.lingo +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "io" -) - -type ( - Whitespace string - Digits string - Operator string - Bracket string - - Expression interface { - Eval() interface{} - Format(f fmt.State, r rune) - } - - Integer int64 - Float float64 - - BinaryOp struct { - LHS Expression - RHS Expression - } - - Add BinaryOp - Subtract BinaryOp - Multiply BinaryOp - Divide BinaryOp - Remainder BinaryOp -) - -const childFormatMarker = ' ' - -func (n *BinaryOp) doFormat(f fmt.State, op Operator, r rune) { - if r == childFormatMarker { - io.WriteString(f, "(") - } - n.LHS.Format(f, childFormatMarker) - io.WriteString(f, string(op)) - n.RHS.Format(f, childFormatMarker) - if r == childFormatMarker { - io.WriteString(f, ")") - } -} - -func (n Integer) Format(f fmt.State, r rune) { fmt.Fprint(f, int64(n)) } -func (n Float) Format(f fmt.State, r rune) { fmt.Fprint(f, float64(n)) } -func (n *Add) Format(f fmt.State, r rune) { (*BinaryOp)(n).doFormat(f, opAdd, r) } -func (n *Subtract) Format(f fmt.State, r rune) { (*BinaryOp)(n).doFormat(f, opSubtract, r) } -func (n *Multiply) Format(f fmt.State, r rune) { (*BinaryOp)(n).doFormat(f, opMultiply, r) } -func (n *Divide) Format(f fmt.State, r rune) { (*BinaryOp)(n).doFormat(f, opDivide, r) } -func (n *Remainder) Format(f fmt.State, r rune) { (*BinaryOp)(n).doFormat(f, opRemainder, r) } - -func eval(n Expression) (int64, float64, bool) { - switch v := n.Eval().(type) { - case int64: - return v, float64(v), false - case float64: - return 0, v, true - default: - panic("Unexpected eval type") - } -} - -func (n Integer) Eval() interface{} { return int64(n) } -func (n Float) Eval() interface{} { return float64(n) } - -func (n *Add) Eval() interface{} { - lhsInt, lhsFloat, lhsIsFloat := eval(n.LHS) - rhsInt, rhsFloat, rhsIsFloat := eval(n.RHS) - if lhsIsFloat || rhsIsFloat { - return lhsFloat + rhsFloat - } - return lhsInt + rhsInt -} - -func (n *Subtract) Eval() interface{} { - lhsInt, lhsFloat, lhsIsFloat := eval(n.LHS) - rhsInt, rhsFloat, rhsIsFloat := eval(n.RHS) - if lhsIsFloat || rhsIsFloat { - return lhsFloat - rhsFloat - } - return lhsInt - rhsInt -} - -func (n *Multiply) Eval() interface{} { - lhsInt, lhsFloat, lhsIsFloat := eval(n.LHS) - rhsInt, rhsFloat, rhsIsFloat := eval(n.RHS) - if lhsIsFloat || rhsIsFloat { - return lhsFloat * rhsFloat - } - return lhsInt * rhsInt -} - -func (n *Divide) Eval() interface{} { - lhsInt, lhsFloat, lhsIsFloat := eval(n.LHS) - rhsInt, rhsFloat, rhsIsFloat := eval(n.RHS) - if lhsIsFloat || rhsIsFloat { - return lhsFloat / rhsFloat - } - return lhsInt / rhsInt -} - -func (n *Remainder) Eval() interface{} { - lhsInt, _, lhsIsFloat := eval(n.LHS) - rhsInt, _, rhsIsFloat := eval(n.RHS) - if lhsIsFloat || rhsIsFloat { - panic("Remainder on floats") - } - return lhsInt % rhsInt -} diff --git a/test/robot/lingo/examples/calc/parser.lingo b/test/robot/lingo/examples/calc/parser.lingo deleted file mode 100644 index ca1f7de284..0000000000 --- a/test/robot/lingo/examples/calc/parser.lingo +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "strconv" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/lingo" -) - -func Parse(ctx context.Context, name string, input string) (Expression, error) { - s := lingo.NewStringScanner(ctx, name, input, nil) - s.SetSkip(skip) - value, err := expression(s) - if err != nil { - return nil, err - } - if !s.EOF() { - return nil, log.Err(ctx, nil, "Input not consumed") - } - return value, nil -} - -func skip(s *lingo.Scanner) { - _, _ = space(s) -} - -func expression(s *lingo.Scanner) (Expression, error) { - return addition(s) -} - -func parenthesised(s *lingo.Scanner) (Expression, error) { - openParenthesis(s) - value := expression(s) - closeParenthesis(s) - return value, nil -} - -func addition(s *lingo.Scanner) (Expression, error) { - value := multiplication(s) - for { - switch { - case opAdd(s): - value = &Add{LHS: value, RHS: multiplication(s)} - case opSubtract(s): - value = &Subtract{LHS: value, RHS: multiplication(s)} - default: - return value, nil - } - } -} - -func multiplication(s *lingo.Scanner) (Expression, error) { - value := numeral(s) - for { - switch { - case opMultiply(s): - value = &Multiply{LHS: value, RHS: numeral(s)} - case opDivide(s): - value = &Divide{LHS: value, RHS: numeral(s)} - case opRemainder(s): - value = &Remainder{LHS: value, RHS: numeral(s)} - default: - return value, nil - } - } -} - -func numeral(s *lingo.Scanner) (Expression, error) { - if value, err := parenthesised(s); err == nil { - return value, err - } - if value, err := float(s); err == nil { - return value, err - } - if value, err := integer(s); err == nil { - return value, err - } - return nil, s.Error(nil, ErrorParenOrNumber) -} - -func float(s *lingo.Scanner) (Float, error) { - value, err := strconv.ParseFloat(string(floatDigits(s)), 64) - if err != nil { - return Float(0), s.Error(err, "") - } - return Float(value), nil -} - -func integer(s *lingo.Scanner) (Integer, error) { - value, err := strconv.ParseInt(string(intDigits(s)), 10, 64) - if err != nil { - return Integer(0), s.Error(err, "") - } - return Integer(value), nil -} diff --git a/test/robot/lingo/examples/cstcalc/BUILD.bazel b/test/robot/lingo/examples/cstcalc/BUILD.bazel deleted file mode 100644 index 9e696f9d61..0000000000 --- a/test/robot/lingo/examples/cstcalc/BUILD.bazel +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") -load("//tools/build:rules.bzl", "lingo") - -lingo( - name = "lingo", - srcs = glob(["*.lingo"]), -) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - ":lingo", # keep - ], - importpath = "github.com/google/gapid/test/robot/lingo/examples/cstcalc", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", # keep - "//core/log:go_default_library", # keep - "//test/robot/lingo:go_default_library", # keep - ], -) - -go_binary( - name = "cstcalc", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/test/robot/lingo/examples/cstcalc/doc.go b/test/robot/lingo/examples/cstcalc/doc.go deleted file mode 100644 index 2c21d39562..0000000000 --- a/test/robot/lingo/examples/cstcalc/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The cstcalc command implements a simple calculator. -// This is an example of using the lingo system to parse, ignoring the -// parsed nodes, and then directly evaluating the cst. -// This example is more about showing how to use the cst, it would be very -// unusual to actually use the parser in this way. - -package main diff --git a/test/robot/lingo/examples/cstcalc/main.lingo b/test/robot/lingo/examples/cstcalc/main.lingo deleted file mode 100644 index 9e1c4a1b88..0000000000 --- a/test/robot/lingo/examples/cstcalc/main.lingo +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "fmt" - "os" - "regexp" - "strconv" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/lingo" -) - -func main() { - app.ShortHelp = "calc: A simple calculator." - app.Run(run) -} - -type _ regexp.Regexp - -type ( - Whitespace string - Digits string - Operator string - Bracket string - - Structural struct{} -) - -const ( - opAdd = Operator('+') - opSubtract = Operator('-') - opMultiply = Operator('*') - opDivide = Operator('/') - openParenthesis = Bracket('(') - closeParenthesis = Bracket(')') - - space = Whitespace(`\s*`) - digits = Digits(`[0-9]+`) -) - -const ( - ErrorParenOrNumber = "Expected parenthesis or number" -) - -func run(ctx context.Context) error { - args := flag.Args() - if len(args) < 1 { - app.Usage(ctx, "Missing expression") - return nil - } - r := lingo.Records{} - s := lingo.NewStringScanner(ctx, "command_line", strings.Join(args, " "), &r) - _, err := expression(s) - if err != nil { - return err - } - if !s.EOF() { - return log.Err(ctx, nil, "Input not consumed") - } - cst := r.ToCST() - result := eval(ctx, cst) - fmt.Fprintf(os.Stderr, "%v = %d\n", cst, result.value) - return nil -} - -type Eval struct { - hasValue bool - value int - op Operator -} - -func eval(ctx context.Context, node *lingo.Node) Eval { - result := Eval{} - switch obj := node.Object.(type) { - case int: - result.hasValue = true - result.value = obj - case Operator: - result.op = obj - } - for _, child := range node.Children { - got := eval(ctx, child) - if got.hasValue { - if !result.hasValue { - result.value = got.value - } else { - switch result.op { - case opAdd: - result.value += got.value - case opSubtract: - result.value -= got.value - case opMultiply: - result.value *= got.value - case opDivide: - result.value /= got.value - default: - log.F(ctx, true, "Cannot combine values without operator") - } - } - result.hasValue = true - } - if got.op != "" { - result.op = got.op - } - } - return result -} - -func expression(s *lingo.Scanner) (Structural, error) { - addition(s) - return Structural{}, nil -} - -func parenthesised(s *lingo.Scanner) (Structural, error) { - openParenthesis(s) - expression(s) - closeParenthesis(s) - return Structural{}, nil -} - -func addition(s *lingo.Scanner) (Structural, error) { - multiplication(s) - for { - space(s) - switch { - case opAdd(s): - multiplication(s) - case opSubtract(s): - multiplication(s) - default: - return Structural{}, nil - } - } -} - -func multiplication(s *lingo.Scanner) (Structural, error) { - numeral(s) - for { - space(s) - switch { - case opMultiply(s): - numeral(s) - case opDivide(s): - numeral(s) - default: - return Structural{}, nil - } - } -} - -func numeral(s *lingo.Scanner) (Structural, error) { - switch { - case parenthesised(s): - case number(s): - default: - return Structural{}, s.Error(nil, ErrorParenOrNumber) - } - return Structural{}, nil -} - -func number(s *lingo.Scanner) (int, error) { - space(s) - value, err := strconv.Atoi(string(digits(s))) - if err != nil { - return 0, s.Error(err, "") - } - return value, nil -} diff --git a/test/robot/lingo/examples/simplecalc/BUILD.bazel b/test/robot/lingo/examples/simplecalc/BUILD.bazel deleted file mode 100644 index 8c09927593..0000000000 --- a/test/robot/lingo/examples/simplecalc/BUILD.bazel +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") -load("//tools/build:rules.bzl", "lingo") - -lingo( - name = "lingo", - srcs = glob(["*.lingo"]), -) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - ":lingo", # keep - ], - importpath = "github.com/google/gapid/test/robot/lingo/examples/simplecalc", - visibility = ["//visibility:private"], - deps = [ - "//core/app:go_default_library", # keep - "//core/log:go_default_library", # keep - "//test/robot/lingo:go_default_library", # keep - ], -) - -go_binary( - name = "simplecalc", - embed = [":go_default_library"], - visibility = ["//visibility:public"], -) diff --git a/test/robot/lingo/examples/simplecalc/doc.go b/test/robot/lingo/examples/simplecalc/doc.go deleted file mode 100644 index b4362defef..0000000000 --- a/test/robot/lingo/examples/simplecalc/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// The simplecalc command implements a very simple calculator. -// This is an example of using the lingo system to parse and evaluate in a single pass. -// No AST or CST is ever built, the return of parsing is the calculated result. -// This pattern is fairly unusual, only the simplest of parsers where speed and -// simplicity matters would follow this approach. - -package main diff --git a/test/robot/lingo/examples/simplecalc/main.lingo b/test/robot/lingo/examples/simplecalc/main.lingo deleted file mode 100644 index 7676824f71..0000000000 --- a/test/robot/lingo/examples/simplecalc/main.lingo +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "flag" - "fmt" - "os" - "regexp" - "strconv" - "strings" - - "github.com/google/gapid/core/app" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/lingo" -) - -func main() { - app.ShortHelp = "calc: A simple calculator." - app.Run(run) -} - -type _ regexp.Regexp - -type ( - Whitespace string - Digits string - Operator string - Bracket string -) - -const ( - opAdd = Operator('+') - opSubtract = Operator('-') - opMultiply = Operator('*') - opDivide = Operator('/') - openParenthesis = Bracket('(') - closeParenthesis = Bracket(')') - - space = Whitespace(`\s*`) - digits = Digits(`[0-9]+`) -) - -const ( - ErrorParenOrNumber = "Expected parenthesis or number" -) - -func run(ctx context.Context) error { - args := flag.Args() - if len(args) < 1 { - app.Usage(ctx, "Missing expression") - return nil - } - input := strings.Join(args, " ") - s := lingo.NewStringScanner(ctx, "command_line", input, nil) - value, err := expression(s) - if err != nil { - return err - } - if !s.EOF() { - return log.Err(ctx, nil, "Input not consumed") - } - fmt.Fprintf(os.Stdout, "%s = %d\n", input, value) - return nil -} - -func expression(s *lingo.Scanner) (int, error) { - return addition(s) -} - -func parenthesised(s *lingo.Scanner) (int, error) { - openParenthesis(s) - value := expression(s) - closeParenthesis(s) - return value, nil -} - -func addition(s *lingo.Scanner) (int, error) { - value := multiplication(s) - for { - space(s) - switch { - case opAdd(s): - value += multiplication(s) - case opSubtract(s): - value -= multiplication(s) - default: - return value, nil - } - } -} - -func multiplication(s *lingo.Scanner) (int, error) { - value := numeral(s) - for { - space(s) - switch { - case opMultiply(s): - value *= numeral(s) - case opDivide(s): - value /= numeral(s) - default: - return value, nil - } - } -} - -func numeral(s *lingo.Scanner) (int, error) { - if value, err := parenthesised(s); err == nil { - return value, err - } - if value, err := number(s); err == nil { - return value, err - } - return 0, s.Error(nil, ErrorParenOrNumber) -} - -func number(s *lingo.Scanner) (int, error) { - space(s) - value, err := strconv.Atoi(string(digits(s))) - if err != nil { - return 0, s.Error(err, "") - } - return value, nil -} diff --git a/test/robot/lingo/generator/BUILD.bazel b/test/robot/lingo/generator/BUILD.bazel deleted file mode 100644 index 2a98459698..0000000000 --- a/test/robot/lingo/generator/BUILD.bazel +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "generator.go", - "introspect.go", - "rewrite.go", - "wrap.go", - ], - importpath = "github.com/google/gapid/test/robot/lingo/generator", - visibility = ["//visibility:public"], - deps = [ - "//core/fault:go_default_library", - "//core/log:go_default_library", - "//core/os/file:go_default_library", - ], -) diff --git a/test/robot/lingo/generator/doc.go b/test/robot/lingo/generator/doc.go deleted file mode 100644 index 2e43533f5a..0000000000 --- a/test/robot/lingo/generator/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package generator provides the functionality used by the lingo command to add -// generated parser functionality based on syntactically correct go code. -// -// TODO: document the rewrites that this package performs, and thus the dsl it accepts -package generator diff --git a/test/robot/lingo/generator/generator.go b/test/robot/lingo/generator/generator.go deleted file mode 100644 index 05e3b2527a..0000000000 --- a/test/robot/lingo/generator/generator.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package generator - -import ( - "bytes" - "context" - "go/ast" - "go/format" - "go/parser" - "go/token" - "io/ioutil" - "strings" - - "github.com/google/gapid/core/fault" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" -) - -type lingoFile struct { - Input file.Path - Output file.Path - Parsed *ast.File -} - -const ( - inputSuffix = ".lingo" - outputSuffix = ".go" - ErrInvalidFilename = fault.Const("Invalid lingo input filename") -) - -// RewriteFiles is called to generate parsing functionality. -// It takes a list of input lingo files, and generates go files of the same basename in the output path. -func RewriteFiles(ctx context.Context, base string, inputs ...string) error { - info := &introspection{ - fset: token.NewFileSet(), - byName: map[string]*entry{}, - } - files := []lingoFile{} - basePath := file.Path{} - if base != "" { - basePath = file.Abs(base) - } - for _, name := range inputs { - f := lingoFile{Input: file.Abs(name)} - path, basename := f.Input.Split() - if !basePath.IsEmpty() { - path = basePath - } - if !strings.HasSuffix(name, inputSuffix) { - return log.Err(ctx, ErrInvalidFilename, "") - } - f.Output = path.Join(basename[:len(basename)-len(inputSuffix)] + outputSuffix) - parsed, err := parser.ParseFile(info.fset, f.Input.System(), nil, parser.ParseComments) - if err != nil { - return err - } - f.Parsed = parsed - if group := parsed.Comments[0]; group.Pos() < parsed.Package { - group.List = append(group.List, - &ast.Comment{Text: "// "}, - &ast.Comment{Text: "// Generated by lingo from " + basename}, - ) - } - info.collectEntryPoints(ctx, f.Parsed) - files = append(files, f) - } - info.prepare(ctx) - info.rewrite(ctx) - for _, f := range files { - ctx := log.V{"file": f.Output.Basename()}.Bind(ctx) - buf := &bytes.Buffer{} - formatErr := format.Node(buf, info.fset, f.Parsed) - writeErr := ioutil.WriteFile(f.Output.System(), buf.Bytes(), 0666) - if formatErr != nil { - return log.Err(ctx, formatErr, "Formatting") - } - if writeErr != nil { - return log.Err(ctx, writeErr, "Writing") - } - } - return nil -} diff --git a/test/robot/lingo/generator/introspect.go b/test/robot/lingo/generator/introspect.go deleted file mode 100644 index 12ee0853dc..0000000000 --- a/test/robot/lingo/generator/introspect.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package generator - -import ( - "context" - "go/ast" - "go/token" - "unicode" - "unicode/utf8" - - "github.com/google/gapid/core/log" -) - -type introspection struct { - fset *token.FileSet - entries []*entry - byName map[string]*entry -} - -type entry struct { - // Source is the source file the declaration came from. - Source *ast.File - // Name is the function name being wrapped. - Name string - // IsPointer is true if the return type is a pointer. - // This is used to control whether nil or a default value is used for error returns. - IsPointer bool - // ResultType is the stringified type declaration for the primary return type of the function. - ResultType string - // ParsedType is the underlying return type. This is only different from the result type in the - // presenced of type aliases, when a type cast may have to be inserted in the generated functions. - ParsedType string - // Params is the extracted parameters to the funciton. - Params []*ast.Field - // Public is true if this function is exposed outside the package. - Public bool - // Parser is true if this is detected to be a parsing funciton that wrapping. - Parser bool - // Called is true if the function is actually used. - Called bool - // DefaultName is name of the package global that holds the default value for the function return type - DefaultName string - // Func is the AST for the function being rewritten. - Func *ast.FuncDecl - // Value is the value declaration when constant as function rewrites are occuring. - Value *ast.BasicLit - // Method is the scanner method to invoke when constant as parser rewrites are occuring. - Method string -} - -func (info *introspection) collectEntryPoints(ctx context.Context, f *ast.File) { - // Find all the functions and constants. - for _, decl := range f.Decls { - switch decl := decl.(type) { - case *ast.FuncDecl: - info.entries = append(info.entries, &entry{ - Source: f, - Func: decl, - Name: decl.Name.Name, - }) - case *ast.GenDecl: - if decl.Tok != token.CONST { - break - } - for _, spec := range decl.Specs { - spec := spec.(*ast.ValueSpec) - for i, name := range spec.Names { - e := buildConstEntry(spec.Type, spec.Values[i]) - if e != nil { - e.Source = f - e.Name = name.Name - info.entries = append(info.entries, e) - } - } - } - } - } -} - -func buildConstEntry(t ast.Expr, v ast.Expr) *entry { - e := &entry{} - e.Parser = true - switch v := v.(type) { - case *ast.BasicLit: - e.Value = v - case *ast.CallExpr: - if len(v.Args) != 1 { - return nil - } - e.ResultType = v.Fun.(*ast.Ident).Name - litArg, ok := v.Args[0].(*ast.BasicLit) - if !ok { - return nil - } - e.Value = litArg - default: - return nil - } - switch e.Value.Kind { - case token.CHAR: - e.ParsedType = "rune" - e.Method = runeMethod - case token.STRING: - switch e.Value.Value[0] { - case '"': - e.Method = stringMethod - case '`': - e.Method = patternMethod - } - default: - return nil - } - if e.ResultType == "" { - e.ResultType = e.ParsedType - } - return e -} - -func (info *introspection) prepare(ctx context.Context) { - params := []*ast.Field{} - // Detect the rewritable functions - for _, e := range info.entries { - info.byName[e.Name] = e - if e.Func == nil { - // not a function type - continue - } - e.Parser = true - e.Params = e.Func.Type.Params.List - if r, _ := utf8.DecodeRuneInString(e.Name); unicode.IsUpper(r) { - e.Parser = false - } - if !collectReturnType(ctx, e) { - e.Parser = false - } - if len(e.Params) < 1 || len(e.Params[0].Names) < 1 { - e.Parser = false - } - if len(params) == 0 && e.Parser && len(e.Params) == 1 && len(e.Params[0].Names) == 1 { - params = e.Params - } - } - // Set the default params list now we have found it - for _, e := range info.entries { - if e.Params == nil { - e.Params = params - } - } -} - -func collectReturnType(ctx context.Context, e *entry) bool { - if e.Func.Type.Results == nil { - return false - } - if len(e.Func.Type.Results.List) != 2 { - return false - } - if !collectTypeName(ctx, e, e.Func.Type.Results.List[0].Type, true) { - return false - } - e.ResultType = e.ParsedType - return true -} - -func collectTypeName(ctx context.Context, e *entry, expr ast.Expr, top bool) bool { - switch t := expr.(type) { - case *ast.Ident: - e.ParsedType = t.Name - return true - case *ast.SelectorExpr: - if !collectTypeName(ctx, e, t.X, false) { - return false - } - e.ParsedType = e.ParsedType + "." + t.Sel.Name - return true - case *ast.StarExpr: - if !top { - log.F(ctx, true, "Can't cope with non simple pointers (%v)", expr) - return false - } - if !collectTypeName(ctx, e, t.X, false) { - return false - } - e.ParsedType = "*" + e.ParsedType - return true - default: - log.F(ctx, true, "Unknown type %T", t) - return false - } -} diff --git a/test/robot/lingo/generator/rewrite.go b/test/robot/lingo/generator/rewrite.go deleted file mode 100644 index fb729ed454..0000000000 --- a/test/robot/lingo/generator/rewrite.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package generator - -import ( - "context" - "fmt" - "go/ast" - "go/token" - "strings" -) - -type rewriter struct { - uid int - funcs map[string]*entry - fun *entry -} - -func (info *introspection) rewrite(ctx context.Context) { - // Do the initial rewrites - for _, e := range info.entries { - if e.Func != nil { - r := &rewriter{ - funcs: info.byName, - fun: e, - } - r.rewriteBlock(e.Func.Body) - } - } - // Add any additional function forms we need - for _, e := range info.entries { - generateFor(ctx, info.fset, e) - } - // Map and default values needed to the first file they are seen in - defined := map[string]bool{} - for _, e := range info.entries { - if e.DefaultName != "" { - if _, seen := defined[e.DefaultName]; !seen { - defined[e.DefaultName] = true - generateDefault(e.Source, e.DefaultName, e.ResultType) - } - } - } -} - -func (r *rewriter) UID() int { - r.uid++ - return r.uid -} - -func (r *rewriter) rewriteBlock(stmt *ast.BlockStmt) { - // We need to walk and rewrite all statements in all blocks - block := []ast.Stmt{} - for _, stmt := range stmt.List { - block = append(block, r.rewriteStatement(&block, stmt)) - } - stmt.List = block -} - -func (r *rewriter) rewriteStatement(stmts *[]ast.Stmt, stmt ast.Stmt) ast.Stmt { - switch stmt := stmt.(type) { - case *ast.BlockStmt: - r.rewriteBlock(stmt) - case *ast.ExprStmt: - call := r.checkCall(stmt.X) - if call != nil { - // Direct call, replace it - return r.errTest("err", &ast.AssignStmt{ - Lhs: []ast.Expr{ - &ast.Ident{Name: "_"}, - &ast.Ident{Name: "err"}, - }, - Tok: token.DEFINE, - Rhs: []ast.Expr{call}, - }) - } - case *ast.AssignStmt: - for i, expr := range stmt.Lhs { - stmt.Lhs[i] = r.liftValueExpression(stmts, expr) - } - if len(stmt.Lhs) != 2 || len(stmt.Rhs) != 1 || r.checkCall(stmt.Rhs[0]) == nil { - for i, expr := range stmt.Rhs { - stmt.Rhs[i] = r.liftValueExpression(stmts, expr) - } - } - case *ast.ReturnStmt: - if len(stmt.Results) == 1 { - r.checkCall(stmt.Results[0]) - } else { - for i, expr := range stmt.Results { - stmt.Results[i] = r.liftValueExpression(stmts, expr) - } - } - case *ast.IfStmt: - count := len(*stmts) - stmt.Cond = r.liftBoolExpression(stmts, stmt.Cond) - if stmt.Init != nil { - stmt.Init = r.rewriteStatement(stmts, stmt.Init) - } else if len(*stmts) == count+1 { - stmt.Init = (*stmts)[count] - *stmts = (*stmts)[:count] - } - r.rewriteBlock(stmt.Body) - if stmt.Else != nil { - count = len(*stmts) - stmt.Else = r.rewriteStatement(stmts, stmt.Else) - if len(*stmts) != count { - stmt.Else = &ast.BadStmt{} - } - } - case *ast.ForStmt: - id := r.UID() - mark := &ast.Ident{Name: fmt.Sprint("forMark", id)} - err := &ast.Ident{Name: fmt.Sprint("forErr", id)} - *stmts = append(*stmts, - &ast.AssignStmt{ - Lhs: []ast.Expr{mark}, - Tok: token.DEFINE, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: r.fun.Params[0].Names[0].Name}, - Sel: &ast.Ident{Name: "PreMark"}, - }, - Args: []ast.Expr{}, - }, - }, - }, - &ast.DeclStmt{ - Decl: &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{err}, - Type: &ast.Ident{Name: "error"}, - }}, - }, - }, - ) - stmt.Cond = r.liftBoolExpression(stmts, stmt.Cond) - r.rewriteBlock(stmt.Body) - stmt.Body.List = append([]ast.Stmt{ - r.errTest(err.Name, &ast.AssignStmt{ - Lhs: []ast.Expr{mark, err}, - Tok: token.ASSIGN, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: r.fun.Params[0].Names[0].Name}, - Sel: &ast.Ident{Name: "MustProgress"}, - }, - Args: []ast.Expr{mark}, - }, - }, - }), - }, stmt.Body.List...) - case *ast.DeclStmt: - // TODO: - case *ast.LabeledStmt: - stmt.Stmt = r.rewriteStatement(stmts, stmt.Stmt) - case *ast.SendStmt: - stmt.Chan = r.liftValueExpression(stmts, stmt.Chan) - stmt.Value = r.liftValueExpression(stmts, stmt.Value) - case *ast.IncDecStmt: - stmt.X = r.liftValueExpression(stmts, stmt.X) - case *ast.SwitchStmt: - stmt.Init = r.rewriteStatement(stmts, stmt.Init) - r.rewriteBlock(stmt.Body) - case *ast.CaseClause: - var extras []ast.Stmt - for i, expr := range stmt.List { - stmt.List[i] = r.liftBoolExpression(&extras, expr) - } - body := []ast.Stmt{} - if len(extras) != 0 { - body = append(body, &ast.BadStmt{}) - body = append(body, extras...) - body = append(body, &ast.BadStmt{}) - } - for _, stmt := range stmt.Body { - body = append(body, r.rewriteStatement(&body, stmt)) - } - stmt.Body = body - case *ast.TypeSwitchStmt: - stmt.Init = r.rewriteStatement(stmts, stmt.Init) - stmt.Assign = r.rewriteStatement(stmts, stmt.Assign) - r.rewriteBlock(stmt.Body) - case *ast.SelectStmt: - r.rewriteBlock(stmt.Body) - case *ast.CommClause: - stmt.Comm = r.rewriteStatement(stmts, stmt.Comm) - body := []ast.Stmt{} - for _, stmt := range stmt.Body { - body = append(body, r.rewriteStatement(&body, stmt)) - } - stmt.Body = body - case *ast.RangeStmt: - stmt.X = r.liftValueExpression(stmts, stmt.X) - r.rewriteBlock(stmt.Body) - } - return stmt -} - -func (r *rewriter) liftBoolExpression(stmts *[]ast.Stmt, expr ast.Expr) ast.Expr { - call := r.checkCall(expr) - if call == nil { - r.liftFromExpression(stmts, expr) - return expr - } - return &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "lingo"}, - Sel: &ast.Ident{Name: "WasOk"}, - }, - Args: []ast.Expr{call}, - } -} - -func (r *rewriter) liftValueExpression(stmts *[]ast.Stmt, expr ast.Expr) ast.Expr { - r.liftFromExpression(stmts, expr) - call := r.checkCall(expr) - if call == nil { - return expr - } - if len(call.Args) == 0 { - return call.Fun - } - val := &ast.Ident{Name: fmt.Sprint("val", r.UID())} - errName := fmt.Sprint("err", r.UID()) - *stmts = append(*stmts, - &ast.AssignStmt{ - Lhs: []ast.Expr{val, &ast.Ident{Name: errName}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{call}, - }, - r.errTest(errName, nil), - ) - return val -} - -func (r *rewriter) liftFromExpression(stmts *[]ast.Stmt, expr ast.Expr) { - switch expr := expr.(type) { - case *ast.UnaryExpr: - if expr.Op == token.NOT { - expr.X = r.liftBoolExpression(stmts, expr.X) - } else { - expr.X = r.liftValueExpression(stmts, expr.X) - } - case *ast.BinaryExpr: - if expr.Op == token.LAND || expr.Op == token.LOR { - expr.X = r.liftBoolExpression(stmts, expr.X) - expr.Y = r.liftBoolExpression(stmts, expr.Y) - } else { - expr.X = r.liftValueExpression(stmts, expr.X) - expr.Y = r.liftValueExpression(stmts, expr.Y) - } - case *ast.CallExpr: - for i, arg := range expr.Args { - expr.Args[i] = r.liftValueExpression(stmts, arg) - } - case *ast.CompositeLit: - for i, arg := range expr.Elts { - expr.Elts[i] = r.liftValueExpression(stmts, arg) - } - case *ast.ParenExpr: - expr.X = r.liftValueExpression(stmts, expr.X) - case *ast.SelectorExpr: - expr.X = r.liftValueExpression(stmts, expr.X) - case *ast.IndexExpr: - expr.X = r.liftValueExpression(stmts, expr.X) - expr.Index = r.liftValueExpression(stmts, expr.Index) - case *ast.SliceExpr: - expr.X = r.liftValueExpression(stmts, expr.X) - expr.Low = r.liftValueExpression(stmts, expr.Low) - expr.High = r.liftValueExpression(stmts, expr.High) - expr.Max = r.liftValueExpression(stmts, expr.Max) - case *ast.StarExpr: - expr.X = r.liftValueExpression(stmts, expr.X) - case *ast.KeyValueExpr: - expr.Value = r.liftValueExpression(stmts, expr.Value) - } -} - -func (r *rewriter) errTest(errName string, init ast.Stmt) *ast.IfStmt { - results := []ast.Expr{} - if r.fun.ResultType == "" { - } else if !r.fun.IsPointer { - if r.fun.DefaultName == "" { - r.fun.DefaultName = strings.Replace(r.fun.ResultType, ".", "_", -1) + "Default" - } - results = []ast.Expr{ - &ast.Ident{Name: r.fun.DefaultName}, - &ast.Ident{Name: errName}, - } - } else { - results = []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.Ident{Name: errName}, - } - } - return &ast.IfStmt{ - Init: init, - Cond: &ast.BinaryExpr{ - X: &ast.Ident{Name: errName}, - Op: token.NEQ, - Y: &ast.Ident{Name: "nil"}, - }, - Body: &ast.BlockStmt{List: []ast.Stmt{ - &ast.ReturnStmt{Results: results}, - }}, - } -} - -func (r *rewriter) checkCall(expr ast.Expr) *ast.CallExpr { - call, found := expr.(*ast.CallExpr) - if !found { - return nil - } - name, found := call.Fun.(*ast.Ident) - if !found { - return nil - } - invoke, found := r.funcs[name.Name] - if !found || !invoke.Parser { - return nil - } - invoke.Called = true - call.Fun = &ast.Ident{Name: invoke.Name + parserName} - return call -} diff --git a/test/robot/lingo/generator/wrap.go b/test/robot/lingo/generator/wrap.go deleted file mode 100644 index fd72fc1484..0000000000 --- a/test/robot/lingo/generator/wrap.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package generator - -import ( - "bytes" - "context" - "go/ast" - "go/format" - "go/parser" - "go/token" - "strings" -) - -const ( - runeMethod = `Rune` - stringMethod = `Literal` - patternMethod = `Pattern` - parserName = `Parser` - wrapper = ` - package exemplar - func _name_Parser(_params_) (_type_, error) { - _scanner_.Skip() - mark := _scanner_.Mark() - result, err := _call_(_args_) - if err != nil { - err = _scanner_.Error(err, "_name_") - _scanner_.Reset(mark) - } else { - _scanner_.Register(mark, _result_) - } - return _result_, err - } - ` -) - -func generateFor(ctx context.Context, fset *token.FileSet, wrap *entry) { - if !wrap.Called { - return - } - if wrap.Method == patternMethod { - wrap.Source.Decls = append(wrap.Source.Decls, &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: wrap.Name + patternMethod}}, - Values: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: "regexp"}, - Sel: &ast.Ident{Name: "MustCompile"}, - }, - Args: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: string(wrap.Value.Value[0]) + "^" + wrap.Value.Value[1:], - }}, - }}, - }}, - }) - } - scanner := wrap.Params[0].Names[0].Name - result := "result" - if wrap.ParsedType != wrap.ResultType { - result = wrap.ResultType + "(result)" - } - call := "" - args := "" - buf := &bytes.Buffer{} - for _, p := range wrap.Params { - for _, name := range p.Names { - if args != "" { - buf.WriteString(" ,") - args += ", " - } - buf.WriteString(name.Name) - buf.WriteString(" ") - format.Node(buf, fset, p.Type) - args += name.Name - } - } - params := buf.String() - if wrap.Func != nil { - call = "_name_" - } else { - call = "_scanner_." + wrap.Method - if wrap.Method == patternMethod { - args = wrap.Name + patternMethod - } else { - args = wrap.Value.Value - } - } - text := wrapper - text = strings.Replace(text, "_result_", result, -1) - text = strings.Replace(text, "_call_", call, -1) - text = strings.Replace(text, "_args_", args, -1) - text = strings.Replace(text, "_params_", params, -1) - text = strings.Replace(text, "_type_", wrap.ResultType, -1) - text = strings.Replace(text, "_scanner_", scanner, -1) - text = strings.Replace(text, "_name_", wrap.Name, -1) - wrapped, err := parser.ParseFile(fset, "", text, parser.ParseComments) - if err != nil { - panic(err) - } - wrap.Source.Decls = append(wrap.Source.Decls, wrapped.Decls...) -} - -func generateDefault(f *ast.File, name string, typ string) { - f.Decls = append(f.Decls, &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: name}}, - Type: &ast.Ident{Name: typ}, - }}, - }) -} diff --git a/test/robot/lingo/node.go b/test/robot/lingo/node.go deleted file mode 100644 index cc5a8ede19..0000000000 --- a/test/robot/lingo/node.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package lingo - -import "fmt" - -// Record is an entry in a Records list that holds a parse result along with its scan stream bounds. -type Record struct { - Start int - End int - Object interface{} -} - -// Records is a list of Record objects that represent the ordered sequence of parse results. -type Records []Record - -// Node is the form used when Records are reconstituted into a -type Node struct { - Start int - End int - Object interface{} - Parent *Node - Children []*Node -} - -// ToCST converts from a record list to a node span tree. -func (r Records) ToCST() *Node { - root := &Node{ - Start: 0, - End: len(r), - } - active := root - for _, entry := range r { - for entry.Start >= active.End && active.Parent != nil { - active = active.Parent - } - child := &Node{ - Start: entry.Start, - End: entry.End, - Object: entry.Object, - Parent: active, - } - active.Children = append(active.Children, child) - active = child - } - return root -} - -// Format implements fmt.Formatter to print the full record list. -func (r Records) Format(f fmt.State, _ rune) { - for _, entry := range r { - fmt.Fprint(f, entry.Object) - } -} - -// Format implements fmt.Formatter to print the leaf nodes in depth first order. -func (n *Node) Format(f fmt.State, _ rune) { - if len(n.Children) > 0 { - for _, child := range n.Children { - fmt.Fprint(f, child) - } - } else if n.Object != nil { - fmt.Fprint(f, n.Object) - } -} diff --git a/test/robot/lingo/scanner.go b/test/robot/lingo/scanner.go deleted file mode 100644 index 9db4f73e43..0000000000 --- a/test/robot/lingo/scanner.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package lingo - -import ( - "bytes" - "context" - "regexp" - "unicode/utf8" -) - -type Skipper func(*Scanner) - -// Marker is a stored point in a scanner that can be reset to. -type Marker struct { - offset int - count int -} - -// Scanner is a basic implementation of the functions used by generated parsers. -// It expects a the full byte slice of the source file. -type Scanner struct { - ctx context.Context - name string - data []byte - offset int - skipper Skipper - skipping bool - records *Records - watermark scanError -} - -// NewByteScanner builds a scanner over an input byte slice. -// If records is nil, the cst will not be maintained, otherwise it will be filled in with the parse Record list. -func NewByteScanner(ctx context.Context, name string, input []byte, records *Records) *Scanner { - return &Scanner{ctx: ctx, name: name, data: input, records: records} -} - -// NewStringScanner builds a scanner over an input string. -// If records is nil, the cst will not be maintained, otherwise it will be filled in with the parse Record list. -func NewStringScanner(ctx context.Context, name string, input string, records *Records) *Scanner { - return NewByteScanner(ctx, name, []byte(input), records) -} - -// WasOk is a helper function called by generated parser code. -// It is used to abandon the value result, and return true if there was no error. -// This is used in cases where the sub-parser is optional and the result is not needed. -func WasOk(_ interface{}, err error) bool { - return err == nil -} - -// SetSkip sets the skip function and returns the old one. -func (s *Scanner) SetSkip(skipper Skipper) Skipper { - old := s.skipper - s.skipper = skipper - return old -} - -// Skip invokes the current skip function if one is set. -func (s *Scanner) Skip() { - if s.skipping { - return - } - s.skipping = true - s.skipper(s) - s.skipping = false -} - -// EOF returns true if the scanner has run out of input. -func (s *Scanner) EOF() bool { - return s.offset >= len(s.data) -} - -// Mark returns a new marker for the current scan position and state. -func (s *Scanner) Mark() Marker { - m := Marker{offset: s.offset} - if s.records != nil { - m.count = len(*s.records) - } - return m -} - -// PreMark returns an invalid marker, used for before the start sentinels. -func (s *Scanner) PreMark() Marker { - return Marker{offset: -1} -} - -// MustProgress panics if the marker does not move forwards. -// Used to catch when the grammar is broken. -func (s *Scanner) MustProgress(m Marker) (Marker, error) { - err := error(nil) - if m.offset >= s.offset { - err = s.Error(nil, "Failed to make progress") - } - return s.Mark(), err -} - -// Watermark returns the error that was generatd furthest into the parse stream. -// This is normally included in errors automatically, and often indicates the point where -// the best match failed, and thus the actual error in the source. -func (s *Scanner) Watermark() error { - return s.watermark -} - -// Register adds a node to the cst from the start marker to the current position. -func (s *Scanner) Register(start Marker, object interface{}) { - if s.records == nil { - return - } - // append to grow - *s.records = append(*s.records, Record{}) - // shuffle up - copy((*s.records)[start.count+1:], (*s.records)[start.count:]) - // insert the record - (*s.records)[start.count] = Record{Start: start.offset, End: s.offset, Object: object} -} - -// Reset puts the scanner back in the state it was when the start Marker was taken. -func (s *Scanner) Reset(start Marker) { - s.offset = start.offset - if s.records != nil { - *s.records = (*s.records)[:start.count] - } -} - -// Rune is a parser for a single rune. -// If the next rune in the stream is a match, the rune will be consumed an error will be nil. -// Otherwise an error will be returned. -// In either case, the requested rune is returned as the value. -func (s *Scanner) Rune(r rune) (rune, error) { - v, size := utf8.DecodeRune(s.data[s.offset:]) - if v != r { - return r, scanFailure - } - s.offset += size - return v, nil -} - -// Rune is a parser for a literal string. -// If literal string is next in the stream, the string will be consumed an error will be nil. -// Otherwise an error will be returned and the value will be the empty string. -func (s *Scanner) Literal(str string) (string, error) { - data := []byte(str) - remains := s.data[s.offset:] - if len(data) > len(remains) || !bytes.Equal(data, remains[:len(data)]) { - return "", scanFailure - } - s.offset += len(data) - return str, nil -} - -// Pattern is a parser for a regular expression. -// If the pattern matches the start of the stream, the matching string will be consumed and returned. -// Otherwise an error will be returned and the value will be the empty string. -func (s *Scanner) Pattern(re *regexp.Regexp) (string, error) { - remains := s.data[s.offset:] - match := re.FindIndex(remains) - if match == nil { - return "", scanFailure - } - s.offset += match[1] - return string(remains[:match[1]]), nil -} diff --git a/test/robot/master/BUILD.bazel b/test/robot/master/BUILD.bazel deleted file mode 100644 index cea39a2167..0000000000 --- a/test/robot/master/BUILD.bazel +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "local.go", - "master.go", - "remote.go", - "satellite.go", - "server.go", - ], - embed = [":master_go_proto"], - importpath = "github.com/google/gapid/test/robot/master", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/event:go_default_library", - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "master_proto", - srcs = ["master.proto"], - visibility = ["//visibility:public"], - deps = ["//test/robot/search:search_proto"], -) - -go_proto_library( - name = "master_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/master", - proto = ":master_proto", - visibility = ["//visibility:public"], - deps = ["//test/robot/search:go_default_library"], -) diff --git a/test/robot/master/client.go b/test/robot/master/client.go deleted file mode 100644 index 3ee5149dad..0000000000 --- a/test/robot/master/client.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - "io" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/search" - "github.com/pkg/errors" -) - -// Client is a wrapper over a Master object that provides client targeted features. -type Client struct { - // Master is the master this client is talking to. - // This should not be modifed, the results are undefined if you do. - Master Master - shutdown Shutdown - name string -} - -// NewClient returns a new master client object that talks to the provided Master. -func NewClient(ctx context.Context, m Master) *Client { - return &Client{ - Master: m, - } -} - -// Orbit registers a satellite with the master. -// The function will only return when the connection is lost. -func (c *Client) Orbit(ctx context.Context, services ServiceList) (Shutdown, error) { - err := c.Master.Orbit(ctx, services, - func(ctx context.Context, command *Command) error { - switch do := command.Do.(type) { - case *Command_Ping: - return nil - case *Command_Identify: - c.name = do.Identify.Name - log.I(ctx, "Identified as %s", c.name) - return nil - case *Command_Shutdown: - // abort the report stream - c.shutdown = *do.Shutdown - return io.EOF - default: - return log.Err(ctx, nil, "Unknown command type") - } - }, - ) - if errors.Cause(err) == io.EOF { - err = nil - } - return c.shutdown, err -} - -// Shutdown causes a graceful shutdown of the server. -func (c *Client) Shutdown(ctx context.Context, to ...string) error { - _, err := c.Master.Shutdown(ctx, &ShutdownRequest{ - Shutdown: &Shutdown{ - Now: false, - Restart: false, - }, - To: to, - }) - return err -} - -// Restart causes a graceful shutdown and restart of the server. -func (c *Client) Restart(ctx context.Context, to ...string) error { - _, err := c.Master.Shutdown(ctx, &ShutdownRequest{ - Shutdown: &Shutdown{ - Now: false, - Restart: true, - }, - To: to, - }) - return err -} - -// Kill causes an immediate shutdown of the server. -func (c *Client) Kill(ctx context.Context, to ...string) error { - _, err := c.Master.Shutdown(ctx, &ShutdownRequest{ - Shutdown: &Shutdown{ - Now: true, - Restart: false, - }, - To: to, - }) - return err -} - -// Search delivers the set of satellites that match the query to the supplied function. -func (c *Client) Search(ctx context.Context, query *search.Query, handler SatelliteHandler) error { - return c.Master.Search(ctx, query, handler) -} diff --git a/test/robot/master/doc.go b/test/robot/master/doc.go deleted file mode 100644 index 9d9113d9c3..0000000000 --- a/test/robot/master/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package master holds the code for a master in the robot system. -// The master is the main coordination point, all other service are discovered -// through the master. -// It's main job is to manage and control the set of satellites. -// A satellite is a server that offers any of the other robot services. -package master diff --git a/test/robot/master/local.go b/test/robot/master/local.go deleted file mode 100644 index 6b94cae3ef..0000000000 --- a/test/robot/master/local.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - "fmt" - "reflect" - "sync" - "time" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/event" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" -) - -const masterName = "Master" -const keepaliveFrequency = time.Second * 10 - -var satelliteClass = reflect.TypeOf(&Satellite{}) - -type local struct { - satelliteLock sync.Mutex - satellites []*satellite - nextID int32 - keepalive *time.Ticker - onChange event.Broadcast -} - -// NewLocal creates a new local Master that manages it's own satellites. -func NewLocal(ctx context.Context) Master { - l := &local{ - keepalive: time.NewTicker(keepaliveFrequency), - } - crash.Go(func() { l.run(ctx) }) - return l -} - -func (m *local) Close(ctx context.Context) { - m.keepalive.Stop() -} - -// Search implements Master.Search -// It searches the set of active satellites, and supports monitoring of satellites as they start orbiting. -func (m *local) Search(ctx context.Context, query *search.Query, handler SatelliteHandler) error { - filter := eval.Filter(ctx, query, satelliteClass, event.AsHandler(ctx, handler)) - initial := m.producer(ctx) - if query.Monitor { - return event.Monitor(ctx, &m.satelliteLock, m.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -// Orbit implements Master.Orbit -// It will start orbiting the master, and will not return until it leaves orbit. -func (m *local) Orbit(ctx context.Context, services ServiceList, commands CommandHandler) error { - sat := m.addSatellite(ctx, services) - defer m.removeSatellite(ctx, sat) - crash.Go(func() { - sat.sendCommand(ctx, &Command{Do: &Command_Identify{Identify: &Identify{Name: sat.info.Name}}}) - }) - sat.processCommands(ctx, commands) - return nil -} - -// Shutdown implements Master.Shutdown -// It broadcasts the shutdown message to all satellites currently orbiting the master. -func (m *local) Shutdown(ctx context.Context, request *ShutdownRequest) (*ShutdownResponse, error) { - command := &Command{Do: &Command_Shutdown{Shutdown: request.Shutdown}} - response := &ShutdownResponse{} - return response, m.broadcast(ctx, command, request.To) -} - -func (m *local) getSatellites() []*satellite { - m.satelliteLock.Lock() - defer m.satelliteLock.Unlock() - return append([]*satellite(nil), m.satellites...) -} - -func (m *local) producer(ctx context.Context) event.Producer { - i := 0 - return func(ctx context.Context) interface{} { - if i >= len(m.satellites) { - return nil - } - res := m.satellites[i] - i++ - return res - } -} - -func (m *local) addSatellite(ctx context.Context, services ServiceList) *satellite { - m.satelliteLock.Lock() - defer m.satelliteLock.Unlock() - // generate the name and modify the list under the lock - name := "" - switch { - case services.Master: - name = fmt.Sprintf("Master_%d", m.nextID) - case services.Worker: - name = fmt.Sprintf("Worker_%d", m.nextID) - case services.Web: - name = fmt.Sprintf("Web_%d", m.nextID) - } - m.nextID++ - sat := newSatellite(ctx, name, services) - m.satellites = append(m.satellites, sat) - return sat -} - -func (m *local) removeSatellite(ctx context.Context, sat *satellite) error { - m.satelliteLock.Lock() - defer m.satelliteLock.Unlock() - // find and remove the satellite from the list - for i, e := range m.satellites { - if e == sat { - m.satellites = append(m.satellites[:i], m.satellites[i+1:]...) - break - } - } - return nil -} - -func serverInList(name string, servers []string) bool { - if len(servers) == 0 { - return true - } - for _, s := range servers { - if s == name { - return true - } - } - return false -} - -func (m *local) broadcast(ctx context.Context, command *Command, to []string) error { - // First send the command to all the registered services that match the to list - for _, sat := range m.getSatellites() { - if !serverInList(sat.info.Name, to) { - continue - } - sat.sendCommand(ctx, command) - } - return nil -} - -func (m *local) run(ctx context.Context) { - ping := &Command{Do: &Command_Ping{Ping: &Ping{}}} - // each time a tick happens - for _ = range m.keepalive.C { - // ping all the satellites to see if they are still up - for _, sat := range m.getSatellites() { - sat.sendCommand(ctx, ping) - } - } -} diff --git a/test/robot/master/master.go b/test/robot/master/master.go deleted file mode 100644 index a4d2c4481c..0000000000 --- a/test/robot/master/master.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - - "github.com/google/gapid/test/robot/search" -) - -type SatelliteHandler func(context.Context, *Satellite) error -type CommandHandler func(context.Context, *Command) error - -// Master is the interface to a master implementation. -// It abstracts away whether the master is remote or local. -type Master interface { - // Search returns a iterator of matching satellites from the store. - Search(context.Context, *search.Query, SatelliteHandler) error - // Orbit adds a satellite to the set being managed by the master. - // The master will use the returned command stream to control the satellite. - Orbit(context.Context, ServiceList, CommandHandler) error - // Shutdown is called to ask the master to send shutdown requests to satellites. - Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) -} diff --git a/test/robot/master/master.proto b/test/robot/master/master.proto deleted file mode 100644 index 878ac5e0c4..0000000000 --- a/test/robot/master/master.proto +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package master; -option go_package = "github.com/google/gapid/test/robot/master"; - -import "test/robot/search/search.proto"; - -// Satellite is the set of information the master knows about a connected -// satellite. -message Satellite { - // Name is the name of the satellite for command targeting. - // The name 'master' is reserved to refer to the master rather - // than the satellites. - // Names are assigned by the master on registry, and may be different - // for the same server each time it registers. - string name = 1; - // Services is the set of services the satellite reported supporting. - ServiceList services = 2; -} - -// Shutdown is a command that is sent to satellites to stop and restart them. -message Shutdown { - // Now controls whether the server is allowed to shutdown gracefully. - bool now = 1; - // Restart makes the server attempt to restart itself after it has shut down. - bool restart = 2; -} - -// Ping is a command used to verify from the send end that a streaming rpc is -// still open. -message Ping { -} - -// Identify is a command that is sent to satellites to tell them their identity. -message Identify { - // Restart makes the server attempt to restart itself after it has shut down. - string name = 1; -} - -// ServiceList is a report sent to the master to say what types of service -// a satellite supports. -message ServiceList { - // Master indicates the satellite is actually a master. - bool master = 1; - // Worker indicates the satellite supports one or more worker devices. - bool worker = 2; - // Web indicates the satellite is running the web service client. - bool web = 3; -} - -// Command contains master to satellite messages. -message Command { - oneof do { - Ping Ping = 1; - Identify Identify = 2; - Shutdown Shutdown = 3; - } -} - -// Service is the api to the robot master controller. -service Service { - // Orbit adds a satellite to the set being managed by the master. - // It will stay connected until the report stream is closed. - // The master will use the returned command stream to control the satellite. - rpc Orbit(OrbitRequest) returns (stream Command) { - }; - // Shutdown is called to ask the master to send shutdown requests to - // satellites. - rpc Shutdown(ShutdownRequest) returns (ShutdownResponse) { - }; - // Search is used to find satellite servers that match the given query. - rpc Search(search.Query) returns (stream Satellite) { - }; -} - -message ShutdownRequest { - // Shutdown hold the shutdown options. - Shutdown shutdown = 1; - // To holds the set of satellite servers to issue the shutdown - // command to. - // If the list is empty, the master broadcasts to all satellites, - // and also itself. - repeated string to = 2; -} - -message ShutdownResponse { -} - -message OrbitRequest { - // The list of services that the orbitting satellite supports. - ServiceList Services = 1; -} diff --git a/test/robot/master/remote.go b/test/robot/master/remote.go deleted file mode 100644 index 48b68bf24e..0000000000 --- a/test/robot/master/remote.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemoteMaster returns a Master that talks to a remote grpc Master service. -func NewRemoteMaster(ctx context.Context, conn *grpc.ClientConn) Master { - return &remote{ - client: NewServiceClient(conn), - } -} - -// Search implements Master.Search -// It forwards the call through grpc to the remote implementation. -func (m *remote) Search(ctx context.Context, query *search.Query, handler SatelliteHandler) error { - stream, err := m.client.Search(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Orbit implements Master.Orbit -// It forwards the call through grpc to the remote implementation. -func (m *remote) Orbit(ctx context.Context, services ServiceList, handler CommandHandler) error { - request := &OrbitRequest{Services: &services} - stream, err := m.client.Orbit(ctx, request) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Shutdown implements Master.Shutdown -// It forwards the call through grpc to the remote implementation. -func (m *remote) Shutdown(ctx context.Context, request *ShutdownRequest) (*ShutdownResponse, error) { - return m.client.Shutdown(ctx, request) -} diff --git a/test/robot/master/satellite.go b/test/robot/master/satellite.go deleted file mode 100644 index 94b93d62cf..0000000000 --- a/test/robot/master/satellite.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - "sync" - - "github.com/google/gapid/core/event/task" -) - -type satellite struct { - lock sync.Mutex - info *Satellite - issues chan issue -} - -// issue is used to package a command with a channel to feed the result of -// handling the command. -type issue struct { - command *Command - result chan error -} - -func newSatellite(ctx context.Context, name string, services ServiceList) *satellite { - return &satellite{ - info: &Satellite{ - Name: name, - Services: &services, - }, - issues: make(chan issue), - } -} - -// processCommands reads the issues from the channel and hands them to the command handler, sending -// the result back through the issue channel. -func (sat *satellite) processCommands(ctx context.Context, handler CommandHandler) { - for { - select { - case <-task.ShouldStop(ctx): - return - case i := <-sat.issues: - i.result <- handler(ctx, i.command) - close(i.result) - } - } -} - -// sendCommand posts an issue for the command into the channel, then blocks until it gets a result. -func (sat *satellite) sendCommand(ctx context.Context, command *Command) { - result := make(chan error) - sat.lock.Lock() - if sat.issues != nil { - sat.issues <- issue{command: command, result: result} - } - sat.lock.Unlock() - err := <-result - if err != nil { - sat.lock.Lock() - if sat.issues != nil { - close(sat.issues) - sat.issues = nil - } - sat.lock.Unlock() - } -} diff --git a/test/robot/master/server.go b/test/robot/master/server.go deleted file mode 100644 index 4eb58086c1..0000000000 --- a/test/robot/master/server.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package master - -import ( - "context" - - "github.com/google/gapid/test/robot/search" - - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - master Master - restart bool -} - -// Serve wraps a Master in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, m Master) error { - s := &server{master: m} - RegisterServiceServer(grpcServer, s) - return nil -} - -// Search implements ServiceServer.Search -// It delegates the call to the provided Master implementation. -func (s *server) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.master.Search(ctx, query, func(ctx context.Context, e *Satellite) error { return stream.Send(e) }) -} - -// Orbit implements ServiceServer.Orbit -// It delegates the call to the provided Master implementation. -func (s *server) Orbit(request *OrbitRequest, stream Service_OrbitServer) error { - ctx := stream.Context() - return s.master.Orbit(ctx, *request.Services, - func(ctx context.Context, command *Command) error { return stream.Send(command) }, - ) -} - -// Shutdown implements ServiceServer.Shutdown -// It delegates the call to the provided Master implementation. -func (s *server) Shutdown(ctx xctx.Context, request *ShutdownRequest) (*ShutdownResponse, error) { - return s.master.Shutdown(ctx, request) -} diff --git a/test/robot/monitor/BUILD.bazel b/test/robot/monitor/BUILD.bazel deleted file mode 100644 index 57a3136440..0000000000 --- a/test/robot/monitor/BUILD.bazel +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "build.go", - "doc.go", - "generation.go", - "job.go", - "monitor.go", - "replay.go", - "report.go", - "subject.go", - "trace.go", - ], - importpath = "github.com/google/gapid/test/robot/monitor", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/log:go_default_library", - "//core/os/android/apk:go_default_library", - "//core/os/device:go_default_library", - "//test/robot/build:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/master:go_default_library", - "//test/robot/replay:go_default_library", - "//test/robot/report:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/stash:go_default_library", - "//test/robot/subject:go_default_library", - "//test/robot/trace:go_default_library", - ], -) diff --git a/test/robot/monitor/build.go b/test/robot/monitor/build.go deleted file mode 100644 index 143b9eeb89..0000000000 --- a/test/robot/monitor/build.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/core/os/android/apk" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/build" -) - -// Package is the in memory representation/wrapper for a build.Package -type Package struct { - build.Package - parent *Package -} - -// Packages is the type that manages a set of Package objects. -type Packages struct { - entries []*Package -} - -// Track is the in memory representation/wrapper for a build.Track -type Track struct { - build.Track - head *Package -} - -// Tracks is the type that manages a set of Track objects. -type Tracks struct { - entries []*Track -} - -// All returns the complete set of Package objects we have seen so far. -func (p *Packages) All() []*Package { - return p.entries -} - -// All returns the complete set of Track objects we have seen so far. -func (t *Tracks) All() []*Track { - return t.entries -} - -// FindTools returns the tool set that matches the supplied device, if the package has one. -func (p *Package) FindTools(ctx context.Context, d *Device) *build.ToolSet { - if p == nil || d == nil { - return nil - } - for _, abi := range d.Information.Configuration.ABIs { - if tools := p.Package.GetHostTools(abi); tools != nil { - return tools - } - } - return nil -} - -// FindToolsForAPK returns the best matching tool set for a certain apk on a device, -// if present in the package. -func (p *Package) FindToolsForAPK(ctx context.Context, host *Device, target *Device, apkInfo *apk.Information) *build.AndroidToolSet { - targetToolsAbi := target.GetInformation().GetConfiguration().PreferredABI(apkInfo.ABI) - if targetToolsAbi == nil { - return nil - } - for _, abi := range host.Information.Configuration.ABIs { - if tools := p.Package.GetTargetTools(abi, targetToolsAbi); tools != nil { - return tools - } - } - return nil -} - -// FindToolsForDevice returns the best matching tool set for a certain device. -func (p *Package) FindToolsForDevice(ctx context.Context, host *Device, target *Device) *build.AndroidToolSet { - targetToolsAbi := target.GetInformation().GetConfiguration().PreferredABI([]*device.ABI{}) - if targetToolsAbi == nil { - return nil - } - for _, abi := range host.Information.Configuration.ABIs { - if tools := p.Package.GetTargetTools(abi, targetToolsAbi); tools != nil { - return tools - } - } - return nil -} - -func (o *DataOwner) updateTrack(ctx context.Context, track *build.Track) error { - o.Write(func(data *Data) { - for i, e := range data.Tracks.entries { - if track.Id == e.Id { - data.Tracks.entries[i].Track = *track - return - } - } - data.Tracks.entries = append(data.Tracks.entries, &Track{Track: *track}) - }) - return nil -} - -func (o *DataOwner) updatePackage(ctx context.Context, pkg *build.Package) error { - o.Write(func(data *Data) { - for i, e := range data.Packages.entries { - if pkg.Id == e.Id { - data.Packages.entries[i].Package = *pkg - return - } - } - data.Packages.entries = append(data.Packages.entries, &Package{Package: *pkg}) - }) - return nil -} diff --git a/test/robot/monitor/doc.go b/test/robot/monitor/doc.go deleted file mode 100644 index ee9b8e9550..0000000000 --- a/test/robot/monitor/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package monitor is a helper for keeping a local in memory representation -// of the key data from some of the robot services. -// It's purpose is to provice the main data source for packages like the web -// server and the scheduler. -// Most of the types are opaque about their contents to allow for lazy aquisition -// construction or lookup of their members. -// For instance, id's are normally resolved to objects for you, but that resolve may -// not happen until the member is asked for. -package monitor diff --git a/test/robot/monitor/generation.go b/test/robot/monitor/generation.go deleted file mode 100644 index ced3c4d48f..0000000000 --- a/test/robot/monitor/generation.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "sync" -) - -var alreadyClosed = make(chan struct{}) - -func init() { close(alreadyClosed) } - -// Generation is a way to handle sequences of 'updates' or 'generations', -// find out how many have happened, as well as blocking until the next one happens. -// This does not assume an 'update' to mean anything specific. -type Generation struct { - lock sync.Mutex - id uint64 - changed chan struct{} -} - -// ID returns the current generation identifier under the lock -func (g *Generation) ID() uint64 { - g.lock.Lock() - defer g.lock.Unlock() - return g.id -} - -// Get returns the generation identifier and blocking channel under the lock -func (g *Generation) Get() (uint64, chan struct{}) { - g.lock.Lock() - defer g.lock.Unlock() - return g.id, g.changed -} - -// Update increments the generation and notifies all blocked goroutines -func (g *Generation) Update() uint64 { - g.lock.Lock() - defer g.lock.Unlock() - close(g.changed) - g.changed = make(chan struct{}) - g.id++ - return g.id -} - -// WaitForUpdate blocks until the generation is past previous, and returns the -// current generation. -func (g *Generation) WaitForUpdate(previous uint64) uint64 { - current, block := g.Get() - if previous < current { - // we are already past this point, no need to wait - return current - } - <-block - return g.ID() -} - -// After returns a channel that will be closed as soon as the generation exceeds ID. -// This is intended for use in select calls, if you just want to wait, WaitForUpdate is -// more efficient. -func (g *Generation) After(id uint64) <-chan struct{} { - current, block := g.Get() - if id < current { - // we are already past this point, no need to wait - return alreadyClosed - } - return block -} - -// NewGeneration returns a new Generation starting with an id of 0. -func NewGeneration() *Generation { - return &Generation{ - changed: make(chan struct{}), - } -} diff --git a/test/robot/monitor/job.go b/test/robot/monitor/job.go deleted file mode 100644 index bfa3d6b363..0000000000 --- a/test/robot/monitor/job.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/test/robot/job" -) - -// Device is the in memory representation/wrapper for a job.Device -type Device struct { - job.Device -} - -// Devices is the type that manages a set of Device objects. -type Devices struct { - entries []*Device -} - -// Worker is the in memory representation/wrapper for a job.Worker -type Worker struct { - job.Worker -} - -// Workers is the type that manages a set of Worker objects. -type Workers struct { - entries []*Worker -} - -// All returns the complete set of Device objects we have seen so far. -func (d *Devices) All() []*Device { - return d.entries -} - -// FindDevice searches the device list for one that matches the supplied id. -func (data *Data) FindDevice(id string) *Device { - for _, d := range data.Devices.entries { - if d.Device.Id == id { - return d - } - } - return nil -} - -func (o *DataOwner) updateDevice(ctx context.Context, device *job.Device) error { - o.Write(func(data *Data) { - for i, e := range data.Devices.entries { - if device.Id == e.Id { - data.Devices.entries[i].Device = *device - return - } - } - data.Devices.entries = append(data.Devices.entries, &Device{Device: *device}) - }) - return nil -} - -// All returns the complete set of Worker objects we have seen so far. -func (w *Workers) All() []*Worker { - return w.entries -} - -func (o *DataOwner) updateWorker(ctx context.Context, worker *job.Worker) error { - o.Write(func(data *Data) { - for i, e := range data.Workers.entries { - if worker.Host == e.Host && worker.Target == e.Target { - data.Workers.entries[i].Worker = *worker - return - } - } - data.Workers.entries = append(data.Workers.entries, &Worker{Worker: *worker}) - }) - return nil -} diff --git a/test/robot/monitor/monitor.go b/test/robot/monitor/monitor.go deleted file mode 100644 index a991e822f3..0000000000 --- a/test/robot/monitor/monitor.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - "sync" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/master" - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/report" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/stash" - "github.com/google/gapid/test/robot/subject" - "github.com/google/gapid/test/robot/trace" -) - -// Managers describes the set of managers to monitor for data changes. -type Managers struct { - Master master.Master - Stash *stash.Client - Job job.Manager - Build build.Store - Subject subject.Subjects - Trace trace.Manager - Report report.Manager - Replay replay.Manager -} - -// Data is the live store of data from the monitored servers. -// Entries with no live manager will not be updated. -type Data struct { - mu sync.Mutex - cond *sync.Cond - - Gen *Generation - - Devices Devices - Workers Workers - Subjects Subjects - Tracks Tracks - Packages Packages - Traces Traces - Reports Reports - Replays Replays -} - -type DataOwner struct { - data *Data -} - -func NewDataOwner() DataOwner { - data := &Data{ - Gen: NewGeneration(), - } - data.cond = sync.NewCond(&data.mu) - return DataOwner{data} -} - -func (o DataOwner) Read(rf func(d *Data)) { - o.data.mu.Lock() - defer o.data.mu.Unlock() - rf(o.data) -} - -func (o DataOwner) Write(wf func(d *Data)) { - o.data.mu.Lock() - defer func() { - o.data.cond.Broadcast() - o.data.mu.Unlock() - }() - wf(o.data) -} - -func (data *Data) Wait() { - data.cond.Wait() -} - -// Run is used to run a new monitor. -// It will monitor the data from all the managers that are in the supplied managers, filling in the data structure -// with all the results it receives. -// Each time it receives a batch of updates it will invoke the update function passing in the manager set being -// monitored and the updated set of data. -func Run(ctx context.Context, managers Managers, owner DataOwner, update func(ctx context.Context, managers *Managers, data *Data) []error) error { - // start all the data monitors we have managers for - if err := monitor(ctx, &managers, owner); err != nil { - return err - } - - owner.Read(func(data *Data) { - for { - // Update generation - data.Gen.Update() - // Run the update - if update != nil { - if errs := update(ctx, &managers, data); len(errs) != 0 { - log.E(ctx, "Error(s) during update: %v", errs) - } - } - // Wait for new data - data.Wait() - } - }) - return nil -} - -func monitor(ctx context.Context, managers *Managers, owner DataOwner) error { - initial := &search.Query{} - // TODO: care about monitors erroring - monitor := &search.Query{Monitor: true} - if managers.Job != nil { - if err := managers.Job.SearchDevices(ctx, initial, owner.updateDevice); err != nil { - return err - } - crash.Go(func() { managers.Job.SearchDevices(ctx, monitor, owner.updateDevice) }) - if err := managers.Job.SearchWorkers(ctx, initial, owner.updateWorker); err != nil { - return err - } - crash.Go(func() { managers.Job.SearchWorkers(ctx, monitor, owner.updateWorker) }) - } - if managers.Build != nil { - if err := managers.Build.SearchTracks(ctx, initial, owner.updateTrack); err != nil { - return err - } - crash.Go(func() { managers.Build.SearchTracks(ctx, monitor, owner.updateTrack) }) - if err := managers.Build.SearchPackages(ctx, initial, owner.updatePackage); err != nil { - return err - } - crash.Go(func() { managers.Build.SearchPackages(ctx, monitor, owner.updatePackage) }) - } - if managers.Subject != nil { - if err := managers.Subject.Search(ctx, initial, owner.updateSubject); err != nil { - return err - } - crash.Go(func() { managers.Subject.Search(ctx, monitor, owner.updateSubject) }) - } - if managers.Trace != nil { - if err := managers.Trace.Search(ctx, initial, owner.updateTrace); err != nil { - return err - } - crash.Go(func() { managers.Trace.Search(ctx, monitor, owner.updateTrace) }) - } - if managers.Report != nil { - if err := managers.Report.Search(ctx, initial, owner.updateReport); err != nil { - return err - } - crash.Go(func() { managers.Report.Search(ctx, monitor, owner.updateReport) }) - } - if managers.Replay != nil { - if err := managers.Replay.Search(ctx, initial, owner.updateReplay); err != nil { - return err - } - crash.Go(func() { managers.Replay.Search(ctx, monitor, owner.updateReplay) }) - } - - return nil -} diff --git a/test/robot/monitor/replay.go b/test/robot/monitor/replay.go deleted file mode 100644 index 73cc91b2b6..0000000000 --- a/test/robot/monitor/replay.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/replay" -) - -// Replay is the in memory representation/wrapper for a replay.Action -type Replay struct { - replay.Action -} - -// Replays is the type that manages a set of Replay objects. -type Replays struct { - entries []*Replay -} - -// All returns the complete set of Replay objects we have seen so far. -func (r *Replays) All() []*Replay { - return r.entries -} - -func (o *DataOwner) updateReplay(ctx context.Context, action *replay.Action) error { - o.Write(func(data *Data) { - entry, _ := data.Replays.FindOrCreate(ctx, action) - entry.Action = *action - }) - return nil -} - -// Find searches the replays for the one that matches the supplied action. -// See worker.EquivalentAction for more information about how actions are compared. -func (r *Replays) Find(ctx context.Context, action *replay.Action) *Replay { - for _, entry := range r.entries { - if worker.EquivalentAction(&entry.Action, action) { - return entry - } - } - return nil -} - -// FindOrCreate returns the replay that matches the supplied action if it exists, if not -// it creates a new replay object, and returns it. -// It does not register the newly created replay object for you, that will happen only if -// a call is made to trigger the action on the replay service. -func (r *Replays) FindOrCreate(ctx context.Context, action *replay.Action) (*Replay, bool) { - entry := r.Find(ctx, action) - if entry != nil { - return entry, true - } - entry = &Replay{Action: *action} - r.entries = append(r.entries, entry) - return entry, false -} diff --git a/test/robot/monitor/report.go b/test/robot/monitor/report.go deleted file mode 100644 index d80b15e92b..0000000000 --- a/test/robot/monitor/report.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/report" -) - -// Report is the in memory representation/wrapper for a report.Action -type Report struct { - report.Action -} - -// Reports is the type that manages a set of Report objects. -type Reports struct { - entries []*Report -} - -// All returns the complete set of Report objects we have seen so far. -func (r *Reports) All() []*Report { - return r.entries -} - -func (o *DataOwner) updateReport(ctx context.Context, action *report.Action) error { - o.Write(func(data *Data) { - entry, _ := data.Reports.FindOrCreate(ctx, action) - entry.Action = *action - }) - return nil -} - -// Find searches the reports for the one that matches the supplied action. -// See worker.EquivalentAction for more information about how actions are compared. -func (r *Reports) Find(ctx context.Context, action *report.Action) *Report { - for _, entry := range r.entries { - if worker.EquivalentAction(&entry.Action, action) { - return entry - } - } - return nil -} - -// FindOrCreate returns the report that matches the supplied aciton if it exists, if not -// it creates a new report object, and returns it. -// It does not register the newly created report object for you, that will happen only if -// a call is made to trigger the action on the report service. -func (r *Reports) FindOrCreate(ctx context.Context, action *report.Action) (*Report, bool) { - entry := r.Find(ctx, action) - if entry != nil { - return entry, true - } - entry = &Report{Action: *action} - r.entries = append(r.entries, entry) - return entry, false -} diff --git a/test/robot/monitor/subject.go b/test/robot/monitor/subject.go deleted file mode 100644 index 069a5ced24..0000000000 --- a/test/robot/monitor/subject.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/test/robot/subject" -) - -// Subject is the in memory representation/wrapper for a subject.Subject -type Subject struct { - subject.Subject -} - -// Subjects is the type that manages a set of Subject objects. -type Subjects struct { - entries []*Subject -} - -// All returns the complete set of Subject objects we have seen so far. -func (s *Subjects) All() []*Subject { - return s.entries -} - -// Get returns the Subject which has the given Id, returns nil if such a -// Subject is not found. -func (s *Subjects) Get(id string) *Subject { - for _, subj := range s.All() { - if subj.Id == id { - return subj - } - } - return nil -} - -func (o *DataOwner) updateSubject(ctx context.Context, subj *subject.Subject) error { - o.Write(func(data *Data) { - for i, e := range data.Subjects.entries { - if subj.Id == e.Id { - data.Subjects.entries[i].Subject = *subj - return - } - } - data.Subjects.entries = append(data.Subjects.entries, &Subject{Subject: *subj}) - }) - return nil -} diff --git a/test/robot/monitor/trace.go b/test/robot/monitor/trace.go deleted file mode 100644 index 5c25ae0555..0000000000 --- a/test/robot/monitor/trace.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package monitor - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/trace" -) - -// Trace is the in memory representation/wrapper for a trace.Action -type Trace struct { - trace.Action -} - -// Traces is the type that manages a set of Trace objects. -type Traces struct { - entries []*Trace -} - -// All returns the complete set of Trace objects we have seen so far. -func (t *Traces) All() []*Trace { - return t.entries -} - -// MatchPackage returns the set of Trace objects that were traced with a specific package. -func (t *Traces) MatchPackage(p *Package) []*Trace { - result := []*Trace{} - for _, trace := range t.entries { - if trace.Input.Package == p.Id { - result = append(result, trace) - } - } - return result -} - -func (o *DataOwner) updateTrace(ctx context.Context, action *trace.Action) error { - o.Write(func(data *Data) { - entry, _ := data.Traces.FindOrCreate(ctx, action) - entry.Action = *action - }) - return nil -} - -// Find searches the traces for the one that matches the supplied action. -// See worker.EquivalentAction for more information about how actions are compared. -func (t *Traces) Find(ctx context.Context, action *trace.Action) *Trace { - for _, entry := range t.entries { - if worker.EquivalentAction(&entry.Action, action) { - return entry - } - } - return nil -} - -// FindOrCreate returns the trace that matches the supplied aciton if it exists, if not -// it creates a new trace object, and returns it. -// It does not register the newly created trace object for you, that will happen only if -// a call is made to trigger the action on the trace service. -func (t *Traces) FindOrCreate(ctx context.Context, action *trace.Action) (*Trace, bool) { - entry := t.Find(ctx, action) - if entry != nil { - return entry, true - } - entry = &Trace{Action: *action} - t.entries = append(t.entries, entry) - return entry, false -} diff --git a/test/robot/record/BUILD.bazel b/test/robot/record/BUILD.bazel deleted file mode 100644 index 2ad8cdb3cb..0000000000 --- a/test/robot/record/BUILD.bazel +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "file.go", - "json.go", - "ledger.go", - "library.go", - "null.go", - "pb.go", - "pbtxt.go", - "record.go", - "shelf.go", - ], - embed = [":record_go_proto"], - importpath = "github.com/google/gapid/test/robot/record", - visibility = ["//visibility:public"], - deps = [ - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/os/file:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - ], -) - -proto_library( - name = "record_proto", - srcs = ["record.proto"], - visibility = ["//visibility:public"], -) - -go_proto_library( - name = "record_go_proto", - importpath = "github.com/google/gapid/test/robot/record", - proto = ":record_proto", - visibility = ["//visibility:public"], -) diff --git a/test/robot/record/doc.go b/test/robot/record/doc.go deleted file mode 100644 index 3485299c27..0000000000 --- a/test/robot/record/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package record provides funcitonality for sequential storage of types in a -// variety of serialization formats. -package record diff --git a/test/robot/record/file.go b/test/robot/record/file.go deleted file mode 100644 index 4eace02ba9..0000000000 --- a/test/robot/record/file.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - "os" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" -) - -var ( - fileSearchOrder = []Kind{JSON, Text, Proto} -) - -// FileShelf is an implementation of Shelf that stores it's ledgers in files. -// Each ledger goes in it's own files, and records are appended to the file as they arrive. -// The actual storage format depends on the Kind of the ledger, which is detected on open. -type FileShelf struct { - path file.Path - // Kind specifies the default ledger storage for new ledgers that are created. - // It has no impact on existing ledgers. - Kind Kind -} - -// fileType implements file handling for a specific file Kind. -type fileType interface { - Ext() string - Open(ctx context.Context, f *os.File, null interface{}) (LedgerInstance, error) -} - -type readAt struct { - f *os.File - offset int64 -} - -var ( - // fileTypes holds the map of file handlers for the various kinds. - fileTypes = map[Kind]fileType{ - JSON: jsonFileType{}, - Text: pbtxtFileType{}, - Proto: pbbFileType{}, - } -) - -// NewFileShelf build a new FileShelf backed implementation of a Shelf where the files will be stored -// in the specified path. -func NewFileShelf(ctx context.Context, path file.Path) (Shelf, error) { - os.MkdirAll(path.System(), 0755) - return &FileShelf{ - path: path, - Kind: Proto, - }, nil -} - -// Open implements Shelf.Open for a file backed shelf. -// It will attempt to open and read the specified ledger, returning an error only -// if the ledger exists but is invalid. -// It will try all known ledger types in priority order, if you have more than -// one type for the ledger, only the first file will be found. -func (s *FileShelf) Open(ctx context.Context, name string, null interface{}) (Ledger, error) { - // see if we can find a file that matches the name - for _, kind := range fileSearchOrder { - ft := fileTypes[kind] - l, err := s.tryOpen(ctx, name, null, ft) - if err != nil { - return nil, err - } - if l != nil { - return l, nil - } - } - return nil, nil -} - -// Create implements Shelf.Create for a file backed shelf, creating a new ledger file of the -// current default kind. -// It will return an error if for any reason the ledger cannot be created. -func (s *FileShelf) Create(ctx context.Context, name string, null interface{}) (Ledger, error) { - // Create the default file type - ft := fileTypes[s.Kind] - filename := s.path.Join(name).ChangeExt(ft.Ext()) - f, err := os.OpenFile(filename.System(), os.O_RDWR|os.O_CREATE|os.O_EXCL|os.O_APPEND, 0660) - if err != nil { - return nil, err - } - log.I(ctx, "Created file record ledger: %v", filename) - h, err := ft.Open(ctx, f, null) - if err != nil { - return nil, err - } - return NewLedger(ctx, h), nil -} - -// tryOpen is used to attempt to open and read a ledger file. -// It returns an error only if the ledger file exists, but is not valid. -func (s *FileShelf) tryOpen(ctx context.Context, name string, null interface{}, ft fileType) (Ledger, error) { - filename := s.path.Join(name).ChangeExt(ft.Ext()) - f, err := os.OpenFile(filename.System(), os.O_RDWR|os.O_APPEND, 0660) - if err != nil { - return nil, nil - } - log.I(ctx, "Open file record ledger: %v", filename) - h, err := ft.Open(ctx, f, null) - if err != nil { - return nil, err - } - return NewLedger(ctx, h), nil -} - -func (r *readAt) Read(buf []byte) (int, error) { - n, err := r.f.ReadAt(buf, r.offset) - r.offset += int64(n) - return n, err -} diff --git a/test/robot/record/json.go b/test/robot/record/json.go deleted file mode 100644 index 9b54de2cfe..0000000000 --- a/test/robot/record/json.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - "encoding/json" - "os" - "reflect" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" -) - -// jsonFileType is an implementation of fileType that stores it's records in json format. -type jsonFileType struct{} - -type jsonHandler struct { - f *os.File - encoder *json.Encoder - null reflect.Type -} - -type jsonReader struct { - decoder *json.Decoder - null reflect.Type -} - -func (jsonFileType) Ext() string { return ".json" } - -func (jsonFileType) Open(ctx context.Context, f *os.File, null interface{}) (LedgerInstance, error) { - t := reflect.TypeOf(null).Elem() - if _, err := json.Marshal(reflect.New(t)); err != nil { - return nil, log.Err(ctx, nil, "Cannot create json ledger with non marshalable type") - } - return &jsonHandler{f: f, encoder: json.NewEncoder(f), null: t}, nil -} - -func (h *jsonHandler) Write(ctx context.Context, record interface{}) error { - return h.encoder.Encode(record) -} - -func (h *jsonHandler) Reader(ctx context.Context) event.Source { - return &jsonReader{decoder: json.NewDecoder(&readAt{f: h.f}), null: h.null} -} - -func (h *jsonHandler) Close(ctx context.Context) { - h.f.Close() -} - -func (h *jsonHandler) New(ctx context.Context) interface{} { - return reflect.New(h.null) -} - -func (r *jsonReader) Next(ctx context.Context) interface{} { - message := reflect.New(r.null) - err := r.decoder.Decode(message) - log.E(ctx, "Corrupt record file. Error: %v", err) - return message -} - -func (h *jsonReader) Close(ctx context.Context) {} diff --git a/test/robot/record/ledger.go b/test/robot/record/ledger.go deleted file mode 100644 index b44697b434..0000000000 --- a/test/robot/record/ledger.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - - "github.com/google/gapid/core/event" -) - -// Ledger is the interface to a sequential immutable record store. -// New records can only be added to a ledger, and old records cannot be modified. -type Ledger interface { - // Read will read all records already in the ledger and feed them to the supplied writer. - Read(ctx context.Context, handler event.Handler) error - // Watch will feed new entries as they arrive into the supplied handler. - Watch(ctx context.Context, handler event.Handler) - // Add a new entry to the ledger. - // The record must be of the same type that the ledger was opened with. - Add(ctx context.Context, record interface{}) error - // Close is called to close the register, and notify all watchers. - Close(ctx context.Context) - // New returns a new record of the type the ledger stores. - New(ctx context.Context) interface{} -} - -type ledger struct { - instance LedgerInstance - onAdd event.Broadcast -} - -// LedgerInstance is the interface to an implementation support class for a ledger. -// It is responsible for reading and writing the backing store. -type LedgerInstance interface { - Write(ctx context.Context, event interface{}) error - Reader(ctx context.Context) event.Source - New(ctx context.Context) interface{} - Close(ctx context.Context) -} - -// NewLedger returns a ledger from a backing store. -func NewLedger(ctx context.Context, instance LedgerInstance) Ledger { - return &ledger{instance: instance} -} - -func (l *ledger) Read(ctx context.Context, handler event.Handler) error { - r := l.instance.Reader(ctx) - defer r.Close(ctx) - return event.Feed(ctx, handler, r.Next) -} - -func (l *ledger) Watch(ctx context.Context, handler event.Handler) { - l.onAdd.Listen(ctx, handler) -} - -func (l *ledger) Add(ctx context.Context, record interface{}) error { - if err := l.instance.Write(ctx, record); err != nil { - return err - } - if err := l.onAdd.Send(ctx, record); err != nil { - return err - } - return nil -} - -func (l *ledger) Close(ctx context.Context) { - l.instance.Close(ctx) - l.onAdd.Send(ctx, nil) -} - -func (l *ledger) New(ctx context.Context) interface{} { - return l.instance.New(ctx) -} diff --git a/test/robot/record/library.go b/test/robot/record/library.go deleted file mode 100644 index 24cf271bc4..0000000000 --- a/test/robot/record/library.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - - "github.com/google/gapid/core/log" -) - -// Library is the main interface to record storage. -// It manages a set of shelves, and uses them to open and create ledgers. -type Library interface { - // Add appends new shelves to the library. - Add(ctx context.Context, shelf ...Shelf) - // Open opens a ledger from a shelf in the library. - Open(ctx context.Context, name string, null interface{}) (Ledger, error) -} - -// library is the default implementation of Library, it just holds a list of shelves. -type library struct { - shelves []Shelf -} - -// NewLibrary returns a new record library. -func NewLibrary(ctx context.Context) Library { - return &library{} -} - -// Add implements Shelf.Add for the default library implementation. -func (l *library) Add(ctx context.Context, shelf ...Shelf) { - l.shelves = append(l.shelves, shelf...) -} - -// Open implements Library.Open for the default library implementation. -// All shelves are searched for a matching ledger, if none is found then a new ledger is -// opened in the first shelf that was added. -func (l *library) Open(ctx context.Context, name string, null interface{}) (Ledger, error) { - if len(l.shelves) == 0 { - return nil, log.Err(ctx, nil, "Cannot open ledger with no shelves") - } - for _, shelf := range l.shelves { - if ledger, err := shelf.Open(ctx, name, null); err != nil { - return nil, err - } else if ledger != nil { - return ledger, nil - } - } - return l.shelves[0].Create(ctx, name, null) -} diff --git a/test/robot/record/null.go b/test/robot/record/null.go deleted file mode 100644 index ad1b8458ea..0000000000 --- a/test/robot/record/null.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - - "github.com/google/gapid/core/event" -) - -// nullShelf is an implementation of Shelf that creates null ledgers. -type nullShelf struct{} - -// nullLedger is an implementation of Ledger that just ignores all record append requests. -type nullLedger struct{} - -func NewNullShelf(ctx context.Context) (Shelf, error) { return &nullShelf{}, nil } -func (nullShelf) Open(context.Context, string, interface{}) (Ledger, error) { return nullLedger{}, nil } -func (nullShelf) Create(context.Context, string, interface{}) (Ledger, error) { - return nullLedger{}, nil -} -func (nullLedger) Read(ctx context.Context, h event.Handler) error { return nil } -func (nullLedger) Watch(ctx context.Context, w event.Handler) {} -func (nullLedger) Add(ctx context.Context, record interface{}) error { return nil } -func (nullLedger) Close(context.Context) {} -func (nullLedger) New(context.Context) interface{} { return nil } diff --git a/test/robot/record/pb.go b/test/robot/record/pb.go deleted file mode 100644 index 2178d67e65..0000000000 --- a/test/robot/record/pb.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - "encoding/binary" - "io" - "os" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" -) - -// pbbHandler is an implementation of fileType that stores it's records in binary proto format. -type pbbFileType struct{} - -type pbbHandler struct { - f *os.File - null proto.Message -} - -type pbbReader struct { - buf []byte - f io.Reader - null proto.Message -} - -func (pbbFileType) Ext() string { return ".pb" } - -func (pbbFileType) Open(ctx context.Context, f *os.File, null interface{}) (LedgerInstance, error) { - m, ok := null.(proto.Message) - if !ok { - return nil, log.Err(ctx, nil, "Cannot create proto ledger with non proto type") - } - return &pbbHandler{f: f, null: m}, nil -} - -func (h *pbbHandler) Write(ctx context.Context, record interface{}) error { - buf, err := proto.Marshal(record.(proto.Message)) - if err != nil { - return err - } - size := int32(len(buf)) - if err := binary.Write(h.f, binary.LittleEndian, &size); err != nil { - return err - } - _, err = h.f.Write(buf) - return err -} - -func (h *pbbHandler) Reader(ctx context.Context) event.Source { - return &pbbReader{f: &readAt{f: h.f}, null: h.null} -} - -func (h *pbbHandler) Close(ctx context.Context) { - h.f.Close() -} - -func (h *pbbHandler) New(ctx context.Context) interface{} { - return proto.Clone(h.null) -} - -func (r *pbbReader) Next(ctx context.Context) interface{} { - size := int32(0) - if err := binary.Read(r.f, binary.LittleEndian, &size); err != nil { - if err != io.EOF { - log.E(ctx, "Invalid proto record header in ledger. Error: %v", err) - } - return nil - } - if cap(r.buf) < int(size) { - r.buf = make([]byte, size*2) // TODO: very naive growth algorithm - } - r.buf = r.buf[0:size] - io.ReadFull(r.f, r.buf) - message := proto.Clone(r.null) - err := proto.Unmarshal(r.buf, message) - if err != nil { - log.E(ctx, "Invalid proto in ledger. Error: %v", err) - return nil - } - return message -} - -func (h *pbbReader) Close(ctx context.Context) {} diff --git a/test/robot/record/pbtxt.go b/test/robot/record/pbtxt.go deleted file mode 100644 index 819ac8b9ab..0000000000 --- a/test/robot/record/pbtxt.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "bufio" - "context" - "io" - "os" - - "github.com/golang/protobuf/proto" - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" -) - -// pbtxtFileType is an implementation of fileType that stores it's records in proto text format. -type pbtxtFileType struct{} - -type pbtxtHandler struct { - f *os.File - null proto.Message -} - -type pbtxtReader struct { - pending string - s *bufio.Scanner - null proto.Message -} - -const ( - pbtxtSeparator = "====================" - pbtxtSeparatorLine = "\n " + pbtxtSeparator + "\n" -) - -func (pbtxtFileType) Ext() string { return ".pbtxt" } - -func (pbtxtFileType) Open(ctx context.Context, f *os.File, null interface{}) (LedgerInstance, error) { - m, ok := null.(proto.Message) - if !ok { - return nil, log.Err(ctx, nil, "Cannot create proto text ledger with non proto type") - } - return &pbtxtHandler{f: f, null: m}, nil -} - -func (h *pbtxtHandler) Write(ctx context.Context, record interface{}) error { - if _, err := io.WriteString(h.f, proto.MarshalTextString(record.(proto.Message))); err != nil { - return err - } - _, err := io.WriteString(h.f, pbtxtSeparatorLine) - return err -} - -func (h *pbtxtHandler) Reader(ctx context.Context) event.Source { - return &pbtxtReader{s: bufio.NewScanner(&readAt{f: h.f}), null: h.null} -} - -func (h *pbtxtHandler) Close(ctx context.Context) { - h.f.Close() -} - -func (h *pbtxtHandler) New(ctx context.Context) interface{} { - return proto.Clone(h.null) -} - -func (r *pbtxtReader) Next(ctx context.Context) interface{} { - for r.s.Scan() { - line := r.s.Text() - if line == pbtxtSeparator { - message := proto.Clone(r.null) - err := proto.UnmarshalText(r.pending, message) - if err != nil { - log.E(ctx, "Invalid text proto in ledger. Error: %v", err) - return nil - } - r.pending = "" - return message - } - r.pending += line - r.pending += "\n" - } - return nil -} - -func (h *pbtxtReader) Close(ctx context.Context) {} diff --git a/test/robot/record/record.go b/test/robot/record/record.go deleted file mode 100644 index b22a45f4a4..0000000000 --- a/test/robot/record/record.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -const ( - Unknown = Kind_Unknown - None = Kind_None - Proto = Kind_Proto - Text = Kind_Text - JSON = Kind_JSON -) diff --git a/test/robot/record/record.proto b/test/robot/record/record.proto deleted file mode 100644 index bbde47b22c..0000000000 --- a/test/robot/record/record.proto +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package record; -option go_package = "github.com/google/gapid/test/robot/record"; - -// Kind represents a ledger storage type. -enum Kind { - // Unknown is the default (invalid) status. - Unknown = 0; - // None is used when persistent storage is not desired. - None = 1; - // Proto is used for binary proto buffer storage, extension .pbb - Proto = 2; - // Text is used for text proto buffer storage, extension .pbt - Text = 3; - // JSON is used for json storage, extension .json - JSON = 4; -} diff --git a/test/robot/record/shelf.go b/test/robot/record/shelf.go deleted file mode 100644 index 55b1487648..0000000000 --- a/test/robot/record/shelf.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package record - -import ( - "context" - "net/url" - "runtime" - "strings" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" -) - -// Shelf is the interface to an object that maintains a set of ledgers stored in a -// consistent way. -type Shelf interface { - // Open is used to open a ledger by name. - // All records in the ledger must be of the same type as the null value. - Open(ctx context.Context, name string, null interface{}) (Ledger, error) - // Create is used to make and return a new ledger in the shelf. - // All records in the ledger must be of the same type as the null value. - Create(ctx context.Context, name string, null interface{}) (Ledger, error) -} - -// NewShelf returns a new record shelf from the supplied url. -// The type of shelf will depend on the url given. -func NewShelf(ctx context.Context, shelfURL *url.URL) (Shelf, error) { - ctx = log.V{"ShelfURL": shelfURL.Path}.Bind(ctx) - switch shelfURL.Scheme { - case "", "file": - if shelfURL.Host != "" { - return nil, log.Err(ctx, nil, "Host not supported for file shelves") - } - if shelfURL.Path == "" { - return nil, log.Err(ctx, nil, "Path must be specified for file shelves") - } - if runtime.GOOS == "windows" && strings.IndexByte(shelfURL.Path, ':') == 2 { - // windows file urls have an extra slash before the volume label that needs to be removed - // see https://github.com/golang/go/issues/6027#issuecomment-66083310 - shelfURL.Path = strings.TrimPrefix(shelfURL.Path, "/") - } - log.I(ctx, "Build a file record shelf on %s", shelfURL.Path) - return NewFileShelf(ctx, file.Abs(shelfURL.Path)) - case "memory": - log.I(ctx, "Start an in memory record shelf") - return NewNullShelf(ctx) - default: - return nil, log.Err(ctx, nil, "Unknown record shelf url type") - } -} diff --git a/test/robot/replay/BUILD.bazel b/test/robot/replay/BUILD.bazel deleted file mode 100644 index 10aa18c970..0000000000 --- a/test/robot/replay/BUILD.bazel +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "local.go", - "manager.go", - "remote.go", - "server.go", - ], - embed = [":replay_go_proto"], - importpath = "github.com/google/gapid/test/robot/replay", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/app/layout:go_default_library", - "//core/event:go_default_library", - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//core/os/device/host:go_default_library", - "//core/os/file:go_default_library", - "//core/os/shell:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/stash:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "replay_proto", - srcs = ["replay.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:device_proto", - "//test/robot/job:job_proto", - "//test/robot/job/worker:worker_proto", - "//test/robot/search:search_proto", - ], -) - -go_proto_library( - name = "replay_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/replay", - proto = ":replay_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/replay/client.go b/test/robot/replay/client.go deleted file mode 100644 index eb794ca67c..0000000000 --- a/test/robot/replay/client.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "bytes" - "context" - "fmt" - "strings" - "time" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/app/layout" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/core/os/device/host" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/core/os/shell" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/stash" -) - -const ( - replayTimeout = time.Hour - // this string is returned when GAPIT fails to connect to the GAPIS, particularly due to ETXTBSY - // look at https://github.com/google/gapid/pull/933 for more information - retryString = "Failed to connect to the GAPIS server" -) - -type client struct { - store *stash.Client - manager Manager - tempDir file.Path -} - -// Run starts new replay client if any hardware is available. -func Run(ctx context.Context, store *stash.Client, manager Manager, tempDir file.Path) error { - c := &client{store: store, manager: manager, tempDir: tempDir} - job.OnDeviceAdded(ctx, c.onDeviceAdded) - host := host.Instance(ctx) - return manager.Register(ctx, host, host, c.replay) -} - -func (c *client) onDeviceAdded(ctx context.Context, host *device.Instance, target bind.Device) { - replayOnTarget := func(ctx context.Context, t *Task) error { - job.LockDevice(ctx, target) - defer func() { - // HACK: kill gapid.apk manually for now as subsequent reports/replays may freeze the app. - // Remove when https://github.com/google/gapid/issues/1666 is fixed. - target.Shell("am", "force-stop", "com.google.android.gapid.arm64v8a").Run(ctx) - target.Shell("am", "force-stop", "com.google.android.gapid.armeabiv7a").Run(ctx) - }() - defer job.UnlockDevice(ctx, target) - if target.Status(ctx) != bind.Status_Online { - log.I(ctx, "Trying to replay %s on %s not started, device status %s", - t.Input.Trace, target.Instance().GetSerial(), target.Status(ctx).String()) - return nil - } - return c.replay(ctx, t) - } - crash.Go(func() { - if err := c.manager.Register(ctx, host, target.Instance(), replayOnTarget); err != nil { - log.E(ctx, "Error running replay client: %v", err) - } - }) -} - -func (c *client) replay(ctx context.Context, t *Task) error { - if err := c.manager.Update(ctx, t.Action, job.Running, nil); err != nil { - return err - } - var output *Output - err := worker.RetryFunction(ctx, 4, time.Millisecond*100, func() (err error) { - ctx, cancel := task.WithTimeout(ctx, replayTimeout) - defer cancel() - output, err = doReplay(ctx, t.Action, t.Input, c.store, c.tempDir) - return err - }) - - status := job.Succeeded - if err != nil { - status = job.Failed - log.E(ctx, "Error running replay: %v", err) - } else if output.Err != "" { - status = job.Failed - log.E(ctx, "Error during replay: %v", output.Err) - } - - return c.manager.Update(ctx, t.Action, status, output) -} - -// doReplay extracts input files and runs `gapit video` on them, capturing the output. The output object will -// be partially filled in the event of an upload error from store in order to allow examination of the logs. -func doReplay(ctx context.Context, action string, in *Input, store *stash.Client, tempDir file.Path) (*Output, error) { - tracefile := tempDir.Join(action + ".gfxtrace") - videofile := tempDir.Join(action + "_replay.mp4") - - extractedDir := tempDir.Join(action + "_tools") - extractedLayout, err := layout.NewPkgLayout(extractedDir, true) - if err != nil { - return nil, err - } - - gapit, err := extractedLayout.Gapit(ctx) - if err != nil { - return nil, err - } - gapir, err := extractedLayout.Gapir(ctx, nil) - if err != nil { - return nil, err - } - gapis, err := extractedLayout.Gapis(ctx) - if err != nil { - return nil, err - } - vscLib, err := extractedLayout.Json(ctx, layout.LibVirtualSwapChain, in.GetToolingLayout().GetGapidAbi()) - if err != nil { - return nil, err - } - vscJson, err := extractedLayout.Json(ctx, layout.LibVirtualSwapChain, in.GetToolingLayout().GetGapidAbi()) - if err != nil { - return nil, err - } - - defer func() { - file.Remove(tracefile) - file.Remove(videofile) - file.RemoveAll(extractedDir) - }() - - for _, file := range []struct { - in string - out file.Path - }{ - {in.Trace, tracefile}, - {in.Gapit, gapit}, - {in.Gapis, gapis}, - {in.Gapir, gapir}, - {in.VirtualSwapChainLib, vscLib}, - {in.VirtualSwapChainJson, vscJson}, - } { - if err := store.GetFile(ctx, file.in, file.out); err != nil { - return nil, err - } - } - - if in.GetToolingLayout() != nil { - gapidAPK, err := extractedLayout.GapidApk(ctx, in.GetToolingLayout().GetGapidAbi()) - if err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.GapidApk, gapidAPK); err != nil { - return nil, err - } - } - - params := []string{ - "video", - "-gapir-device", in.GetGapirDevice(), - "-frames-minimum", "10", - "-type", "sxs", - "-out", videofile.System(), - tracefile.System(), - } - cmd := shell.Command(gapit.System(), params...) - outBuf := &bytes.Buffer{} - errBuf := &bytes.Buffer{} - outputObj := &Output{} - errs := []string{} - log.I(ctx, "Running replay action %s", cmd) - if err := cmd.Capture(outBuf, errBuf).Run(ctx); err != nil { - if err := worker.NeedsRetry(err.Error()); err != nil { - return nil, err - } - errs = append(errs, err.Error()) - } - - errs = append(errs, strings.TrimSpace(errBuf.String())) - outputObj.Err = strings.Join(errs, "\n") - if err := worker.NeedsRetry(outputObj.Err, retryString); err != nil { - return nil, err - } - - output := fmt.Sprintf("%s\n\n%s\n%s\n\n", cmd, strings.TrimSpace(outBuf.String()), strings.TrimSpace(errBuf.String())) - log.I(ctx, output) - logID, err := store.UploadString(ctx, stash.Upload{Name: []string{"replay.log"}, Type: []string{"text/plain"}}, output) - if err != nil { - return outputObj, err - } - outputObj.Log = logID - videoID, err := store.UploadFile(ctx, videofile) - if err != nil { - return outputObj, err - } - outputObj.Video = videoID - return outputObj, nil -} diff --git a/test/robot/replay/doc.go b/test/robot/replay/doc.go deleted file mode 100644 index 1b1c0864cc..0000000000 --- a/test/robot/replay/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package replay holds the functionality used to do device replay and -// comparison video generation for robot. -package replay diff --git a/test/robot/replay/local.go b/test/robot/replay/local.go deleted file mode 100644 index ffba51aeb6..0000000000 --- a/test/robot/replay/local.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" -) - -type local struct { - w worker.Manager -} - -func (a *Action) JobID() string { return a.Id } -func (a *Action) JobHost() string { return a.Host } -func (a *Action) JobTarget() string { return a.Target } -func (a *Action) JobInput() worker.Input { return a.Input } -func (a *Action) Init(id string, input worker.Input, w *job.Worker) { - a.Id = id - a.Input = input.(*Input) - a.Host = w.Host - a.Target = w.Target -} -func (t *Task) Init(id string, input worker.Input, w *job.Worker) { - t.Action = id - t.Input = input.(*Input) -} - -// NewLocal builds a new local manager. -func NewLocal(ctx context.Context, library record.Library, jobManager job.Manager) (Manager, error) { - l := &local{} - return l, l.w.Init(ctx, library, jobManager, job.Replay, &Action{}, &Task{}) -} - -// Search implements Manager.Search -// It searches the set of persisted actions, and supports monitoring of actions as they arrive. -func (l *local) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - return l.w.Actions.Search(ctx, query, handler) -} - -// Register implements Manager.Register -// See Workers.Register for more details on the implementation. -func (l *local) Register(ctx context.Context, host *device.Instance, - target *device.Instance, handler TaskHandler) error { - return l.w.Workers.Register(ctx, host, target, handler) -} - -// Do implements Manager.Do -// See Workers.Do for more details on the implementation. -func (l *local) Do(ctx context.Context, device string, input *Input) (string, error) { - return l.w.Do(ctx, device, input) -} - -// Update implements Manager.Update -// See Workers.Update for more details on the implementation. -func (l *local) Update(ctx context.Context, action string, status job.Status, output *Output) error { - return l.w.Update(ctx, &Action{Id: action, Status: status, Output: output}) -} diff --git a/test/robot/replay/manager.go b/test/robot/replay/manager.go deleted file mode 100644 index bd8914a33c..0000000000 --- a/test/robot/replay/manager.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/search" -) - -// ActionHandler is a function that handles a stream of Actions. -type ActionHandler func(context.Context, *Action) error - -// TaskHandler is a function that handles a stream of Tasks. -type TaskHandler func(context.Context, *Task) error - -// Manager is the interface to a trace manager. -type Manager interface { - // Search invokes handler with each output that matches the query. - Search(ctx context.Context, query *search.Query, handler ActionHandler) error - // Register a handler that will accept incoming tasks. - Register(ctx context.Context, host *device.Instance, target *device.Instance, handler TaskHandler) error - // Do asks the manager to send a task to a device. - Do(ctx context.Context, device string, input *Input) (string, error) - // Update adjusts the state of an action. - Update(ctx context.Context, action string, status job.Status, output *Output) error -} diff --git a/test/robot/replay/remote.go b/test/robot/replay/remote.go deleted file mode 100644 index e8abcca258..0000000000 --- a/test/robot/replay/remote.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a Worker that talks to a remote grpc replay service. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Manager { - return &remote{ - client: NewServiceClient(conn), - } -} - -// Search implements Manager.Search -// It forwards the call through grpc to the remote implementation. -func (m *remote) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - stream, err := m.client.Search(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Register implements Manager.Register -// It forwards the call through grpc to the remote implementation. -func (m *remote) Register(ctx context.Context, host *device.Instance, - target *device.Instance, handler TaskHandler) error { - request := &worker.RegisterRequest{Host: host, Target: target} - stream, err := m.client.Register(ctx, request) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Do implements Manager.Do -// It forwards the call through grpc to the remote implementation. -func (m *remote) Do(ctx context.Context, device string, input *Input) (string, error) { - response, err := m.client.Do(ctx, &DoRequest{Device: device, Input: input}) - return response.Id, err -} - -// Update implements Manager.Update -// It forwards the call through grpc to the remote implementation. -func (m *remote) Update(ctx context.Context, action string, status job.Status, output *Output) error { - request := &UpdateRequest{Action: action, Status: status, Output: output} - _, err := m.client.Update(ctx, request) - return err -} diff --git a/test/robot/replay/replay.proto b/test/robot/replay/replay.proto deleted file mode 100644 index a7d022a400..0000000000 --- a/test/robot/replay/replay.proto +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package replay; -option go_package = "github.com/google/gapid/test/robot/replay"; - -import "test/robot/job/job.proto"; -import "test/robot/job/worker/worker.proto"; -import "test/robot/search/search.proto"; -import "core/os/device/device.proto"; - -// Input describes the inputs to a replay action. -message Input { - // Trace is the stash id of the trace to replay. - string trace = 1; - // Gapit is the stash id of the graphics analysis tool to use. - string gapit = 2; - // Gapis is the stash id of the graphics analysis server to use. - string gapis = 3; - // Gapir is the stash id of the graphics replay daemon for replay on host. - string gapir = 4; - // GapidApk is the stash id of the gapid.apk to use for Vulkan trace - string gapid_apk = 5; - // ToolingLayout represents the ABI details for Vulkan replay. - ToolingLayout tooling_layout = 6; - // VirtualSwapChainLib is the stash id of the vulkan virtual-swap-chain loader - // library. - string virtual_swap_chain_lib = 7; - // VirtualSwapChainLib is the stash id of the vulkan virtual-swap-chain loader - // json file. - string virtual_swap_chain_json = 8; - // Package is the stash id of the package used to generate the report. - string package = 9; - // Api is the API of the commands to replay in the trace. - string api = 10; - // GapirDevice is the device on which to run the replay. - string gapir_device = 11; -} - -// ToolingLayout describes tools we use for tracing. -message ToolingLayout { - device.ABI gapid_abi = 1; -} - -// Output holds the outputs of a replay action. -message Output { - // Log is stash id of the generated log file. - string log = 1; - // Video is the movie of the replay frame capture output. - string video = 2; - // Err is the stderr buffer returned by the call to gapit. - string err = 3; -} - -// Action holds the information about an execution of a task. -message Action { - // Id is the unique id the action. - string id = 1; - // Input is the set of inputs to the action. - Input input = 2; - // Host is the device which hosts the action. - string host = 3; - // Target is the device on which the action will be performed. - string target = 4; - // Status is the status to set for the action - job.Status status = 5; - // Output is the results of the action. - Output output = 6; -} - -// Task holds the information needed to run a replay task on a device. -message Task { - // Action is the id of the action this task should post results to. - string action = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -// Service is the api to the robot replay manager. -service Service { - // Search is used to find actions that match the given query. - rpc Search(search.Query) returns (stream Action) { - }; - // Register registers a device for a stream of tasks. - rpc Register(worker.RegisterRequest) returns (stream Task) { - }; - // Do asks the manager to send a task to a device. - rpc Do(DoRequest) returns (worker.DoResponse) { - }; - // Update sets the results of an action. - rpc Update(UpdateRequest) returns (worker.UpdateResponse) { - }; -} - -message DoRequest { - // Device is the device id to perform the task on. - string device = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -message UpdateRequest { - // Action is the action to update. - string action = 1; - // Status is the status to set for the action - job.Status status = 2; - // Output is the outputs to set on the action. - Output output = 3; -} diff --git a/test/robot/replay/server.go b/test/robot/replay/server.go deleted file mode 100644 index ae9c5f0e37..0000000000 --- a/test/robot/replay/server.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package replay - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - manager Manager -} - -// Serve wraps a manager in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, manager Manager) error { - RegisterServiceServer(grpcServer, &server{manager: manager}) - return nil -} - -// Search implements ServiceServer.Search -// It delegates the call to the provided Manager implementation. -func (s *server) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.manager.Search(ctx, query, func(ctx context.Context, e *Action) error { return stream.Send(e) }) -} - -// Register implements ServiceServer.Register -// It delegates the call to the ovided Manager implementation. -func (s *server) Register(request *worker.RegisterRequest, stream Service_RegisterServer) error { - ctx := stream.Context() - return s.manager.Register(ctx, request.Host, request.Target, - func(ctx context.Context, t *Task) error { return stream.Send(t) }) -} - -// Do implements ServiceServer.Do -// It delegates the call to the provided Manager implementation. -func (s *server) Do(ctx xctx.Context, request *DoRequest) (*worker.DoResponse, error) { - id, err := s.manager.Do(ctx, request.Device, request.Input) - return &worker.DoResponse{Id: id}, err -} - -// Update implements ServiceServer.Update -// It delegates the call to t provided Manager implementation. -func (s *server) Update(ctx xctx.Context, request *UpdateRequest) (*worker.UpdateResponse, error) { - if err := s.manager.Update(ctx, request.Action, request.Status, request.Output); err != nil { - return nil, err - } - return &worker.UpdateResponse{}, nil -} diff --git a/test/robot/report/BUILD.bazel b/test/robot/report/BUILD.bazel deleted file mode 100644 index 7cdd809129..0000000000 --- a/test/robot/report/BUILD.bazel +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "local.go", - "manager.go", - "remote.go", - "server.go", - ], - embed = [":report_go_proto"], - importpath = "github.com/google/gapid/test/robot/report", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/app/layout:go_default_library", - "//core/event:go_default_library", - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//core/os/device/host:go_default_library", - "//core/os/file:go_default_library", - "//core/os/shell:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/stash:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "report_proto", - srcs = ["report.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:device_proto", - "//test/robot/job:job_proto", - "//test/robot/job/worker:worker_proto", - "//test/robot/search:search_proto", - ], -) - -go_proto_library( - name = "report_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/report", - proto = ":report_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/report/client.go b/test/robot/report/client.go deleted file mode 100644 index c597dc6212..0000000000 --- a/test/robot/report/client.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package report - -import ( - "bytes" - "context" - "fmt" - "strings" - "time" - - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/app/layout" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/core/os/device/host" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/core/os/shell" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/stash" -) - -const ( - reportTimeout = time.Hour - // this string is returned when GAPIT fails to connect to the GAPIS, particularly due to ETXTBSY - // look at https://github.com/google/gapid/pull/933 for more information - retryString = "Failed to connect to the GAPIS server" -) - -type client struct { - store *stash.Client - manager Manager - tempDir file.Path -} - -// Run starts new report client if any hardware is available. -func Run(ctx context.Context, store *stash.Client, manager Manager, tempDir file.Path) error { - c := &client{store: store, manager: manager, tempDir: tempDir} - job.OnDeviceAdded(ctx, c.onDeviceAdded) - host := host.Instance(ctx) - return manager.Register(ctx, host, host, c.report) -} - -func (c *client) onDeviceAdded(ctx context.Context, host *device.Instance, target bind.Device) { - reportOnTarget := func(ctx context.Context, t *Task) error { - job.LockDevice(ctx, target) - defer func() { - // HACK: kill gapid.apk manually for now as subsequent reports/replays may freeze the app. - // Remove when https://github.com/google/gapid/issues/1666 is fixed. - target.Shell("am", "force-stop", "com.google.android.gapid.arm64v8a").Run(ctx) - target.Shell("am", "force-stop", "com.google.android.gapid.armeabiv7a").Run(ctx) - }() - defer job.UnlockDevice(ctx, target) - if target.Status(ctx) != bind.Status_Online { - log.I(ctx, "Trying to report %s on %s not started, device status %s", - t.Input.Trace, target.Instance().GetSerial(), target.Status(ctx).String()) - return nil - } - return c.report(ctx, t) - } - crash.Go(func() { - if err := c.manager.Register(ctx, host, target.Instance(), reportOnTarget); err != nil { - log.E(ctx, "Error running report client: %v", err) - } - }) -} - -func (c *client) report(ctx context.Context, t *Task) error { - if err := c.manager.Update(ctx, t.Action, job.Running, nil); err != nil { - return err - } - var output *Output - err := worker.RetryFunction(ctx, 4, time.Millisecond*100, func() (err error) { - ctx, cancel := task.WithTimeout(ctx, reportTimeout) - defer cancel() - output, err = doReport(ctx, t.Action, t.Input, c.store, c.tempDir) - return - }) - status := job.Succeeded - if err != nil { - status = job.Failed - log.E(ctx, "Error running report: %v", err) - } else if output.Err != "" { - status = job.Failed - log.E(ctx, "Error during report: %v", output.Err) - } - - return c.manager.Update(ctx, t.Action, status, output) -} - -// doReport extracts input files and runs `gapit report` on them, capturing the output. The output object will -// be partially filled in the event of an upload error from store in order to allow examination of the logs. -func doReport(ctx context.Context, action string, in *Input, store *stash.Client, tempDir file.Path) (*Output, error) { - tracefile := tempDir.Join(action + ".gfxtrace") - reportfile := tempDir.Join(action + "_report.txt") - - extractedDir := tempDir.Join(action + "_tools") - extractedLayout, err := layout.NewPkgLayout(extractedDir, true) - if err != nil { - return nil, err - } - - gapit, err := extractedLayout.Gapit(ctx) - if err != nil { - return nil, err - } - gapis, err := extractedLayout.Gapis(ctx) - if err != nil { - return nil, err - } - - defer func() { - file.Remove(tracefile) - file.Remove(reportfile) - file.RemoveAll(extractedDir) - }() - if err := store.GetFile(ctx, in.Trace, tracefile); err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.Gapit, gapit); err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.Gapis, gapis); err != nil { - return nil, err - } - - if in.GetToolingLayout() != nil { - gapidAPK, err := extractedLayout.GapidApk(ctx, in.GetToolingLayout().GetGapidAbi()) - if err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.GapidApk, gapidAPK); err != nil { - return nil, err - } - } - - params := []string{ - "report", - "-gapir-device", in.GetGapirDevice(), - "-out", reportfile.System(), - tracefile.System(), - } - cmd := shell.Command(gapit.System(), params...) - outBuf := &bytes.Buffer{} - errBuf := &bytes.Buffer{} - outputObj := &Output{} - errs := []string{} - log.I(ctx, "Running report action %s", cmd) - if err := cmd.Capture(outBuf, errBuf).Run(ctx); err != nil { - if err := worker.NeedsRetry(err.Error()); err != nil { - return nil, err - } - errs = append(errs, err.Error()) - } - errs = append(errs, strings.TrimSpace(errBuf.String())) - outputObj.Err = strings.Join(errs, "\n") - if err := worker.NeedsRetry(outputObj.Err, retryString); err != nil { - return nil, err - } - - output := fmt.Sprintf("%s\n\n%s", cmd, strings.TrimSpace(outBuf.String())) - log.I(ctx, output) - logID, err := store.UploadString(ctx, stash.Upload{Name: []string{"report.log"}, Type: []string{"text/plain"}}, output) - if err != nil { - return outputObj, err - } - outputObj.Log = logID - reportID, err := store.UploadFile(ctx, reportfile) - if err != nil { - return outputObj, err - } - outputObj.Report = reportID - return outputObj, nil -} diff --git a/test/robot/report/doc.go b/test/robot/report/doc.go deleted file mode 100644 index 8105400815..0000000000 --- a/test/robot/report/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package report holds the functionality for running trace reports and -// verifying correctness of a trace in the robot system. -package report diff --git a/test/robot/report/local.go b/test/robot/report/local.go deleted file mode 100644 index 876ab0118a..0000000000 --- a/test/robot/report/local.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package report - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" -) - -type local struct { - w worker.Manager -} - -func (a *Action) JobID() string { return a.Id } -func (a *Action) JobHost() string { return a.Host } -func (a *Action) JobTarget() string { return a.Target } -func (a *Action) JobInput() worker.Input { return a.Input } -func (a *Action) Init(id string, input worker.Input, w *job.Worker) { - a.Id = id - a.Input = input.(*Input) - a.Host = w.Host - a.Target = w.Target -} -func (t *Task) Init(id string, input worker.Input, w *job.Worker) { - t.Action = id - t.Input = input.(*Input) -} - -// NewLocal builds a new local manager. -func NewLocal(ctx context.Context, library record.Library, jobManager job.Manager) (Manager, error) { - l := &local{} - return l, l.w.Init(ctx, library, jobManager, job.Report, &Action{}, &Task{}) -} - -// Search implements Manager.Search -// It searches the set of persisted actions, and supports monitoring of actions as they arrive. -func (l *local) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - return l.w.Actions.Search(ctx, query, handler) -} - -// Register implements Manager.Register -// See Workers.Register for more details on the implementation. -func (l *local) Register(ctx context.Context, host *device.Instance, - target *device.Instance, handler TaskHandler) error { - return l.w.Workers.Register(ctx, host, target, handler) -} - -// Do implements Manager.Do -// See Workers.Do for more details on the implementation. -func (l *local) Do(ctx context.Context, device string, input *Input) (string, error) { - return l.w.Do(ctx, device, input) -} - -// Update implements Manager.Update -// See Workers.Update for more details on the implementation. -func (l *local) Update(ctx context.Context, action string, status job.Status, output *Output) error { - return l.w.Update(ctx, &Action{Id: action, Status: status, Output: output}) -} diff --git a/test/robot/report/manager.go b/test/robot/report/manager.go deleted file mode 100644 index e3578b56ea..0000000000 --- a/test/robot/report/manager.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package report - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/search" -) - -// ActionHandler is a function that handles a stream of Actions. -type ActionHandler func(context.Context, *Action) error - -// TaskHandler is a function that handles a stream of Tasks. -type TaskHandler func(context.Context, *Task) error - -// Manager is the interface to a trace manager. -type Manager interface { - // Search invokes handler with each output that matches the query. - Search(ctx context.Context, query *search.Query, handler ActionHandler) error - // Register registers a handler that will accept incoming tasks. - Register(ctx context.Context, host *device.Instance, target *device.Instance, handler TaskHandler) error - // Do asks the manager to send a task to a device. - Do(ctx context.Context, device string, input *Input) (string, error) - // Update adjusts the state of an action. - Update(ctx context.Context, action string, status job.Status, output *Output) error -} diff --git a/test/robot/report/remote.go b/test/robot/report/remote.go deleted file mode 100644 index 91d8660082..0000000000 --- a/test/robot/report/remote.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package report - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a Worker that talks to a remote grpc report service. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Manager { - return &remote{ - client: NewServiceClient(conn), - } -} - -// Search implements Manager.Search -// It forwards the call through grpc to the remote implementation. -func (m *remote) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - stream, err := m.client.Search(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Register implements Manager.Register -// It forwards the call through grpc to the remote implementation. -func (m *remote) Register(ctx context.Context, host *device.Instance, - target *device.Instance, handler TaskHandler) error { - request := &worker.RegisterRequest{Host: host, Target: target} - stream, err := m.client.Register(ctx, request) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Do implements Manager.Do -// It forwards the call through grpc to the remote implementation. -func (m *remote) Do(ctx context.Context, device string, input *Input) (string, error) { - response, err := m.client.Do(ctx, &DoRequest{Device: device, Input: input}) - return response.Id, err -} - -// Update implements Manager.Update -// It forwards the call through grpc to the remote implementation. -func (m *remote) Update(ctx context.Context, action string, status job.Status, output *Output) error { - request := &UpdateRequest{Action: action, Status: status, Output: output} - _, err := m.client.Update(ctx, request) - return err -} diff --git a/test/robot/report/report.proto b/test/robot/report/report.proto deleted file mode 100644 index ff73cdbc65..0000000000 --- a/test/robot/report/report.proto +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package report; -option go_package = "github.com/google/gapid/test/robot/report"; - -import "test/robot/job/job.proto"; -import "test/robot/job/worker/worker.proto"; -import "test/robot/search/search.proto"; -import "core/os/device/device.proto"; - -// Input describes the inputs to a report action. -message Input { - // Trace is the stash id of the trace to generate a report for. - string trace = 1; - // Gapit is the stash id of the graphics analysis tool to use. - string gapit = 2; - // Gapis is the stash id of the graphics analysis server to use. - string gapis = 3; - // GapidApk is the stash id of the gapid.apk to use for a Vulkan trace. - string gapid_apk = 4; - // ToolingLayout represents the ABI details for Vulkan report. - ToolingLayout tooling_layout = 5; - // Package is the stash id of the package used to generate the report. - string package = 6; - // Api is the API of the commands to report in the trace. - string api = 7; - // GapirDevice is the device on which to run the trace for report. - string gapir_device = 8; -} - -// ToolingLayout describes tools we use for tracing. -message ToolingLayout { - device.ABI gapid_abi = 1; -} - -// Output describes the outputs of a report action. -message Output { - // Log is stash id of the generated log file. - string log = 1; - // Report is the stash id of the generated report file. - string report = 2; - // Err is the stderr buffer returned by the call to gapit. - string err = 3; -} - -// Action holds the information about an execution of a task. -message Action { - // Id is the unique id the action. - string id = 1; - // Input is the set of inputs to the action. - Input input = 2; - // Host is the device which hosts the action. - string host = 3; - // Target is the device on which the action will be performed. - string target = 4; - // Status is the status to set for the action - job.Status status = 5; - // Output is the results of the action. - Output output = 6; -} - -// Task holds the information needed to run a report task in a device. -message Task { - // Action is the id of the action this task should post results to. - string action = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -// Service is the api to the robot device storage. -service Service { - // Search is used to find actions that match the given query. - rpc Search(search.Query) returns (stream Action) { - }; - // Register registers a device for a stream of tasks. - rpc Register(worker.RegisterRequest) returns (stream Task) { - }; - // Do asks the manager to send a task to a device. - rpc Do(DoRequest) returns (worker.DoResponse) { - }; - // Update sets the results of an action. - rpc Update(UpdateRequest) returns (worker.UpdateResponse) { - }; -} - -message DoRequest { - // Device is the device id to perform the task on. - string device = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -message UpdateRequest { - // Action is the action to update. - string action = 1; - // Status is the status to set for the action - job.Status status = 2; - // Output is the outputs to set on the action. - Output output = 3; -} diff --git a/test/robot/report/server.go b/test/robot/report/server.go deleted file mode 100644 index 692dc9b647..0000000000 --- a/test/robot/report/server.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package report - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - manager Manager -} - -// Serve wraps a manager in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, manager Manager) error { - RegisterServiceServer(grpcServer, &server{manager: manager}) - return nil -} - -// Search implements ServiceServer.Search -// It delegates the call to the provided Manager implementation. -func (s *server) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.manager.Search(ctx, query, func(ctx context.Context, e *Action) error { return stream.Send(e) }) -} - -// Register implements ServiceServer.Register -// It delegates the call to the provided Manager implementation. -func (s *server) Register(request *worker.RegisterRequest, stream Service_RegisterServer) error { - ctx := stream.Context() - return s.manager.Register(ctx, request.Host, request.Target, - func(ctx context.Context, t *Task) error { return stream.Send(t) }) -} - -// Do implements ServiceServer.Do -// It delegates the call to the provided Manager implementation. -func (s *server) Do(ctx xctx.Context, request *DoRequest) (*worker.DoResponse, error) { - id, err := s.manager.Do(ctx, request.Device, request.Input) - return &worker.DoResponse{Id: id}, err -} - -// Update implements ServiceServer.Update -// It delegates the call to the provided Manager implementation. -func (s *server) Update(ctx xctx.Context, request *UpdateRequest) (*worker.UpdateResponse, error) { - if err := s.manager.Update(ctx, request.Action, request.Status, request.Output); err != nil { - return nil, err - } - return &worker.UpdateResponse{}, nil -} diff --git a/test/robot/scheduler/BUILD.bazel b/test/robot/scheduler/BUILD.bazel deleted file mode 100644 index 5aa8554837..0000000000 --- a/test/robot/scheduler/BUILD.bazel +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "replay.go", - "report.go", - "scheduler.go", - "trace.go", - ], - importpath = "github.com/google/gapid/test/robot/scheduler", - visibility = ["//visibility:public"], - deps = [ - "//core/log:go_default_library", - "//test/robot/build:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/monitor:go_default_library", - "//test/robot/replay:go_default_library", - "//test/robot/report:go_default_library", - "//test/robot/trace:go_default_library", - ], -) diff --git a/test/robot/scheduler/doc.go b/test/robot/scheduler/doc.go deleted file mode 100644 index d846428efa..0000000000 --- a/test/robot/scheduler/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package scheduler holds the main task scheculing for the robot system. -// It watches for newly added builds, subjects and workers, and schedules -// jobs to fill in the holes in the testing. -package scheduler diff --git a/test/robot/scheduler/replay.go b/test/robot/scheduler/replay.go deleted file mode 100644 index de5b97f284..0000000000 --- a/test/robot/scheduler/replay.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/replay" -) - -func (s schedule) doReplay(ctx context.Context, t *monitor.Trace, - tools *build.ToolSet, androidTools *build.AndroidToolSet) error { - if !s.worker.Supports(job.Replay) { - return nil - } - - ctx = log.Enter(ctx, "Replay") - ctx = log.V{"Package": s.pkg.Id}.Bind(ctx) - - input := &replay.Input{ - Trace: t.Action.Output.Trace, - Gapit: tools.Host.Gapit, - Gapis: tools.Host.Gapis, - Gapir: tools.Host.Gapir, - VirtualSwapChainLib: tools.Host.VirtualSwapChainLib, - VirtualSwapChainJson: tools.Host.VirtualSwapChainJson, - Package: s.pkg.Id, - Api: t.Input.Hints.API, - GapirDevice: s.gapirDevice(), - } - if androidTools != nil { - input.GapidApk = androidTools.GapidApk - input.ToolingLayout = &replay.ToolingLayout{ - GapidAbi: androidTools.Abi, - } - } - action := &replay.Action{ - Input: input, - Host: s.worker.Host, - Target: s.worker.Target, - } - if _, found := s.data.Replays.FindOrCreate(ctx, action); found { - return nil - } - // TODO: we just ignore the error right now, what should we do? - go s.managers.Replay.Do(ctx, action.Target, input) - return nil -} diff --git a/test/robot/scheduler/report.go b/test/robot/scheduler/report.go deleted file mode 100644 index ed53e1a252..0000000000 --- a/test/robot/scheduler/report.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/report" -) - -func (s schedule) doReport(ctx context.Context, t *monitor.Trace, - tools *build.ToolSet, androidTools *build.AndroidToolSet) error { - if !s.worker.Supports(job.Report) { - return nil - } - - ctx = log.Enter(ctx, "Report") - ctx = log.V{"Package": s.pkg.Id}.Bind(ctx) - - input := &report.Input{ - Trace: t.Action.Output.Trace, - Gapit: tools.Host.Gapit, - Gapis: tools.Host.Gapis, - Package: s.pkg.Id, - Api: t.Input.Hints.API, - GapirDevice: s.gapirDevice(), - } - if androidTools != nil { - input.GapidApk = androidTools.GapidApk - input.ToolingLayout = &report.ToolingLayout{ - GapidAbi: androidTools.Abi, - } - } - action := &report.Action{ - Input: input, - Host: s.worker.Host, - Target: s.worker.Target, - } - if _, found := s.data.Reports.FindOrCreate(ctx, action); found { - return nil - } - // TODO: we just ignore the error right now, what should we do? - go s.managers.Report.Do(ctx, action.Target, input) - return nil -} diff --git a/test/robot/scheduler/scheduler.go b/test/robot/scheduler/scheduler.go deleted file mode 100644 index 3613b98101..0000000000 --- a/test/robot/scheduler/scheduler.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/monitor" -) - -type schedule struct { - managers *monitor.Managers - data *monitor.Data - pkg *monitor.Package - worker *monitor.Worker -} - -// Tick can be called to schedule new actions based on the current data set. -// It looks at the data to find holes that need actions to fill, and then picks which -// ones it thinks should be next based on the available workers. -// It is intended to be called in the update function of a monitor. -// See monitor.Run for more details. -// Blocking will prevent updates of the data store, so the function will try to schedule -// tasks to idle workers only returning quickly on the assumption it will be ticked again -// as soon as the data changes. -func Tick(ctx context.Context, managers *monitor.Managers, data *monitor.Data) []error { - var errs []error - // TODO: a real scheduler, not just try to do everything in any order - for _, pkg := range data.Packages.All() { - for _, w := range data.Workers.All() { - s := schedule{ - managers: managers, - data: data, - pkg: pkg, - worker: w, - } - tools := s.getHostTools(ctx) - if tools == nil { - continue - } - for _, subj := range data.Subjects.All() { - androidTools := s.getAndroidTools(ctx, subj) - if androidTools == nil { - continue - } - if err := s.doTrace(ctx, subj, tools, androidTools); err != nil { - errs = append(errs, err) - } - } - for _, t := range data.Traces.MatchPackage(s.pkg) { - if t.Status != job.Succeeded { - continue - } - if t.Output == nil { - continue - } - if !s.canReplay(t) { - continue - } - tracedSubj := data.Subjects.Get(t.Input.Subject) - if tracedSubj == nil { - errs = append(errs, log.Errf(ctx, nil, "Subject of trace: id= %v not found", t.Id)) - } - androidTools := s.getAndroidTools(ctx, tracedSubj) - if err := s.doReport(ctx, t, tools, androidTools); err != nil { - errs = append(errs, err) - } - if err := s.doReplay(ctx, t, tools, androidTools); err != nil { - errs = append(errs, err) - } - } - } - } - return errs -} - -func (s schedule) getHostTools(ctx context.Context) *build.ToolSet { - ctx = log.V{"Host": s.worker.Host}.Bind(ctx) - tools := s.pkg.FindTools(ctx, s.data.FindDevice(s.worker.Host)) - if tools == nil { - return nil - } - if tools.Host.Gapit == "" { - return nil - } - if tools.Host.Gapis == "" { - return nil - } - if tools.Host.Gapir == "" { - return nil - } - if tools.Host.VirtualSwapChainLib == "" { - return nil - } - if tools.Host.VirtualSwapChainJson == "" { - return nil - } - return tools -} - -func (s schedule) getAndroidTools(ctx context.Context, subj *monitor.Subject) *build.AndroidToolSet { - ctx = log.V{"target": s.worker.Target}.Bind(ctx) - if subj == nil { - return nil - } - tools := s.pkg.FindToolsForAPK(ctx, s.data.FindDevice(s.worker.Host), s.data.FindDevice(s.worker.Target), subj.GetAPK()) - if tools == nil { - return nil - } - if tools.GapidApk == "" { - return nil - } - return tools -} - -func (s schedule) getDeviceInfoTools(ctx context.Context) *build.AndroidToolSet { - ctx = log.V{"target": s.worker.Target}.Bind(ctx) - tools := s.pkg.FindToolsForDevice(ctx, s.data.FindDevice(s.worker.Host), s.data.FindDevice(s.worker.Target)) - if tools == nil { - return nil - } - if tools.GapidApk == "" { - return nil - } - return tools -} - -// canReplay determines whether the given trace can be replayed (and reported) -// on the target device in the worker of this schedule. -func (s schedule) canReplay(t *monitor.Trace) bool { - if s.worker == nil { - return false - } - // Gles trace must be replayed on host while Vulkan trace must be replayed - // on the same device where the trace was captured. - switch t.Input.Hints.API { - case "vulkan": - return s.worker.GetTarget() == t.GetTarget() - } - return false -} - -// gapirDevice returns "host" or Android device serial number in string of the -// target device of the worker of this schedule. If the schedule does not have -// a worker, returns an empty string. -func (s schedule) gapirDevice() string { - if s.worker == nil { - return "" - } - if s.worker.GetTarget() == s.worker.GetHost() { - return "host" - } - return s.data.FindDevice(s.worker.GetTarget()).GetInformation().GetSerial() -} diff --git a/test/robot/scheduler/trace.go b/test/robot/scheduler/trace.go deleted file mode 100644 index cdad0b31ad..0000000000 --- a/test/robot/scheduler/trace.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package scheduler - -import ( - "context" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/build" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/monitor" - "github.com/google/gapid/test/robot/trace" -) - -func (s schedule) doTrace(ctx context.Context, subj *monitor.Subject, tools *build.ToolSet, androidTools *build.AndroidToolSet) error { - if !s.worker.Supports(job.Trace) { - return nil - } - ctx = log.Enter(ctx, "Trace") - ctx = log.V{"Package": s.pkg.Id}.Bind(ctx) - input := &trace.Input{ - Subject: subj.Id, - Obb: subj.Obb, - Gapis: tools.Host.Gapis, - Gapit: tools.Host.Gapit, - GapidApk: androidTools.GapidApk, - Package: s.pkg.Id, - Hints: subj.Hints, - ToolingLayout: &trace.ToolingLayout{ - GapidAbi: androidTools.Abi, - }, - } - action := &trace.Action{ - Input: input, - Host: s.worker.Host, - Target: s.worker.Target, - } - if _, found := s.data.Traces.FindOrCreate(ctx, action); found { - return nil - } - // TODO: we just ignore the error right now, what should we do? - go s.managers.Trace.Do(ctx, action.Target, input) - return nil -} diff --git a/test/robot/search/BUILD.bazel b/test/robot/search/BUILD.bazel deleted file mode 100644 index c3c40c8b61..0000000000 --- a/test/robot/search/BUILD.bazel +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = ["doc.go"], - embed = [":search_go_proto"], - importpath = "github.com/google/gapid/test/robot/search", - visibility = ["//visibility:public"], -) - -proto_library( - name = "search_proto", - srcs = ["search.proto"], - visibility = ["//visibility:public"], -) - -go_proto_library( - name = "search_go_proto", - importpath = "github.com/google/gapid/test/robot/search", - proto = ":search_proto", - visibility = ["//visibility:public"], -) diff --git a/test/robot/search/doc.go b/test/robot/search/doc.go deleted file mode 100644 index efd380545f..0000000000 --- a/test/robot/search/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package search holds the structures needed to support a generalised -// query structure suitable for rpc's to a search service. -package search diff --git a/test/robot/search/eval/BUILD.bazel b/test/robot/search/eval/BUILD.bazel deleted file mode 100644 index 95b6903c36..0000000000 --- a/test/robot/search/eval/BUILD.bazel +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "eval.go", - ], - importpath = "github.com/google/gapid/test/robot/search/eval", - visibility = ["//visibility:public"], - deps = [ - "//core/event:go_default_library", - "//core/log:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/search/eval/doc.go b/test/robot/search/eval/doc.go deleted file mode 100644 index 06417232aa..0000000000 --- a/test/robot/search/eval/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package eval supplies logic for automatically applying a search query to -// a set of records. -// The main entry point is eval.Compile, that builds and returns a Matcher. -package eval diff --git a/test/robot/search/eval/eval.go b/test/robot/search/eval/eval.go deleted file mode 100644 index e25639cf22..0000000000 --- a/test/robot/search/eval/eval.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package eval - -import ( - "context" - "fmt" - "reflect" - "regexp" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/search" -) - -type eval func(context.Context, interface{}) interface{} - -var ( - boolType = reflect.TypeOf(true) - signedType = reflect.TypeOf(int64(0)) - unsignedType = reflect.TypeOf(uint64(0)) - doubleType = reflect.TypeOf(float64(0)) - stringType = reflect.TypeOf("") -) - -// Compile takes a search query and a a value type and produces a function that will perform the -// query against values of that type. -func Compile(ctx context.Context, query *search.Query, klass reflect.Type) (event.Predicate, error) { - m, res, err := compileExpression(ctx, query.Expression, klass) - if res.Kind() != reflect.Bool { - return nil, log.Err(ctx, nil, "Expression result not a bool") - } - return func(ctx context.Context, value interface{}) bool { - got := reflect.TypeOf(value) - if got != klass { - return false - } - return m(ctx, value).(bool) - }, err -} - -// Filter uses a search query and returns a handler that filters events before passing them to -// the output handler. -func Filter(ctx context.Context, query *search.Query, klass reflect.Type, handler event.Handler) event.Handler { - pred, err := Compile(ctx, query, klass) - if err != nil { - return func(ctx context.Context, event interface{}) error { - return err - } - } - return event.Filter(ctx, pred, handler) -} - -func compileExpression(ctx context.Context, expr *search.Expression, t reflect.Type) (eval, reflect.Type, error) { - if expr == nil { - return func(context.Context, interface{}) interface{} { return true }, boolType, nil - } - switch et := expr.Is.(type) { - case nil: - return func(context.Context, interface{}) interface{} { return true }, boolType, nil - case *search.Expression_Boolean: - return func(context.Context, interface{}) interface{} { return et.Boolean }, boolType, nil - case *search.Expression_String_: - return func(context.Context, interface{}) interface{} { return et.String_ }, stringType, nil - case *search.Expression_Signed: - return func(context.Context, interface{}) interface{} { return et.Signed }, signedType, nil - case *search.Expression_Unsigned: - return func(context.Context, interface{}) interface{} { return et.Unsigned }, unsignedType, nil - case *search.Expression_Double: - return func(context.Context, interface{}) interface{} { return et.Double }, doubleType, nil - case *search.Expression_Name: - return compileGetMember(ctx, et.Name, t) - case *search.Expression_And: - return compileBinaryBool(ctx, et.And, t, func(lhs, rhs bool) bool { return lhs && rhs }) - case *search.Expression_Or: - return compileBinaryBool(ctx, et.Or, t, func(lhs, rhs bool) bool { return lhs || rhs }) - case *search.Expression_Equal: - return compileEqual(ctx, et.Equal, t) - case *search.Expression_Greater: - return compileBinaryNumeric(ctx, et.Greater, t, - func(lhs, rhs int64) bool { return lhs > rhs }, - func(lhs, rhs uint64) bool { return lhs > rhs }, - func(lhs, rhs float64) bool { return lhs > rhs }, - ) - case *search.Expression_GreaterOrEqual: - return compileBinaryNumeric(ctx, et.GreaterOrEqual, t, - func(lhs, rhs int64) bool { return lhs >= rhs }, - func(lhs, rhs uint64) bool { return lhs >= rhs }, - func(lhs, rhs float64) bool { return lhs >= rhs }, - ) - case *search.Expression_Subscript: - return compileSubscript(ctx, et.Subscript, t) - case *search.Expression_Regex: - return compileRegex(ctx, et.Regex, t) - case *search.Expression_Member: - return compileMember(ctx, et.Member, t) - case *search.Expression_Not: - return compileNot(ctx, et.Not, t) - default: - return nil, boolType, log.Errf(ctx, nil, "Invalid expression %v", et) - } -} - -func compileBinaryBool(ctx context.Context, expr *search.Binary, t reflect.Type, test func(bool, bool) bool) (eval, reflect.Type, error) { - lhs, res, err := compileExpression(ctx, expr.Lhs, t) - if err != nil { - return nil, boolType, err - } - if res.Kind() != reflect.Bool { - return nil, boolType, log.Errf(ctx, nil, "lhs was not bool (%v)", res.Kind()) - } - rhs, res, err := compileExpression(ctx, expr.Rhs, t) - if err != nil { - return nil, boolType, err - } - if res.Kind() != reflect.Bool { - return nil, boolType, log.Errf(ctx, nil, "rhs was not bool (%v)", res.Kind()) - } - return func(ctx context.Context, value interface{}) interface{} { - return test(lhs(ctx, value).(bool), rhs(ctx, value).(bool)) - }, boolType, nil -} - -func compileEqual(ctx context.Context, expr *search.Binary, t reflect.Type) (eval, reflect.Type, error) { - lhs, lt, err := compileExpression(ctx, expr.Lhs, t) - if err != nil { - return nil, boolType, err - } - rhs, rt, err := compileExpression(ctx, expr.Rhs, t) - if err != nil { - return nil, boolType, err - } - switch { - case lt == rt: - return func(ctx context.Context, value interface{}) interface{} { - return reflect.DeepEqual(lhs(ctx, value), rhs(ctx, value)) - }, boolType, nil - case rt.Kind() == reflect.String: - return func(ctx context.Context, value interface{}) interface{} { - return reflect.DeepEqual(fmt.Sprint(lhs(ctx, value)), rhs(ctx, value)) - }, boolType, nil - case lt.Kind() == reflect.String: - return func(ctx context.Context, value interface{}) interface{} { - return reflect.DeepEqual(lhs(ctx, value), fmt.Sprint(rhs(ctx, value))) - }, boolType, nil - default: - return nil, boolType, log.Errf(ctx, nil, "Types to equal do not match (%v != %v)", lt, rt) - } -} - -func compileBinaryNumeric(ctx context.Context, expr *search.Binary, t reflect.Type, - testS func(int64, int64) bool, - testU func(uint64, uint64) bool, - testD func(float64, float64) bool, -) (eval, reflect.Type, error) { - lhs, lt, err := compileExpression(ctx, expr.Lhs, t) - if err != nil { - return nil, boolType, err - } - rhs, rt, err := compileExpression(ctx, expr.Rhs, t) - if err != nil { - return nil, boolType, err - } - if lt.AssignableTo(signedType) && rt.AssignableTo(signedType) { - return func(ctx context.Context, value interface{}) interface{} { - return testS(lhs(ctx, value).(int64), rhs(ctx, value).(int64)) - }, boolType, nil - } - if lt.AssignableTo(unsignedType) && rt.AssignableTo(unsignedType) { - return func(ctx context.Context, value interface{}) interface{} { - return testU(lhs(ctx, value).(uint64), rhs(ctx, value).(uint64)) - }, boolType, nil - } - if lt.AssignableTo(doubleType) && rt.AssignableTo(doubleType) { - return func(ctx context.Context, value interface{}) interface{} { - return testD(lhs(ctx, value).(float64), rhs(ctx, value).(float64)) - }, boolType, nil - } - return nil, boolType, log.Errf(ctx, nil, "no numeric comparison possible (%v with %v)", lt, rt) -} - -func compileNot(ctx context.Context, expr *search.Expression, t reflect.Type) (eval, reflect.Type, error) { - rhs, res, err := compileExpression(ctx, expr, t) - if err != nil { - return nil, boolType, err - } - if res.Kind() != reflect.Bool { - return nil, boolType, log.Errf(ctx, nil, "Not only applies to bool (%v)", res.Kind()) - } - return func(ctx context.Context, value interface{}) interface{} { - return !rhs(ctx, value).(bool) - }, boolType, nil -} - -func compileSubscript(ctx context.Context, expr *search.Subscript, t reflect.Type) (eval, reflect.Type, error) { - container, ct, err := compileExpression(ctx, expr.Container, t) - if err != nil { - return nil, boolType, err - } - key, kt, err := compileExpression(ctx, expr.Key, t) - if err != nil { - return nil, boolType, err - } - vt := ct.Elem() - switch ct.Kind() { - case reflect.Slice: - if !kt.AssignableTo(signedType) { - return nil, boolType, log.Errf(ctx, nil, "Slices must be indexed by int64 (%v)", kt) - } - zeroValue := reflect.Zero(vt).Interface() - return func(ctx context.Context, value interface{}) interface{} { - cv := reflect.ValueOf(container(ctx, value)) - index := (int)(key(ctx, value).(int64)) - if index >= cv.Len() { - return zeroValue - } - return cv.Index(index).Interface() - }, vt, nil - case reflect.Map: - if !kt.AssignableTo(ct.Key()) { - return nil, boolType, log.Errf(ctx, nil, "Map index type does not match (%v != %v)", kt, ct.Key()) - } - return func(ctx context.Context, value interface{}) interface{} { - return reflect.ValueOf(container(ctx, value)).MapIndex(reflect.ValueOf(key(ctx, value))).Interface() - }, vt, nil - default: - return nil, boolType, log.Errf(ctx, nil, "Can only subscript map or slice (%v)", ct) - } -} - -func compileRegex(ctx context.Context, expr *search.Regex, t reflect.Type) (eval, reflect.Type, error) { - val, vt, err := compileExpression(ctx, expr.Value, t) - if err != nil { - return nil, boolType, err - } - if vt.Kind() != reflect.String { - return nil, boolType, log.Errf(ctx, nil, "Regex only applies to string (%v)", vt) - } - re, err := regexp.Compile(expr.Pattern) - if err != nil { - return nil, boolType, err - } - return func(ctx context.Context, value interface{}) interface{} { - return re.MatchString(val(ctx, value).(string)) - }, boolType, nil -} - -func compileMember(ctx context.Context, expr *search.Member, t reflect.Type) (eval, reflect.Type, error) { - obj, ot, err := compileExpression(ctx, expr.Object, t) - if err != nil { - return nil, boolType, err - } - get, mt, err := compileGetMember(ctx, expr.Name, ot) - if err != nil { - return nil, boolType, err - } - return func(ctx context.Context, value interface{}) interface{} { - return get(ctx, obj(ctx, value)) - }, mt, nil -} - -func compileGetMember(ctx context.Context, name string, t reflect.Type) (eval, reflect.Type, error) { - wasPtr := t.Kind() == reflect.Ptr - if wasPtr { - t = t.Elem() - } - if t.Kind() != reflect.Struct { - return nil, boolType, log.Errf(ctx, nil, "Field access on non struct type (%v)", t) - } - field, found := t.FieldByName(name) - if !found { - return nil, boolType, log.Errf(ctx, nil, "No field '%v' found in %v", name, t) - } - if wasPtr { - return func(ctx context.Context, value interface{}) interface{} { - return reflect.ValueOf(value).Elem().FieldByIndex(field.Index).Interface() - }, field.Type, nil - } - return func(ctx context.Context, value interface{}) interface{} { - return reflect.ValueOf(value).FieldByIndex(field.Index).Interface() - }, field.Type, nil -} diff --git a/test/robot/search/query/BUILD.bazel b/test/robot/search/query/BUILD.bazel deleted file mode 100644 index 8cbc94075c..0000000000 --- a/test/robot/search/query/BUILD.bazel +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "builder.go", - "doc.go", - "expression.go", - "replace.go", - ], - importpath = "github.com/google/gapid/test/robot/search/query", - visibility = ["//visibility:public"], - deps = [ - "//test/robot/search:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - ], -) diff --git a/test/robot/search/query/builder.go b/test/robot/search/query/builder.go deleted file mode 100644 index db8a379c7b..0000000000 --- a/test/robot/search/query/builder.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package query - -import "github.com/google/gapid/test/robot/search" - -// Builder is the type used to allow fluent construction of search queries. -type Builder struct { - e *search.Expression -} - -// Expression creates a builder from a search expression. -func Expression(e *search.Expression) Builder { - return Builder{e: e} -} - -// Value creates a builder from a value. -// The type of expression will be inferred from the type of the value. -func Value(value interface{}) Builder { - return Expression(exprValue(value)) -} - -// Expression returns the content of the builder as a search expression. -func (b Builder) Expression() *search.Expression { - return b.e -} - -// Query returns the content of the builder as a completed search query. -func (b Builder) Query() *search.Query { - return &search.Query{Expression: b.Expression()} -} - -// Bool builds a boolean literal search expression. -func Bool(value bool) Builder { - return Expression(exprBool(value)) -} - -// String builds a string literal search expression. -func String(value string) Builder { - return Expression(exprString(value)) -} - -// Signed builds a signed integer literal search expression. -func Signed(value int64) Builder { - return Expression(exprSigned(value)) -} - -// Unsigned builds an unsigned integer literal search expression. -func Unsigned(value uint64) Builder { - return Expression(exprUnsigned(value)) -} - -// Double builds an floating point literal search expression. -func Double(value float64) Builder { - return Expression(exprDouble(value)) -} - -// Name builds a root name lookup search expression. -func Name(name string) Builder { - return Expression(exprName(name)) -} - -// And builds a search expression that is the "and" of the lhs and rhs. -func (lhs Builder) And(rhs Builder) Builder { - return Expression(exprAnd(lhs.Expression(), rhs.Expression())) -} - -// Or builds a search expression that is the "or" of the lhs and rhs. -func (lhs Builder) Or(rhs Builder) Builder { - return Expression(exprOr(lhs.Expression(), rhs.Expression())) -} - -// Equal builds a search expression that compares the lhs and rhs for equality. -func (lhs Builder) Equal(rhs Builder) Builder { - return Expression(exprEqual(lhs.Expression(), rhs.Expression())) -} - -// Less builds a search expression that tests whether the lhs is less than the rhs. -func (lhs Builder) Less(rhs Builder) Builder { - return Expression(exprLess(lhs.Expression(), rhs.Expression())) -} - -// LessOrEqual builds a search expression that tests whether the lhs is less than or equal to the rhs. -func (lhs Builder) LessOrEqual(rhs Builder) Builder { - return Expression(exprLessOrEqual(lhs.Expression(), rhs.Expression())) -} - -// Greater builds a search expression that tests whether the lhs is greater than the rhs. -func (lhs Builder) Greater(rhs Builder) Builder { - return Expression(exprGreater(lhs.Expression(), rhs.Expression())) -} - -// GreaterOrEqual builds a search expression that tests whether the lhs is greater than or equal to the rhs. -func (lhs Builder) GreaterOrEqual(rhs Builder) Builder { - return Expression(exprGreaterOrEqual(lhs.Expression(), rhs.Expression())) -} - -// Subscript builds a search expression that applies the key as a subscript to the value. -func (value Builder) Subscript(key Builder) Builder { - return Expression(exprSubscript(value.Expression(), key.Expression())) -} - -// Regex builds a search expression that tests whether value matches the supplied regex pattern. -func (value Builder) Regex(pattern string) Builder { - return Expression(exprRegex(value.Expression(), pattern)) -} - -// Member builds a search expression that looks up the named member of the object. -func (object Builder) Member(name string) Builder { - return Expression(exprMember(object.Expression(), name)) -} - -// Not builds a search expression that applies a boolean not to the supplied rhs. -func Not(rhs Builder) Builder { - return Expression(exprNot(rhs.Expression())) -} diff --git a/test/robot/search/query/doc.go b/test/robot/search/query/doc.go deleted file mode 100644 index 9eaaae3bfd..0000000000 --- a/test/robot/search/query/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package query contains helpful code for building structured search queries. -// The contents of this package are about making the query logic easier to read, -// by providing helpers for building the underlying search proto buffer expressions. -package query diff --git a/test/robot/search/query/expression.go b/test/robot/search/query/expression.go deleted file mode 100644 index 24a0cdc482..0000000000 --- a/test/robot/search/query/expression.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package query - -import "github.com/google/gapid/test/robot/search" - -func exprBool(value bool) *search.Expression { - return &search.Expression{Is: &search.Expression_Boolean{ - Boolean: value, - }} -} - -func exprString(value string) *search.Expression { - return &search.Expression{Is: &search.Expression_String_{ - String_: value, - }} -} - -func exprSigned(value int64) *search.Expression { - return &search.Expression{Is: &search.Expression_Signed{ - Signed: value, - }} -} - -func exprUnsigned(value uint64) *search.Expression { - return &search.Expression{Is: &search.Expression_Unsigned{ - Unsigned: value, - }} -} - -func exprDouble(value float64) *search.Expression { - return &search.Expression{Is: &search.Expression_Double{ - Double: value, - }} -} - -func exprName(name string) *search.Expression { - return &search.Expression{Is: &search.Expression_Name{ - Name: name, - }} -} - -func exprAnd(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_And{ - And: &search.Binary{ - Lhs: lhs, - Rhs: rhs, - }, - }} -} - -func exprOr(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Or{ - Or: &search.Binary{ - Lhs: lhs, - Rhs: rhs, - }, - }} -} - -func exprEqual(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Equal{ - Equal: &search.Binary{ - Lhs: lhs, - Rhs: rhs, - }, - }} -} - -func exprLess(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_GreaterOrEqual{ - GreaterOrEqual: &search.Binary{ - Lhs: rhs, - Rhs: lhs, - }, - }} -} - -func exprLessOrEqual(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Greater{ - Greater: &search.Binary{ - Lhs: rhs, - Rhs: lhs, - }, - }} -} - -func exprGreater(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Greater{ - Greater: &search.Binary{ - Lhs: lhs, - Rhs: rhs, - }, - }} -} - -func exprGreaterOrEqual(lhs, rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_GreaterOrEqual{ - GreaterOrEqual: &search.Binary{ - Lhs: lhs, - Rhs: rhs, - }, - }} -} - -func exprSubscript(value, key *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Subscript{ - Subscript: &search.Subscript{ - Container: value, - Key: key, - }, - }} -} - -func exprRegex(value *search.Expression, pattern string) *search.Expression { - return &search.Expression{Is: &search.Expression_Regex{ - Regex: &search.Regex{ - Value: value, - Pattern: pattern, - }, - }} -} - -func exprMember(object *search.Expression, name string) *search.Expression { - return &search.Expression{Is: &search.Expression_Member{ - Member: &search.Member{ - Object: object, - Name: name, - }, - }} -} - -func exprNot(rhs *search.Expression) *search.Expression { - return &search.Expression{Is: &search.Expression_Not{ - Not: rhs, - }} -} - -func exprValue(value interface{}) *search.Expression { - switch v := value.(type) { - case bool: - return exprBool(v) - case int: - return exprSigned((int64)(v)) - case int64: - return exprSigned(v) - case uint: - return exprUnsigned((uint64)(v)) - case uint64: - return exprUnsigned(v) - case float32: - return exprDouble((float64)(v)) - case float64: - return exprDouble(v) - case string: - return exprString(v) - case Builder: - return v.Expression() - case *search.Expression: - return v - default: - return exprName("*Invalid*") - } -} diff --git a/test/robot/search/query/replace.go b/test/robot/search/query/replace.go deleted file mode 100644 index 115aadfe42..0000000000 --- a/test/robot/search/query/replace.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package query - -import ( - "github.com/golang/protobuf/proto" - "github.com/google/gapid/test/robot/search" -) - -// Replace substitues expr for match in the expression tree. -func (b Builder) Replace(match Builder, expr Builder) Builder { - return Expression(replace(b.Expression(), match.Expression(), expr.Expression())) -} - -// Set is a small helper on top of Replace for the common case of identifier substitution. -// name is a top level identifier to replace, and Value(value) is the expression to replace it with. -func (b Builder) Set(name string, value interface{}) Builder { - return b.Replace(Name(name), Value(value)) -} - -// Using returns a function that when invoked returns a copy of b with Name(name) replace by Value(value). -// This is to make the common case of single value substitutions into precompiles queries easy. -// To use it -// var myQuery = script.MustCompile("Object.Name == $V").Using("$V") -// myService.Search(myQuery(nameToFind).Query()) -func (b Builder) Using(name string) func(interface{}) Builder { - return func(value interface{}) Builder { return b.Replace(Name(name), Value(value)) } -} - -func replace(s, m, r *search.Expression) *search.Expression { - if proto.Equal(s, m) { - return r - } - switch e := s.Is.(type) { - case *search.Expression_And: - return exprAnd(replace(e.And.Lhs, m, r), replace(e.And.Rhs, m, r)) - case *search.Expression_Or: - return exprOr(replace(e.Or.Lhs, m, r), replace(e.Or.Rhs, m, r)) - case *search.Expression_Equal: - return exprEqual(replace(e.Equal.Lhs, m, r), replace(e.Equal.Rhs, m, r)) - case *search.Expression_Greater: - return exprGreater(replace(e.Greater.Lhs, m, r), replace(e.Greater.Rhs, m, r)) - case *search.Expression_GreaterOrEqual: - return exprGreaterOrEqual(replace(e.GreaterOrEqual.Lhs, m, r), replace(e.GreaterOrEqual.Rhs, m, r)) - case *search.Expression_Subscript: - return exprSubscript(replace(e.Subscript.Container, m, r), replace(e.Subscript.Key, m, r)) - case *search.Expression_Regex: - return exprRegex(replace(e.Regex.Value, m, r), e.Regex.Pattern) - case *search.Expression_Member: - return exprMember(replace(e.Member.Object, m, r), e.Member.Name) - case *search.Expression_Not: - return exprNot(replace(e.Not, m, r)) - default: - return s - } -} diff --git a/test/robot/search/script/BUILD.bazel b/test/robot/search/script/BUILD.bazel deleted file mode 100644 index 8cc330ebbd..0000000000 --- a/test/robot/search/script/BUILD.bazel +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("//tools/build:rules.bzl", "lingo") - -lingo( - name = "lingo", - srcs = glob(["*.lingo"]), -) - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - ":lingo", # keep - ], - importpath = "github.com/google/gapid/test/robot/search/script", - visibility = ["//visibility:public"], - deps = [ - "//core/log:go_default_library", # keep - "//test/robot/lingo:go_default_library", # keep - "//test/robot/search/query:go_default_library", # keep - ], -) diff --git a/test/robot/search/script/constants.lingo b/test/robot/search/script/constants.lingo deleted file mode 100644 index ddb43dcf82..0000000000 --- a/test/robot/search/script/constants.lingo +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package script - -import ( - "regexp" - - "github.com/google/gapid/test/robot/lingo" -) - -type _ lingo.Scanner -type _ regexp.Regexp - -type ( - comment string - space string - special string - constant string -) - -const ( - whitespace = space(`[\t\f\r ]+`) - eol = space(`\n`) - - commentStart = comment("/*") - commentBody = comment(`[^/\*]*`) - commentBodyStep = comment(`[/\*]`) - commentEnd = comment("*/") - commentLine = comment("//") - commentToEOL = comment(`[^\n]*`) - - identifier = constant(`[_\pL$][_\pL\pN]*`) - intDigits = constant(`[0-9]+`) - hexDigits = constant(`0x[0-9a-fA-F]+`) - floatDigits = constant(`\pN+\.\pN+([eE][-+]?\pN+)?`) - stringBody = constant(`[^"]*`) - boolFalse = constant("false") - boolTrue = constant("true") - - quote = special('"') - opAnd = special("&&") - opEqual = special("==") - opGreater = special('>') - opGreaterOrEqual = special(">=") - opLess = special('<') - opLessOrEqual = special("<=") - opMember = special('.') - opNot = special('!') - opNotEqual = special("!=") - opOr = special("||") - opRegex = special("?=") - - keywordAnd = special("and") - keywordIs = special("is") - keywordNot = special("not") - keywordOr = special("or") - - opGroupStart = special('(') - opGroupEnd = special(')') - opIndexStart = special('[') - opIndexEnd = special(']') -) diff --git a/test/robot/search/script/doc.go b/test/robot/search/script/doc.go deleted file mode 100644 index 323d03f8d3..0000000000 --- a/test/robot/search/script/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package script provides a fairly terse programming language for expressing -// search queries as strings. -// This is much more compact and easy to read than the full structured form. -// It's intended use is for places where you want a user to be able to type a query -// in a fairly natural language. Programmatic uses should prefer using the query -// package directly. -package script diff --git a/test/robot/search/script/expression.lingo b/test/robot/search/script/expression.lingo deleted file mode 100644 index aacde00647..0000000000 --- a/test/robot/search/script/expression.lingo +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package script - -import ( - "github.com/google/gapid/test/robot/lingo" - "github.com/google/gapid/test/robot/search/query" -) - -func expression(s *lingo.Scanner) (query.Builder, error) { - if e, err := binaryOr(s); err == nil { - return e, nil - } - return query.Bool(false), s.Error(nil, "Expected expression") -} - -func binaryOr(s *lingo.Scanner) (query.Builder, error) { - lhs := binaryAnd(s) - if opOr(s) || keywordOr(s) { - return lhs.Or(binaryOr(s)), nil - } - return lhs, nil -} - -func binaryAnd(s *lingo.Scanner) (query.Builder, error) { - lhs := binaryEqual(s) - if opAnd(s) || keywordAnd(s) { - return lhs.And(binaryAnd(s)), nil - } - return lhs, nil -} - -func binaryEqual(s *lingo.Scanner) (query.Builder, error) { - lhs := binaryCompare(s) - if opEqual(s) || keywordIs(s) { - return lhs.Equal(binaryEqual(s)), nil - } - if opNotEqual(s) { - return query.Not(lhs.Equal(binaryEqual(s))), nil - } - if opRegex(s) { - return lhs.Regex(string(string_(s))), nil - } - return lhs, nil -} - -func binaryCompare(s *lingo.Scanner) (query.Builder, error) { - lhs := extendExpression(s) - if opLess(s) { - return lhs.Less(binaryCompare(s)), nil - } - if opLessOrEqual(s) { - return lhs.LessOrEqual(binaryCompare(s)), nil - } - if opGreaterOrEqual(s) { - return lhs.GreaterOrEqual(binaryCompare(s)), nil - } - if opGreater(s) { - return lhs.Greater(binaryCompare(s)), nil - } - return lhs, nil -} - -func extendExpression(s *lingo.Scanner) (query.Builder, error) { - expr := entity(s) - for { - if i, err := indirect(s, expr); err == nil { - expr = i - } else { - return expr, nil - } - } -} - -func indirect(s *lingo.Scanner, expr query.Builder) (query.Builder, error) { - if s, err := subscript(s, expr); err == nil { - return s, nil - } - if m, err := member(s, expr); err == nil { - return m, nil - } - return query.Bool(false), s.Error(nil, "Expected indirection") -} - -func entity(s *lingo.Scanner) (query.Builder, error) { - if opNot(s) || keywordNot(s) { - return query.Not(expression(s)), nil - } - if value, err := parenthesised(s); err == nil { - return value, err - } - if value, err := literal(s); err == nil { - return value, err - } - if v, err := identifier(s); err == nil { - return query.Name(string(v)), nil - } - return query.Bool(false), s.Error(nil, "Expected entity") -} - -func parenthesised(s *lingo.Scanner) (query.Builder, error) { - opGroupStart(s) - value := expression(s) - opGroupEnd(s) - return value, nil -} - -func subscript(s *lingo.Scanner, value query.Builder) (query.Builder, error) { - opIndexStart(s) - key := expression(s) - opIndexEnd(s) - return value.Subscript(key), nil - -} - -func member(s *lingo.Scanner, value query.Builder) (query.Builder, error) { - opMember(s) - return value.Member(string(identifier(s))), nil -} diff --git a/test/robot/search/script/literal.lingo b/test/robot/search/script/literal.lingo deleted file mode 100644 index ed9164d559..0000000000 --- a/test/robot/search/script/literal.lingo +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package script - -import ( - "strconv" - - "github.com/google/gapid/test/robot/lingo" - "github.com/google/gapid/test/robot/search/query" -) - -func literal(s *lingo.Scanner) (query.Builder, error) { - if _, err := boolTrue(s); err == nil { - return query.Bool(true), nil - } - if _, err := boolFalse(s); err == nil { - return query.Bool(false), nil - } - if v, err := string_(s); err == nil { - return query.String(string(v)), nil - } - if v, err := floatDigits(s); err == nil { - if f, err := strconv.ParseFloat(string(v), 64); err == nil { - return query.Double(f), nil - } - } - if v, err := hexDigits(s); err == nil { - if u, err := strconv.ParseUint(string(v), 0, 64); err == nil { - return query.Unsigned(u), nil - } - } - if v, err := intDigits(s); err == nil { - if i, err := strconv.ParseInt(string(v), 0, 64); err == nil { - return query.Signed(i), nil - } - } - return query.Bool(false), s.Error(nil, "Expected literal") -} - -func string_(s *lingo.Scanner) (constant, error) { - quote(s) - // TODO: handle escape sequences - value := stringBody(s) - quote(s) - return value, nil -} diff --git a/test/robot/search/script/parse.lingo b/test/robot/search/script/parse.lingo deleted file mode 100644 index 5bd6644f7b..0000000000 --- a/test/robot/search/script/parse.lingo +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package script - -import ( - "context" - - "github.com/google/gapid/test/robot/search/query" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/lingo" -) - -// Parse takes a string containing a search expression and returns the Query object representation of it. -// If the string is not syntactically valid, you will get an incomplete query object and an error. -func Parse(ctx context.Context, input string) (value query.Builder, err error) { - if input == "" { - return query.Bool(true), nil - } - defer func() { - v := recover() - if v == nil { - return - } - scanErr := lingo.WasScannerError(v) - if scanErr == nil { - panic(v) - } - err = scanErr - }() - s := lingo.NewStringScanner(ctx, "query", input, nil) - s.SetSkip(skip) - value = expression(s) - if !s.EOF() { - return query.Bool(false), log.Err(ctx, nil, "Input not consumed") - } - return value, nil -} - -// MustParse wraps Parse and panics on failure. -// It is intended for static initializers, which is why it also does not take a context. -func MustParse(input string) query.Builder { - b, err := Parse(context.Background(), input) - if err != nil { - panic(err) - } - return b -} - -func skip(s *lingo.Scanner) { - for { - switch { - case whitespace(s): - case eol(s): - case commentLine(s): - _, _ = commentToEOL(s) - case commentStart(s): - blockComment(s) - default: - return - } - } -} - -func blockComment(s *lingo.Scanner) { - for { - _, _ = commentBody(s) - switch { - case commentLine(s): - _, _ = commentToEOL(s) - case commentStart(s): - commentBody(s) - case commentEnd(s): - return - default: - _, _ = commentBodyStep(s) - } - } -} diff --git a/test/robot/search/search.proto b/test/robot/search/search.proto deleted file mode 100644 index e1c64c3fa5..0000000000 --- a/test/robot/search/search.proto +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package search; -option go_package = "github.com/google/gapid/test/robot/search"; - -message Binary { - Expression lhs = 1; - Expression rhs = 2; -} - -message Subscript { - Expression container = 1; - Expression key = 2; -} - -message Regex { - Expression value = 1; - string pattern = 2; -} - -message Member { - Expression object = 1; - string name = 2; -} - -message Expression { - oneof Is { - bool Boolean = 1; - string String = 2; - int64 Signed = 3; - uint64 Unsigned = 4; - double Double = 5; - string Name = 6; - Binary And = 7; - Binary Or = 8; - Binary Equal = 9; - Binary Greater = 10; - Binary GreaterOrEqual = 11; - Subscript Subscript = 12; - Regex Regex = 13; - Member Member = 14; - Expression Not = 15; - } -} - -// Query represents the arguments to a search. -message Query { - // Query is the test to perform - Expression expression = 1; - // Monitor says to not terminate the search but keep monitoring for new - // entries - bool monitor = 2; -} diff --git a/test/robot/stash/BUILD.bazel b/test/robot/stash/BUILD.bazel deleted file mode 100644 index fe94020896..0000000000 --- a/test/robot/stash/BUILD.bazel +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "factory.go", - "stash.go", - "upload.go", - ], - embed = [":stash_go_proto"], - importpath = "github.com/google/gapid/test/robot/stash", - visibility = ["//visibility:public"], - deps = [ - "//core/fault:go_default_library", - "//core/log:go_default_library", - "//core/os/file:go_default_library", - "//test/robot/search:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@com_github_pkg_errors//:go_default_library", - ], -) - -proto_library( - name = "stash_proto", - srcs = ["stash.proto"], - visibility = ["//visibility:public"], - deps = ["@com_google_protobuf//:timestamp_proto"], -) - -go_proto_library( - name = "stash_go_proto", - importpath = "github.com/google/gapid/test/robot/stash", - proto = ":stash_proto", - visibility = ["//visibility:public"], -) diff --git a/test/robot/stash/client.go b/test/robot/stash/client.go deleted file mode 100644 index d0636f4f6e..0000000000 --- a/test/robot/stash/client.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package stash - -import ( - "context" - "io" - "os" - - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" -) - -type ( - // Client is a wrapper over a Service to provice extended client functionality. - Client struct { - Service - } - - // Uploadable is the interface used by the UploadStream helper. - // It is a standard io reader with the ability to reset to the start. - Uploadable interface { - io.Reader - Reset() error - } -) - -// UploadStream is a helper used to upload a stream to the stash. -// It will return an error if the upload fails, otherwise it will return the stash -// id for the bytes. -func (c *Client) UploadStream(ctx context.Context, info Upload, r Uploadable) (string, error) { - return uploadStream(ctx, c, info, r) -} - -// UploadSeekable is a helper used to upload a single seekable stream. -// It will return an error if either the stream cannot be read, or the upload fails, otherwise -// it will return the stash id for the file. -func (c *Client) UploadSeekable(ctx context.Context, info Upload, r io.ReadSeeker) (string, error) { - return uploadStream(ctx, c, info, seekadapter{r}) -} - -// UploadBytes is a helper used to upload a byte array. -// It will return an error if the upload fails, otherwise it will return the stash id for the file. -func (c *Client) UploadBytes(ctx context.Context, info Upload, data []byte) (string, error) { - return uploadStream(ctx, c, info, &bytesAdapter{data: data}) -} - -// UploadString is a helper used to upload a string. -// It will return an error if the upload fails, otherwise it will return the stash id for the file. -func (c *Client) UploadString(ctx context.Context, info Upload, content string) (string, error) { - return uploadStream(ctx, c, info, &bytesAdapter{data: ([]byte)(content)}) -} - -// UploadFile is a helper used to upload a single file to the stash. -// It will return an error if either the file cannot be read, or the upload fails, otherwise -// it will return the stash id for the file. -func (c *Client) UploadFile(ctx context.Context, filename file.Path) (string, error) { - file, err := os.Open(filename.System()) - if err != nil { - return "", err - } - defer file.Close() - stat, _ := file.Stat() - info := Upload{ - Name: []string{filename.Basename()}, - Executable: stat.Mode()&0111 != 0, - } - return uploadStream(ctx, c, info, seekadapter{file}) -} - -// GetFile retrieves the data for an entity in the given Store and -// saves it to a file. -func (c *Client) GetFile(ctx context.Context, id string, filename file.Path) error { - entity, err := c.Lookup(ctx, id) - if err != nil || entity == nil { - return nil - } - - if err := file.Mkdir(filename.Parent()); err != nil { - return log.Err(ctx, err, "file.Path.Mkdir failed") - } - - mode := os.FileMode(0644) - if entity.Upload.Executable { - mode = 0755 - } - f, err := os.OpenFile(filename.System(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) - if err != nil { - return err - } - defer f.Close() - r, err := c.Open(ctx, id) - if err != nil { - return err - } - if _, err := io.Copy(f, r); err != nil { - return log.Err(ctx, err, "io.Copy failed") - } - return nil -} diff --git a/test/robot/stash/doc.go b/test/robot/stash/doc.go deleted file mode 100644 index fa73aa297c..0000000000 --- a/test/robot/stash/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package stash provides the defenition of a service that stores immutable blobs of data -// keyed by id, and the client helpers for dealing with that service. -package stash diff --git a/test/robot/stash/factory.go b/test/robot/stash/factory.go deleted file mode 100644 index 0129164a03..0000000000 --- a/test/robot/stash/factory.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package stash - -import ( - "context" - "net/url" - "runtime" - "strings" - - "github.com/google/gapid/core/log" -) - -// Builder is the function type that opens a stash from a url. -type Builder func(context.Context, *url.URL) (*Client, error) - -var schemeMap = map[string]Builder{} - -// ReigsterHandler adds a new scheme handler to the factory. -func RegisterHandler(scheme string, builder Builder) { - //TODO: complain about duplicates? - schemeMap[scheme] = builder -} - -// Dial returns a new client for the given url. -func Dial(ctx context.Context, location *url.URL) (*Client, error) { - ctx = log.V{"Store": location.Path}.Bind(ctx) - if location.Scheme == "" { - switch { - case location.Host != "": - location.Scheme = "grpc" - case location.Path == "": - location.Scheme = "memory" - default: - location.Scheme = "file" - } - } - if location.Scheme == "file" { - if runtime.GOOS == "windows" && strings.IndexByte(location.Path, ':') == 2 { - // windows file urls have an extra slash before the volume label that needs to be removed - // see https://github.com/golang/go/issues/6027#issuecomment-66083310 - location.Path = strings.TrimPrefix(location.Path, "/") - } - } - builder, found := schemeMap[location.Scheme] - if !found { - return nil, log.Errf(ctx, nil, "Invalid stash scheme") - } - return builder(ctx, location) -} diff --git a/test/robot/stash/grpc/BUILD.bazel b/test/robot/stash/grpc/BUILD.bazel deleted file mode 100644 index 734f76b77e..0000000000 --- a/test/robot/stash/grpc/BUILD.bazel +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "server.go", - ], - embed = [":grpc_go_proto"], - importpath = "github.com/google/gapid/test/robot/stash/grpc", - visibility = ["//visibility:public"], - deps = [ - "//core/event:go_default_library", - "//core/event/task:go_default_library", - "//core/fault:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/file:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/script:go_default_library", - "//test/robot/stash:go_default_library", - "@com_github_pkg_errors//:go_default_library", - "@org_golang_google_grpc//:go_default_library", - ], -) - -proto_library( - name = "grpc_proto", - srcs = ["stash.proto"], - visibility = ["//visibility:public"], - deps = [ - "//test/robot/search:search_proto", - "//test/robot/stash:stash_proto", - ], -) - -go_proto_library( - name = "grpc_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/stash/grpc", - proto = ":grpc_proto", - visibility = ["//visibility:public"], - deps = [ - "//test/robot/search:go_default_library", - "//test/robot/stash:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["grpc_test.go"], - embed = [":go_default_library"], - deps = [ - "//core/assert:go_default_library", - "//core/fault:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//test/robot/stash:go_default_library", - "//test/robot/stash/local:go_default_library", - "@org_golang_google_grpc//:go_default_library", - ], -) diff --git a/test/robot/stash/grpc/client.go b/test/robot/stash/grpc/client.go deleted file mode 100644 index 908ef692fa..0000000000 --- a/test/robot/stash/grpc/client.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpc - -import ( - "context" - "io" - "io/ioutil" - "net/url" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/fault" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/script" - "github.com/google/gapid/test/robot/stash" - "github.com/pkg/errors" - "google.golang.org/grpc" -) - -const ( - uploadLimit = 1 * 1024 * 1024 - downloadLimit = uploadLimit - - ErrInvalidOffset = fault.Const("invalid seek offset") -) - -type ( - remoteStore struct { - client ServiceClient - temp file.Path - } - - connectedStore struct { - remoteStore - conn *grpc.ClientConn - } -) - -func init() { - stash.RegisterHandler("grpc", Dial) -} - -// Connect returns a remote grpc backed implementation of stash.Service using the supplied connection. -func Connect(ctx context.Context, conn *grpc.ClientConn) (*stash.Client, error) { - remote, err := connect(ctx, conn) - if err != nil { - return nil, err - } - return &stash.Client{Service: &remote}, nil -} - -// MustConnect returns a remote grpc backed implementation of a stash client using the supplied connection. -// It panics if the connection fails for any reason. -func MustConnect(ctx context.Context, conn *grpc.ClientConn) *stash.Client { - s, err := Connect(ctx, conn) - if err != nil { - panic(err) - } - return s -} - -// Dial returns a remote grpc backed stash client from a url. -func Dial(ctx context.Context, location *url.URL) (*stash.Client, error) { - if location.Host == "" { - return nil, log.Err(ctx, nil, "Host not supported for memory servers") - } - if location.Path != "" { - return nil, log.Err(ctx, nil, "Path not supported for grpc servers") - } - conn, err := grpcutil.Dial(ctx, location.Host, grpc.WithInsecure()) - if err != nil { - return nil, err - } - remote, err := connect(ctx, conn) - if err != nil { - return nil, err - } - return &stash.Client{Service: &connectedStore{ - remoteStore: remote, - conn: conn, - }}, nil -} - -func connect(ctx context.Context, conn *grpc.ClientConn) (remoteStore, error) { - tmp, err := ioutil.TempDir("", "stash_") - if err != nil { - return remoteStore{}, err - } - return remoteStore{ - client: NewServiceClient(conn), - temp: file.Abs(tmp), - }, nil -} - -func (s *remoteStore) Close() {} -func (s *connectedStore) Close() { s.conn.Close() } - -var uploadQuery = script.MustParse("Upload.Id == $").Using("$") - -func (s *remoteStore) Lookup(ctx context.Context, id string) (*stash.Entity, error) { - query := uploadQuery(id).Query() - stream, err := s.client.Search(ctx, query) - if err != nil { - return nil, err - } - entity, err := stream.Recv() - if errors.Cause(err) == io.EOF { - if entity == nil { - err = stash.ErrEntityNotFound - } else { - err = nil - } - } - return entity, err -} - -func (s *remoteStore) Search(ctx context.Context, query *search.Query, handler stash.EntityHandler) error { - stream, err := s.client.Search(ctx, query) - if err != nil { - return err - } - p := grpcutil.ToProducer(stream) - return event.Feed(ctx, event.AsHandler(ctx, handler), p) -} - -func (s *remoteStore) Open(ctx context.Context, id string) (io.ReadSeeker, error) { - e, err := s.Lookup(ctx, id) - if err != nil { - return nil, log.Err(ctx, err, "entity lookup") - } - if e.Status != stash.Status_Present { - return nil, log.Err(ctx, err, "entity not ready") - } - return &remoteStoreReadSeeker{ctx: ctx, id: id, len: e.GetLength(), s: s}, nil -} - -type remoteStoreReadSeeker struct { - ctx context.Context - s *remoteStore - id string - len int64 - - offset int64 - cancel context.CancelFunc - stream Service_DownloadClient - - data []byte - recvbuf []byte -} - -func (r *remoteStoreReadSeeker) Seek(offset int64, whence int) (int64, error) { - var newOffset int64 - switch whence { - case io.SeekStart: - newOffset = offset - case io.SeekCurrent: - newOffset = r.offset + offset - case io.SeekEnd: - newOffset = r.len + offset - } - - if newOffset < 0 { - return 0, ErrInvalidOffset - } - - delta := newOffset - r.offset - bufoffset := int64(len(r.recvbuf) - len(r.data)) - if 0 < delta && delta < int64(len(r.data)) { - r.data = r.data[delta:] - } else if -bufoffset < delta && delta < 0 { - r.data = r.recvbuf[int(bufoffset+delta):] - } else if delta != 0 { - if r.cancel != nil { - r.cancel() - } - r.stream = nil - r.data = nil - r.recvbuf = nil - } - - r.offset = newOffset - return newOffset, nil -} - -func (r *remoteStoreReadSeeker) Read(b []byte) (int, error) { - for len(r.data) == 0 { - if r.stream == nil { - ctx, cancel := context.WithCancel(r.ctx) - stream, err := r.s.client.Download(ctx, &DownloadRequest{Id: r.id, Offset: uint64(r.offset)}) - r.cancel = cancel - r.stream = stream - if err != nil { - return 0, log.Err(r.ctx, err, "Remote store download") - } - } - - chunk, err := r.stream.Recv() - if err != nil { - return 0, err - } - r.data = chunk.Data - r.recvbuf = r.data - } - n := copy(b, r.data) - if n == len(r.data) { - r.data = nil - } else { - r.data = r.data[n:] - } - r.offset += int64(n) - return n, nil -} - -func (s *remoteStore) Read(ctx context.Context, id string) ([]byte, error) { - r, err := s.Open(ctx, id) - if err != nil { - return nil, err - } - return ioutil.ReadAll(r) -} - -func (s *remoteStore) Create(ctx context.Context, info *stash.Upload) (io.WriteCloser, error) { - stream, err := s.client.Upload(ctx) - if err != nil { - return nil, log.Err(ctx, err, "Remote store upload start") - } - if err := stream.Send(&UploadChunk{Of: &UploadChunk_Upload{Upload: info}}); err != nil { - return nil, log.Err(ctx, err, "Remote store upload header") - } - return &remoteStoreWriter{stream: stream}, nil -} - -type remoteStoreWriter struct { - stream Service_UploadClient -} - -func (w *remoteStoreWriter) Write(b []byte) (int, error) { - n := 0 - for len(b) > 0 { - data := b - if len(b) > uploadLimit { - data = b[:uploadLimit] - b = b[uploadLimit:] - } else { - b = nil - } - err := w.stream.Send(&UploadChunk{Of: &UploadChunk_Data{Data: data}}) - if err != nil { - return 0, err - } - n += len(data) - } - return n, nil -} - -func (w *remoteStoreWriter) Close() error { - // Use CloseAndRecv() to block until the server acknowledges the close. - // CloseSend() would return without waiting for the server to complete the - // call. - _, err := w.stream.CloseAndRecv() - return err -} - -func (s *remoteStore) Upload(ctx context.Context, info *stash.Upload, reader io.Reader) error { - stream, err := s.client.Upload(ctx) - if err != nil { - return log.Err(ctx, err, "Remote store upload") - } - buf := make([]byte, uploadLimit) - chunk := &UploadChunk{ - Of: &UploadChunk_Upload{Upload: info}, - } - for { - err = stream.Send(chunk) - if err != nil { - return log.Err(ctx, err, "Remote store upload") - } - n, err := reader.Read(buf) - if errors.Cause(err) == io.EOF { - stream.CloseSend() - return nil - } - if err != nil { - return log.Err(ctx, err, "Data read") - } - chunk.Of = &UploadChunk_Data{Data: buf[:n]} - } -} diff --git a/test/robot/stash/grpc/doc.go b/test/robot/stash/grpc/doc.go deleted file mode 100644 index 20f594e81f..0000000000 --- a/test/robot/stash/grpc/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package grpc provides the client and server support for communicating -// with a remote stash using grpc. -package grpc diff --git a/test/robot/stash/grpc/grpc_test.go b/test/robot/stash/grpc/grpc_test.go deleted file mode 100644 index d822d4e7b5..0000000000 --- a/test/robot/stash/grpc/grpc_test.go +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpc_test - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "io/ioutil" - "math/rand" - "net" - "testing" - "time" - - "github.com/google/gapid/core/assert" - "github.com/google/gapid/core/fault" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/stash" - stashgrpc "github.com/google/gapid/test/robot/stash/grpc" - "github.com/google/gapid/test/robot/stash/local" - "google.golang.org/grpc" -) - -type data struct { - id string - bytes []byte -} - -func checkReadFromStash(ctx context.Context, assert assert.Manager, rnd *rand.Rand, s *stash.Client, exp []data) { - for _, expected := range exp { - e, err := s.Lookup(ctx, expected.id) - assert.For("lookup err").ThatError(err).Succeeded() - assert.For("lookup e").That(e).IsNotNil() - assert.For("lookup length").That(e.Length).Equals(int64(len(expected.bytes))) - - rs, err := s.Open(ctx, expected.id) - assert.For("open").ThatError(err).Succeeded() - - data, err := ioutil.ReadAll(rs) - assert.For("readall").ThatError(err).Succeeded() - assert.For("readall").ThatSlice(data).Equals(expected.bytes) - - data, err = readInRandomOrder(rnd, rs, 60, 3) - assert.For("read random").ThatError(err).Succeeded() - assert.For("read random").ThatSlice(data).Equals(expected.bytes) - - data, err = s.Read(ctx, expected.id) - assert.For("stash.Read").ThatError(err).Succeeded() - assert.For("stash.Read").ThatSlice(data).Equals(expected.bytes) - } -} - -func uploadRandomDataToStash(ctx context.Context, assert assert.Manager, r *rand.Rand, s *stash.Client, lens []int) []data { - out := make([]data, len(lens)) - for i, ln := range lens { - bytes := randomBytes(r, ln) - id, err := s.UploadBytes(ctx, stash.Upload{Name: []string{fmt.Sprintf("%d.bin", i)}, Type: []string{"application/binary"}}, bytes) - assert.For("upload").ThatError(err).Succeeded() - out[i] = data{id, bytes} - } - return out -} - -func TestMemoryAndGrpcStash(t *testing.T) { - assert := assert.To(t) - ctx := log.Testing(t) - r := rand.New(rand.NewSource(12345)) - - memStash := local.NewMemoryService() - testData := uploadRandomDataToStash(ctx, assert, r, memStash, []int{10, 100, 100, 1, 100000, 100000, 0}) - assert.For("test data length").ThatInteger(len(testData)).IsAtLeast(1) - checkReadFromStash(ctx, assert, r, memStash, testData) - - var srv *grpc.Server - go grpcutil.ServeWithListener( - ctx, - grpcutil.NewPipeListener("pipe:stashgrpc"), - func(ctx context.Context, listener net.Listener, server *grpc.Server) error { - srv = server - return stashgrpc.Serve(ctx, server, memStash) - }, - ) - - ok := fault.Const("ok") - err := grpcutil.Client(ctx, "pipe:stashgrpc", func(ctx context.Context, cc *grpc.ClientConn) error { - sc := stashgrpc.MustConnect(ctx, cc) - // Make sure the in-memory stash is correctly exposed. - checkReadFromStash(ctx, assert, r, sc, testData) - // Make sure upload works through GRPC as well. - testData = uploadRandomDataToStash(ctx, assert, r, sc, []int{17}) - checkReadFromStash(ctx, assert, r, sc, testData) - return ok - }, grpc.WithDialer(grpcutil.GetDialer(ctx)), grpc.WithTimeout(1*time.Second), grpc.WithInsecure()) - assert.For("").ThatError(err).Equals(ok) - - srv.GracefulStop() -} - -func randomBytes(r *rand.Rand, length int) []byte { - p := make([]byte, length) - r.Read(p) - return p -} - -func TestReadInRandomOrder(t *testing.T) { - assert := assert.To(t) - r := rand.New(rand.NewSource(12345)) - - for _, c := range []struct { - length int - sections int - maxConsecutive int - }{ - {1000, 40, 5}, - {1000, 1, 1}, - {1000, 1, 30}, - {1000, 40, 1}, - {1, 1, 1}, - } { - data := randomBytes(r, c.length) - got, err := readInRandomOrder(r, bytes.NewReader(data), c.sections, c.maxConsecutive) - assert.For("read random").ThatError(err).Succeeded() - assert.For("read random").ThatSlice(got).Equals(data) - } -} - -// readInRandom order exercises an io.ReadSeeker by splitting it up in sections which are -// read in random order. Within a section, several consecutive reads may be performed. -// All types of seeking are used. -func readInRandomOrder(r *rand.Rand, rs io.ReadSeeker, sections int, maxConsecutiveReads int) ([]byte, error) { - length, err := rs.Seek(0, io.SeekEnd) - if err != nil { - return nil, err - } - var pos int64 = length - - data := make([]byte, length) - - for _, s := range randomSections(r, int(length), sections, maxConsecutiveReads) { - switch r.Intn(3) { - case 0: - pos, err = rs.Seek(s.offset, io.SeekStart) - case 1: - pos, err = rs.Seek(s.offset-length, io.SeekEnd) - case 2: - pos, err = rs.Seek(s.offset-pos, io.SeekCurrent) - } - if err != nil { - return nil, err - } - if pos != s.offset { - return nil, errors.New("Incorrect offset returned") - } - for _, rd := range s.reads { - n, err := io.ReadAtLeast(rs, data[int(pos):int(pos)+rd], rd) - if err != nil { - return nil, err - } - if n != rd { - return nil, fmt.Errorf("Expected %d bytes to be read, got %d", rd, n) - } - pos += int64(n) - } - } - return data, nil -} - -type readSection struct { - offset int64 // absolute section offset - reads []int // lengths of consecutive reads within section -} - -func randomSections(r *rand.Rand, length int, n int, maxReadsPerSection int) []readSection { - if length == 0 { - return []readSection{{0, []int{0}}} - } - min := func(a, b int) int { - if a < b { - return a - } - return b - } - sections := make([]readSection, n) - p := r.Perm(n) - n = min(n, length) - ch := randomChunks(r, length, n) - offset := 0 - for i := 0; i < n; i++ { - sections[p[i]] = readSection{ - offset: int64(offset), - reads: randomChunks(r, ch[i], min(ch[i], 1+r.Intn(maxReadsPerSection))), - } - offset += ch[i] - } - return sections -} - -func randomChunks(r *rand.Rand, length int, n int) []int { - chunks := make([]int, n) - - sum := 0 - for i := 0; i < n; i++ { - sz := r.Intn(length / n) - chunks[i] = sz - sum += sz - } - delta := (length - sum) / n - for i := 0; i < len(chunks); i++ { - chunks[i] += delta - sum += delta - } - chunks[r.Intn(len(chunks))] += (length - sum) - return chunks -} diff --git a/test/robot/stash/grpc/server.go b/test/robot/stash/grpc/server.go deleted file mode 100644 index c5bd8b6a7c..0000000000 --- a/test/robot/stash/grpc/server.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package grpc - -import ( - "context" - "io" - - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/stash" - "github.com/pkg/errors" - "google.golang.org/grpc" -) - -type storeServer struct { - service stash.Service -} - -// Serve wraps a store in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, service stash.Service) error { - RegisterServiceServer(grpcServer, &storeServer{service: service}) - return nil -} - -// Search scans the underlying store for matching entities. -// See ServiceServer for more information. -func (s *storeServer) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.service.Search(ctx, query, func(ctx context.Context, e *stash.Entity) error { - return stream.Send(e) - }) -} - -type uploader struct { - w io.WriteCloser -} - -func (u *uploader) Open(ctx context.Context, service stash.Service, upload *stash.Upload) error { - u.Close(ctx) - w, err := service.Create(ctx, upload) - if err != nil { - return log.Err(ctx, err, "Opening upload") - } - u.w = w - return nil -} - -func (u *uploader) Write(ctx context.Context, data []byte) error { - if _, err := u.w.Write(data); err != nil { - return log.Err(ctx, err, "Appending upload") - } - return nil -} - -func (u *uploader) Close(ctx context.Context) { - if u.w == nil { - return - } - u.w.Close() -} - -// Upload adds entities to the underlying store. -// See ServiceServer for more information. -func (s *storeServer) Upload(stream Service_UploadServer) error { - ctx := stream.Context() - u := &uploader{} - defer u.Close(ctx) - for { - chunk, err := stream.Recv() - switch { - case errors.Cause(err) == io.EOF: - return stream.SendAndClose(&UploadResponse{}) - case err != nil: - return err - default: - switch c := chunk.Of.(type) { - case *UploadChunk_Upload: - u.Open(ctx, s.service, c.Upload) - case *UploadChunk_Data: - u.Write(ctx, c.Data) - default: - return log.Err(ctx, nil, "Unknown upload chunk type") - } - } - } -} - -// Download fetches entities from the underlying store. -// See ServiceServer for more information. -func (s *storeServer) Download(request *DownloadRequest, stream Service_DownloadServer) error { - ctx := stream.Context() - readSeeker, err := s.service.Open(ctx, request.Id) - if err != nil { - return log.Err(ctx, err, "Entity open") - } - - if request.Offset > 0 { - if _, err := readSeeker.Seek(int64(request.Offset), io.SeekStart); err != nil { - return log.Err(ctx, err, "Seek") - } - } - - var reader io.Reader = readSeeker - bufSize := downloadLimit - if request.Length > 0 { - reader = io.LimitReader(readSeeker, int64(request.Length)) - if int(request.Length) < bufSize { - bufSize = int(request.Length) - } - } - - buf := make([]byte, bufSize) - chunk := &DownloadChunk{} - for { - if task.Stopped(ctx) { - return nil - } - - n, err := reader.Read(buf) - if errors.Cause(err) == io.EOF { - return nil - } - if err != nil { - return log.Err(ctx, err, "Data read") - } - chunk.Data = buf[:n] - err = stream.Send(chunk) - if err != nil { - return log.Err(ctx, err, "Stash download chunk") - } - } -} diff --git a/test/robot/stash/grpc/stash.proto b/test/robot/stash/grpc/stash.proto deleted file mode 100644 index 6803244028..0000000000 --- a/test/robot/stash/grpc/stash.proto +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package grpc; -option go_package = "github.com/google/gapid/test/robot/stash/grpc"; - -import "test/robot/stash/stash.proto"; -import "test/robot/search/search.proto"; - -// UploadChunk represents a chunk of data to upload a new entity to the stash. -// The first entity in an upload chunk stream must be an Upload entry. -// An Upload entry closes the previous Upload if there is one, and starts a new -// one. Data entries are added to the currently active upload. -message UploadChunk { - oneof Of { - // Upload adds a new entity to the store. - stash.Upload Upload = 1; - // Data contains data to append to the currently uploading chunk. - bytes data = 2; - } -} - -// DownloadChunk represents a chunk of data being downloaded. -message DownloadChunk { - // Data is the actual bytes to download for this chunk. - bytes data = 1; -} - -// Service is the api to a byte buffer storage service. -service Service { - // Search is used to find entities that match the given patterns. - rpc Search(search.Query) returns (stream stash.Entity) { - }; - // Upload is used to add new entities to the store. - // The data may be broken into many chunks, which should not be bigger than 1M - // each. - rpc Upload(stream UploadChunk) returns (UploadResponse) { - }; - // Download is used to fetch the full entity for an id. - // The data may be broken into many chunks, which should not be bigger than 1M - // each. - rpc Download(DownloadRequest) returns (stream DownloadChunk) { - }; -} - -message DownloadRequest { - // Id is the identity of the entity to download. - string id = 1; - // Offset is the offset from which to download. - uint64 offset = 2; - // Length represents the amount of data to download (up to the end if zero). - uint64 length = 3; -} - -message UploadResponse { -} diff --git a/test/robot/stash/local/BUILD.bazel b/test/robot/stash/local/BUILD.bazel deleted file mode 100644 index 7a7e2dc6ec..0000000000 --- a/test/robot/stash/local/BUILD.bazel +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "entity.go", - "file.go", - "memory.go", - ], - importpath = "github.com/google/gapid/test/robot/stash/local", - visibility = ["//visibility:public"], - deps = [ - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/os/file:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "//test/robot/stash:go_default_library", - "@com_github_golang_protobuf//proto:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - ], -) diff --git a/test/robot/stash/local/doc.go b/test/robot/stash/local/doc.go deleted file mode 100644 index 51a79c78da..0000000000 --- a/test/robot/stash/local/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package local provides implementations of a stash.Service for local storage. -package local diff --git a/test/robot/stash/local/entity.go b/test/robot/stash/local/entity.go deleted file mode 100644 index a2bff34227..0000000000 --- a/test/robot/stash/local/entity.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package local - -import ( - "context" - "reflect" - "sync" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" - "github.com/google/gapid/test/robot/stash" -) - -var entityClass = reflect.TypeOf(&stash.Entity{}) - -type entityIndex struct { - mu sync.Mutex - entities []*stash.Entity - byID map[string]*stash.Entity - onAdd event.Broadcast -} - -func (i *entityIndex) init() { - i.entities = []*stash.Entity{} - i.byID = map[string]*stash.Entity{} -} - -func (i *entityIndex) lockedAddEntry(ctx context.Context, entity *stash.Entity) { - i.entities = append(i.entities, entity) - i.byID[entity.Upload.Id] = entity - if err := i.onAdd.Send(ctx, entity); err != nil { - log.E(ctx, "Stash notification failed. Error: %v", err) - } -} - -func (e *entityIndex) Lookup(ctx context.Context, id string) (*stash.Entity, error) { - e.mu.Lock() - defer e.mu.Unlock() - - entity, found := e.byID[id] - if !found { - return nil, stash.ErrEntityNotFound - } - return entity, nil -} - -func (e *entityIndex) Search(ctx context.Context, query *search.Query, handler stash.EntityHandler) error { - filter := eval.Filter(ctx, query, entityClass, event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, e.entities) - if query.Monitor { - return event.Monitor(ctx, &e.mu, e.onAdd.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} diff --git a/test/robot/stash/local/file.go b/test/robot/stash/local/file.go deleted file mode 100644 index 9a5750ed69..0000000000 --- a/test/robot/stash/local/file.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package local - -import ( - "context" - "io" - "io/ioutil" - "net/url" - "os" - "time" - - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/test/robot/stash" -) - -type fileStore struct { - entityIndex - directory file.Path -} - -const metaExtension = ".meta" - -func init() { - stash.RegisterHandler("file", DialFileService) -} - -// DialFileService returns a file backed implementation of stash.Service from a url. -func DialFileService(ctx context.Context, location *url.URL) (*stash.Client, error) { - if location.Host != "" { - return nil, log.Err(ctx, nil, "Host not supported for file servers") - } - if location.Path == "" { - return nil, log.Err(ctx, nil, "Path must be specified for file servers") - } - return NewFileService(ctx, file.Abs(location.Path)) -} - -// NewFileService returns a file backed implementation of stash.Service for a path. -func NewFileService(ctx context.Context, directory file.Path) (*stash.Client, error) { - s := &fileStore{directory: directory} - s.entityIndex.init() - os.MkdirAll(directory.System(), 0755) - files, err := ioutil.ReadDir(directory.System()) - if err != nil { - return nil, err - } - for _, file := range files { - filename := directory.Join(file.Name()) - if filename.Ext() != metaExtension { - continue - } - data, err := ioutil.ReadFile(filename.System()) - if err != nil { - return nil, err - } - entity := &stash.Entity{} - if err := proto.Unmarshal(data, entity); err != nil { - return nil, err - } - s.lockedAddEntry(ctx, entity) - } - return &stash.Client{Service: s}, nil -} - -func (c *fileStore) Close() {} - -func (s *fileStore) Open(ctx context.Context, id string) (io.ReadSeeker, error) { - s.mu.Lock() - defer s.mu.Unlock() - if _, found := s.byID[id]; !found { - return nil, stash.ErrEntityNotFound - } - return os.Open(s.directory.Join(id).System()) -} - -func (s *fileStore) Read(ctx context.Context, id string) ([]byte, error) { - s.mu.Lock() - defer s.mu.Unlock() - if _, found := s.byID[id]; !found { - return nil, stash.ErrEntityNotFound - } - return ioutil.ReadFile(s.directory.Join(id).System()) -} - -func (s *fileStore) Create(ctx context.Context, info *stash.Upload) (io.WriteCloser, error) { - s.mu.Lock() - defer s.mu.Unlock() - if _, found := s.byID[info.Id]; found { - return nil, log.Err(ctx, nil, "Stash entity already exists") - } - filename := s.directory.Join(info.Id) - mode := os.FileMode(0666) - if info.Executable { - mode = 0777 - } - f, err := os.OpenFile(filename.System(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode) - if err != nil { - return nil, log.Err(ctx, err, "Stash could not create file") - } - now, _ := ptypes.TimestampProto(time.Now()) - w := &fileStoreWriter{ - f: f, - meta: filename.ChangeExt(metaExtension), - entity: &stash.Entity{ - Upload: info, - Status: stash.Uploading, - Length: 0, - Timestamp: now, - }, - } - // Write the meta data to the disk - meta, err := proto.Marshal(w.entity) - if err != nil { - return nil, log.Err(ctx, err, "Stash could not marshal meta data") - } - err = ioutil.WriteFile(w.meta.System(), meta, 0666) - if err != nil { - return nil, log.Err(ctx, err, "Stash could not save meta data") - } - // and finally add the entry into the map - s.lockedAddEntry(ctx, w.entity) - return w, nil -} - -type fileStoreWriter struct { - entity *stash.Entity - meta file.Path - f *os.File - size int64 -} - -func (w *fileStoreWriter) Write(b []byte) (int, error) { - n, err := w.f.Write(b) - w.size += int64(n) - return n, err -} - -func (w *fileStoreWriter) Close() error { - // Write the finalized meta data to the disk - w.entity.Status = stash.Present - w.entity.Length = w.size - meta, err := proto.Marshal(w.entity) - if err != nil { - return err - } - err = ioutil.WriteFile(w.meta.System(), meta, 0666) - if err != nil { - return err - } - return w.f.Close() -} diff --git a/test/robot/stash/local/memory.go b/test/robot/stash/local/memory.go deleted file mode 100644 index dc6b2e8e20..0000000000 --- a/test/robot/stash/local/memory.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package local - -import ( - "bytes" - "context" - "io" - "net/url" - "time" - - "github.com/golang/protobuf/ptypes" - "github.com/google/gapid/core/log" - "github.com/google/gapid/test/robot/stash" -) - -type memoryStore struct { - entityIndex - data map[string][]byte -} - -func init() { - stash.RegisterHandler("memory", DialMemoryService) -} - -// DialMemoryService returns a file backed implementation of stash.Service from a url. -func DialMemoryService(ctx context.Context, location *url.URL) (*stash.Client, error) { - if location.Host != "" { - return nil, log.Err(ctx, nil, "Host not supported for memory servers") - } - if location.Path != "" { - //TODO: keep a persistent map of memory services by name? - return nil, log.Err(ctx, nil, "Path not supported for memory servers") - } - return NewMemoryService(), nil -} - -// NewMemoryService returns a new purely in memory implementation of Store. -func NewMemoryService() *stash.Client { - store := &memoryStore{data: map[string][]byte{}} - store.entityIndex.init() - return &stash.Client{Service: store} -} - -func (s *memoryStore) Close() {} - -func (s *memoryStore) Open(ctx context.Context, id string) (io.ReadSeeker, error) { - s.mu.Lock() - defer s.mu.Unlock() - if data, found := s.data[id]; found { - return bytes.NewReader(data), nil - } - return nil, stash.ErrEntityNotFound -} - -func (s *memoryStore) Read(ctx context.Context, id string) ([]byte, error) { - s.mu.Lock() - defer s.mu.Unlock() - data, found := s.data[id] - if !found { - return nil, stash.ErrEntityNotFound - } - return data, nil -} - -func (s *memoryStore) Create(ctx context.Context, info *stash.Upload) (io.WriteCloser, error) { - s.mu.Lock() - defer s.mu.Unlock() - if _, found := s.byID[info.Id]; found { - return nil, log.Err(ctx, nil, "Stash entity already exists") - } - now, _ := ptypes.TimestampProto(time.Now()) - w := &memoryStoreWriter{ - store: s, - entity: &stash.Entity{ - Upload: info, - Status: stash.Uploading, - Length: 0, - Timestamp: now, - }, - } - s.lockedAddEntry(ctx, w.entity) - return w, nil -} - -type memoryStoreWriter struct { - store *memoryStore - entity *stash.Entity - buf bytes.Buffer -} - -func (w *memoryStoreWriter) Write(b []byte) (int, error) { - return w.buf.Write(b) -} - -func (w *memoryStoreWriter) Close() error { - data := w.buf.Bytes() - w.entity.Status = stash.Present - w.entity.Length = int64(len(data)) - w.store.data[w.entity.Upload.Id] = data - return nil -} diff --git a/test/robot/stash/stash.go b/test/robot/stash/stash.go deleted file mode 100644 index a4bcb2bdbf..0000000000 --- a/test/robot/stash/stash.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package stash - -import ( - "context" - "fmt" - "io" - "time" - - "github.com/golang/protobuf/ptypes" - "github.com/google/gapid/core/fault" - "github.com/google/gapid/test/robot/search" -) - -const ( - Unknown = Status_Unknown - Uploading = Status_Uploading - Present = Status_Present - - ErrEntityNotFound = fault.Const("Entity not found") -) - -type ( - // EntityHandler is a fuction that can be invoked for each entry in a - // stream of entities. - EntityHandler func(context.Context, *Entity) error - - // Service is the interface to a stash storage implementation. - // It abstracts away the actual storage part from the service logic. - Service interface { - // Close can be called to shut down the store. - // Behaviour of any other method after close is called is undefined. - Close() - // Lookup returns information about a single entity by id from the store. - Lookup(ctx context.Context, id string) (*Entity, error) - // Search returns a channel of matching entities from the store. - // The handler will be invoked once per matching entry. - // If the handler returns an error, the search will be terminated. - Search(ctx context.Context, query *search.Query, handler EntityHandler) error - // Open returns a reader to an entity's data. - // The reader may be nil if the entity is not present. - Open(ctx context.Context, id string) (io.ReadSeeker, error) - // Read returns a complete entity from the store. - // It may return an empty byte array if the entity is not present. - Read(ctx context.Context, id string) ([]byte, error) - // Create is used to add a new entity to the store. - // It returns a writer that can be used to write the content of the entity. - Create(ctx context.Context, info *Upload) (io.WriteCloser, error) - } -) - -// Format provices pretty printing of stash entities. -// It conforms to the fmt.Formatter interface. -func (e *Entity) Format(f fmt.State, c rune) { - name := "?" - if len(e.Upload.Name) > 0 { - name = e.Upload.Name[0] - } - t, _ := ptypes.Timestamp(e.Timestamp) - fmt.Fprintf(f, "%s %s : %s", name, t.Format(time.Stamp), e.Upload.Id) -} diff --git a/test/robot/stash/stash.proto b/test/robot/stash/stash.proto deleted file mode 100644 index 30c9dc3d8d..0000000000 --- a/test/robot/stash/stash.proto +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package stash; -option go_package = "github.com/google/gapid/test/robot/stash"; - -import "google/protobuf/timestamp.proto"; - -// Status represents the current known status of a stash entity. -enum Status { - // Unknown is the default (invalid) status. - Unknown = 0; - // Uploading means the entity is currently uploading. - Uploading = 1; - // Present means the entity is valid and present in the stash. - Present = 2; -} - -// Upload is the meta data supplied when uploading a new entity. -message Upload { - // Id is the unique identifier of the entity. - string id = 1; - // Name represents textual names to associate with the entity. - // This may be empty. - repeated string name = 2; - // Type represents (mime) types to associate with the entity. - // This may be empty. - repeated string type = 3; - // Executable is true if the file represents an executable binary. - bool executable = 4; -} - -// Entity represents the information known about an entity. -message Entity { - Upload Upload = 1; - // Status is the current known state of the entity. - Status status = 2; - // Length is the size in bytes of the entity. - int64 length = 3; - // Timestamp is the time when the entity was initially added to the server. - google.protobuf.Timestamp timestamp = 4; -} diff --git a/test/robot/stash/upload.go b/test/robot/stash/upload.go deleted file mode 100644 index 3e65267bb4..0000000000 --- a/test/robot/stash/upload.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package stash - -import ( - "context" - "crypto/sha1" - "encoding/hex" - "hash" - "io" - "mime" - "path/filepath" - "sync" - - "github.com/pkg/errors" -) - -var sha1Pool = sync.Pool{New: func() interface{} { return sha1.New() }} - -func hashStream(r io.Reader) string { - h := sha1Pool.Get().(hash.Hash) - defer sha1Pool.Put(h) - h.Reset() - io.Copy(h, r) - return hex.EncodeToString(h.Sum(nil)) -} - -func uploadStream(ctx context.Context, service Service, info Upload, r Uploadable) (string, error) { - // first calculate an id for the file - info.Id = hashStream(r) - // now check if the file is already in the stash - if entity, _ := service.Lookup(ctx, info.Id); entity != nil { - return info.Id, nil - } - // reset the stream and then upload the file to the specified id - if err := r.Reset(); err != nil { - return "", err - } - if len(info.Type) == 0 { - for _, name := range info.Name { - info.Type = append(info.Type, mime.TypeByExtension(filepath.Ext(name))) - } - } - w, err := service.Create(ctx, &info) - if err != nil { - return "", err - } - defer w.Close() - _, err = io.Copy(w, r) - if errors.Cause(err) == io.EOF { - err = nil - } - return info.Id, err -} - -type seekadapter struct { - io.ReadSeeker -} - -func (s seekadapter) Reset() error { - _, err := s.Seek(0, io.SeekStart) - return err -} - -type bytesAdapter struct { - data []byte - offset int -} - -func (b *bytesAdapter) Read(to []byte) (int, error) { - if b.offset >= len(b.data) { - return 0, io.EOF - } - count := copy(to, b.data[b.offset:]) - b.offset += count - return count, nil -} - -func (b *bytesAdapter) Reset() error { - b.offset = 0 - return nil -} diff --git a/test/robot/subject/BUILD.bazel b/test/robot/subject/BUILD.bazel deleted file mode 100644 index 7f2a530cf2..0000000000 --- a/test/robot/subject/BUILD.bazel +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "doc.go", - "local.go", - "remote.go", - "server.go", - "subject.go", - ], - embed = [":subject_go_proto"], - importpath = "github.com/google/gapid/test/robot/subject", - visibility = ["//visibility:public"], - deps = [ - "//core/event:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/android/apk:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/eval:go_default_library", - "//test/robot/stash:go_default_library", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "subject_proto", - srcs = ["subject.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/android/apk:apk_proto", - "//test/robot/search:search_proto", - "@com_google_protobuf//:duration_proto", - ], -) - -go_proto_library( - name = "subject_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/subject", - proto = ":subject_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/android/apk:go_default_library", - "//test/robot/search:go_default_library", - ], -) diff --git a/test/robot/subject/doc.go b/test/robot/subject/doc.go deleted file mode 100644 index e2aaacf912..0000000000 --- a/test/robot/subject/doc.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package subject holds the code for handling tracable applications -// in the robot system. -package subject diff --git a/test/robot/subject/local.go b/test/robot/subject/local.go deleted file mode 100644 index ee3f432e42..0000000000 --- a/test/robot/subject/local.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package subject - -import ( - "context" - "reflect" - "sync" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/android/apk" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" - "github.com/google/gapid/test/robot/search/eval" - "github.com/google/gapid/test/robot/stash" -) - -type local struct { - mu sync.Mutex - store *stash.Client - ledger record.Ledger - subjects []*Subject - byID map[string]*Subject - onChange event.Broadcast -} - -// NewLocal returns a new persistent store of Subjects. -func NewLocal(ctx context.Context, library record.Library, store *stash.Client) (Subjects, error) { - ledger, err := library.Open(ctx, "subjects", &Subject{}) - if err != nil { - return nil, err - } - s := &local{ - store: store, - ledger: ledger, - subjects: []*Subject{}, - byID: map[string]*Subject{}, - } - apply := event.AsHandler(ctx, s.apply) - if err := s.ledger.Read(ctx, apply); err != nil { - return nil, err - } - s.ledger.Watch(ctx, apply) - return s, nil -} - -// apply is called with items coming out of the ledger -// it should be called with the mutation lock already held. -func (s *local) apply(ctx context.Context, subject *Subject) error { - old := s.byID[subject.Id] - if old == nil { - s.subjects = append(s.subjects, subject) - s.byID[subject.Id] = subject - s.onChange.Send(ctx, subject) - return nil - } - if subject.Hints != nil { - if old.Hints.TraceTime != subject.Hints.TraceTime { - old.Hints.TraceTime = subject.Hints.TraceTime - } - if old.Hints.API != subject.Hints.API { - old.Hints.API = subject.Hints.API - } - } - s.onChange.Send(ctx, old) - return nil -} - -// Search implements Subjects.Search -// It searches the set of persisted subjects, and supports monitoring of subjects as they arrive. -func (s *local) Search(ctx context.Context, query *search.Query, handler Handler) error { - filter := eval.Filter(ctx, query, reflect.TypeOf(&Subject{}), event.AsHandler(ctx, handler)) - initial := event.AsProducer(ctx, s.subjects) - if query.Monitor { - return event.Monitor(ctx, &s.mu, s.onChange.Listen, initial, filter) - } - return event.Feed(ctx, filter, initial) -} - -// Add implements Subjects.Add -func (s *local) Add(ctx context.Context, id string, obbID string, hints *Hints) (*Subject, bool, error) { - s.mu.Lock() - defer s.mu.Unlock() - if subject, ok := s.byID[id]; ok { - return subject, false, nil - } - data, err := s.store.Read(ctx, id) - if err != nil { - return nil, false, err - } - if len(data) == 0 { - return nil, false, nil - } - // TODO: support non apk subjects - info, err := apk.Analyze(ctx, data) - if err != nil { - return nil, false, err - } - subject := &Subject{ - Id: id, - Information: &Subject_APK{ - APK: info, - }, - Hints: hints, - Obb: obbID, - } - if err := s.ledger.Add(ctx, subject); err != nil { - return nil, false, err - } - return subject, true, nil -} - -func (s *local) Update(ctx context.Context, subj *Subject) (*Subject, error) { - s.mu.Lock() - defer s.mu.Unlock() - if _, found := s.byID[subj.Id]; !found { - return nil, log.Err(ctx, nil, "Subject not found") - } - if err := s.ledger.Add(ctx, subj); err != nil { - return nil, err - } - return s.byID[subj.Id], nil -} diff --git a/test/robot/subject/remote.go b/test/robot/subject/remote.go deleted file mode 100644 index 2496a39087..0000000000 --- a/test/robot/subject/remote.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package subject - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a Subjects that talks to a remote grpc Subject service. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Subjects { - return &remote{ - client: NewServiceClient(conn), - } -} - -// Search implements Subjects.Search -// It forwards the call through grpc to the remote implementation. -func (m *remote) Search(ctx context.Context, query *search.Query, handler Handler) error { - stream, err := m.client.Search(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Add implements Subjects.Add -// It forwards the call through grpc to the remote implementation. -func (m *remote) Add(ctx context.Context, id string, obbID string, hints *Hints) (*Subject, bool, error) { - request := &AddRequest{Id: id, Hints: hints, Obb: obbID} - response, err := m.client.Add(ctx, request) - if err != nil { - return nil, false, err - } - return response.Subject, response.Created, nil -} - -func (m *remote) Update(ctx context.Context, subj *Subject) (*Subject, error) { - request := &UpdateRequest{Subject: subj} - response, err := m.client.Update(ctx, request) - if err != nil { - return nil, err - } - return response.Subject, nil -} diff --git a/test/robot/subject/server.go b/test/robot/subject/server.go deleted file mode 100644 index 3f0542aec6..0000000000 --- a/test/robot/subject/server.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package subject - -import ( - "context" - - "github.com/google/gapid/test/robot/search" - - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - subjects Subjects -} - -// Serve wraps a subject service in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, subjects Subjects) error { - RegisterServiceServer(grpcServer, &server{subjects: subjects}) - return nil -} - -// Add implements ServiceServer.Add -// It delegates the call to the provided Subjects implementation. -func (s *server) Add(ctx xctx.Context, request *AddRequest) (*AddResponse, error) { - subj, created, err := s.subjects.Add(ctx, request.Id, request.Obb, request.Hints) - if err != nil { - return nil, err - } - return &AddResponse{Subject: subj, Created: created}, nil -} - -// Search implements ServiceServer.Search -// It delegates the call to the provided Subjects implementation. -func (s *server) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.subjects.Search(ctx, query, func(ctx context.Context, e *Subject) error { return stream.Send(e) }) -} - -// Update implements ServiceServer.Update -// It delegates the call to the provided Subjects implementation. -func (s *server) Update(ctx xctx.Context, request *UpdateRequest) (*UpdateResponse, error) { - subj, err := s.subjects.Update(ctx, request.Subject) - if err != nil { - return nil, err - } - return &UpdateResponse{Subject: subj}, nil -} diff --git a/test/robot/subject/subject.go b/test/robot/subject/subject.go deleted file mode 100644 index 212b88dce6..0000000000 --- a/test/robot/subject/subject.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package subject - -import ( - "context" - - "github.com/google/gapid/test/robot/search" -) - -// Handler is a function that handles a stream of Subjects. -type Handler func(context.Context, *Subject) error - -// Subjects is the interface to a subject manager. -type Subjects interface { - // Search returns a iterator of matching subjects from the store. - Search(context.Context, *search.Query, Handler) error - // Add adds a new subject to the set. - Add(ctx context.Context, id string, obbID string, hints *Hints) (*Subject, bool, error) - // Update changes the values of a subject. - Update(ctx context.Context, subj *Subject) (*Subject, error) -} diff --git a/test/robot/subject/subject.proto b/test/robot/subject/subject.proto deleted file mode 100644 index a4de76a0fb..0000000000 --- a/test/robot/subject/subject.proto +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package subject; -option go_package = "github.com/google/gapid/test/robot/subject"; - -import "core/os/android/apk/apk.proto"; -import "test/robot/search/search.proto"; -import "google/protobuf/duration.proto"; - -// Subject is the information we know about a given subject. -message Subject { - // Id is the id of the app in the stash. - string id = 1; - // Information is the extracted details we know about the subject. - oneof Information { - // APK is the information if the subject type is an android APK. - apk.Information APK = 2; - } - Hints hints = 3; - // Obb is the id of the OBB file in the stash. - string obb = 4; -} - -message Hints { - // traceTime is the preferred duration for tracing this subject. - google.protobuf.Duration traceTime = 1; - // ObserveFrames is the preferred number of frames to observe for tracing this - // subject, 0 for all. - uint32 observeFrames = 2; - // API is the name of the api to capture on this subject, values can be gles - // and vulkan - string API = 4; -} - -// Service is the api to the robot app storage. -service Service { - // Search is used to find subjects that match the given query. - rpc Search(search.Query) returns (stream Subject) { - }; - // Add pulls the subject from the stash, analyzes it and adds it to the - // service. If the subject already exists, it will be returned without - // modification. - rpc Add(AddRequest) returns (AddResponse) { - }; - // Update modifies a subject entry - rpc Update(UpdateRequest) returns (UpdateResponse) { - }; -} - -message AddRequest { - // Id is the id of the subject in the stash. - string id = 1; - // hints is the set of trace hints for this subject. - Hints hints = 2; - // Obb is the id of the OBB file in the stash. - string obb = 3; -} - -message AddResponse { - // Subject is the subject that was generated by the add. - Subject subject = 1; - // Created is set to true if the subject was added by this call, - // and false if it was already present - bool created = 2; -} - -message UpdateRequest { - // Subject contains the information to merge into the subject. - // If the id is present, it must match an existing subject. - // Only updates the Hints field. - Subject subject = 1; -} - -message UpdateResponse { - // Subject is the updated subject information. - Subject subject = 1; -} diff --git a/test/robot/trace/BUILD.bazel b/test/robot/trace/BUILD.bazel deleted file mode 100644 index c5123ca746..0000000000 --- a/test/robot/trace/BUILD.bazel +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "doc.go", - "local.go", - "manager.go", - "remote.go", - "server.go", - ], - embed = [":trace_go_proto"], - importpath = "github.com/google/gapid/test/robot/trace", - visibility = ["//visibility:public"], - deps = [ - "//core/app/crash:go_default_library", - "//core/app/layout:go_default_library", - "//core/event:go_default_library", - "//core/event/task:go_default_library", - "//core/log:go_default_library", - "//core/net/grpcutil:go_default_library", - "//core/os/device:go_default_library", - "//core/os/device/bind:go_default_library", - "//core/os/file:go_default_library", - "//core/os/shell:go_default_library", - "//gapidapk:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/record:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/stash:go_default_library", - "@com_github_golang_protobuf//ptypes:go_default_library_gen", - "@org_golang_google_grpc//:go_default_library", - "@org_golang_x_net//context:go_default_library", - ], -) - -proto_library( - name = "trace_proto", - srcs = ["trace.proto"], - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:device_proto", - "//test/robot/job:job_proto", - "//test/robot/job/worker:worker_proto", - "//test/robot/search:search_proto", - "//test/robot/subject:subject_proto", - ], -) - -go_proto_library( - name = "trace_go_proto", - compilers = ["@io_bazel_rules_go//proto:go_grpc"], - importpath = "github.com/google/gapid/test/robot/trace", - proto = ":trace_proto", - visibility = ["//visibility:public"], - deps = [ - "//core/os/device:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/job/worker:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/subject:go_default_library", - ], -) diff --git a/test/robot/trace/client.go b/test/robot/trace/client.go deleted file mode 100644 index 1600c72d9f..0000000000 --- a/test/robot/trace/client.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "bytes" - "context" - "fmt" - "strconv" - "strings" - "time" - - "github.com/golang/protobuf/ptypes" - "github.com/google/gapid/core/app/crash" - "github.com/google/gapid/core/app/layout" - "github.com/google/gapid/core/event/task" - "github.com/google/gapid/core/log" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/core/os/device/bind" - "github.com/google/gapid/core/os/file" - "github.com/google/gapid/core/os/shell" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/stash" - - _ "github.com/google/gapid/gapidapk" -) - -const ( - traceTimeout = time.Hour - // this string is returned when GAPIT fails to connect to the GAPIS, particularly due to ETXTBSY - // look at https://github.com/google/gapid/pull/933 for more information - retryString = "Failed to connect to the GAPIS server" - // The value to use for gapit's --observe-frames flag. - observeEveryNthFrame = 5 -) - -type client struct { - store *stash.Client - manager Manager - tempDir file.Path -} - -// Run starts new trace client if any hardware is available. -func Run(ctx context.Context, store *stash.Client, manager Manager, tempDir file.Path) error { - c := &client{store: store, manager: manager, tempDir: tempDir} - job.OnDeviceAdded(ctx, c.onDeviceAdded) - return nil -} - -// TODO: not assume all android devices are valid trace targets -func (c *client) onDeviceAdded(ctx context.Context, host *device.Instance, target bind.Device) { - traceOnTarget := func(ctx context.Context, t *Task) error { - job.LockDevice(ctx, target) - defer job.UnlockDevice(ctx, target) - if target.Status(ctx) != bind.Status_Online { - log.I(ctx, "Trying to trace %s on %s not started, device status %s", - t.Input.Subject, target.Instance().GetSerial(), target.Status(ctx).String()) - return nil - } - return c.trace(ctx, target, t) - } - crash.Go(func() { - if err := c.manager.Register(ctx, host, target.Instance(), traceOnTarget); err != nil { - log.E(ctx, "Error running trace client: %v", err) - } - }) -} - -func (c *client) trace(ctx context.Context, d bind.Device, t *Task) error { - if err := c.manager.Update(ctx, t.Action, job.Running, nil); err != nil { - return err - } - var output *Output - err := worker.RetryFunction(ctx, 4, time.Millisecond*100, func() (err error) { - ctx, cancel := task.WithTimeout(ctx, traceTimeout) - defer cancel() - output, err = doTrace(ctx, t.Action, t.Input, c.store, d, c.tempDir) - return - }) - status := job.Succeeded - if err != nil { - status = job.Failed - log.E(ctx, "Error running trace: %v", err) - } else if output.Err != "" { - status = job.Failed - log.E(ctx, "Error during trace: %v", output.Err) - } - - return c.manager.Update(ctx, t.Action, status, output) -} - -// doTrace extracts input files and runs `gapit trace` on them, capturing the output. The output object will -// be partially filled in the event of an upload error from store in order to allow examination of the logs. -func doTrace(ctx context.Context, action string, in *Input, store *stash.Client, d bind.Device, tempDir file.Path) (*Output, error) { - subject := tempDir.Join(action + ".apk") - obb := tempDir.Join(action + ".obb") - tracefile := tempDir.Join(action + ".gfxtrace") - extractedDir := tempDir.Join(action + "_tools") - extractedLayout, err := layout.NewPkgLayout(extractedDir, true) - if err != nil { - return nil, err - } - - gapidAPK, err := extractedLayout.GapidApk(ctx, in.GetToolingLayout().GetGapidAbi()) - if err != nil { - return nil, err - } - - gapis, err := extractedLayout.Gapis(ctx) - if err != nil { - return nil, err - } - - gapit, err := extractedLayout.Gapit(ctx) - if err != nil { - return nil, err - } - - traceTime, err := ptypes.Duration(in.GetHints().GetTraceTime()) - if err != nil { - traceTime = 10 * time.Minute // TODO: support Robot-wide override - } - - defer func() { - file.Remove(subject) - file.Remove(tracefile) - file.RemoveAll(extractedDir) - }() - if err := store.GetFile(ctx, in.Subject, subject); err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.Gapis, gapis); err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.Gapit, gapit); err != nil { - return nil, err - } - if err := store.GetFile(ctx, in.GapidApk, gapidAPK); err != nil { - return nil, err - } - - params := []string{ - "trace", - "-out", tracefile.System(), - "-for", traceTime.String(), - "-disable-pcs", - "-observe-frames", strconv.Itoa(observeEveryNthFrame), - "-record-errors", - "-serial", d.Instance().Serial, - "-api", in.GetHints().GetAPI(), - } - - if frames := in.GetHints().GetObserveFrames(); frames > 0 { - params = append(params, "-capture-frames", strconv.Itoa(int(frames*observeEveryNthFrame+1))) - } - if in.Obb != "" { - if err := store.GetFile(ctx, in.Obb, obb); err != nil { - return nil, err - } - defer func() { - file.Remove(obb) - }() - // TODO fix this - // params = append(params, "-obb", obb.System()) - return log.Errf(ctx, nil, "OBBs are currently not supported") - } - cmd := shell.Command(gapit.System(), append(params, "apk:"+subject.System())...) - outBuf := &bytes.Buffer{} - errBuf := &bytes.Buffer{} - outputObj := &Output{} - errs := []string{} - log.I(ctx, "Running trace action %s", cmd) - if err := cmd.Capture(outBuf, errBuf).Run(ctx); err != nil { - if err := worker.NeedsRetry(err.Error()); err != nil { - return nil, err - } - errs = append(errs, err.Error()) - } - errs = append(errs, strings.TrimSpace(errBuf.String())) - outputObj.Err = strings.Join(errs, "\n") - if err := worker.NeedsRetry(outputObj.Err, retryString); err != nil { - return nil, err - } - - output := fmt.Sprintf("%s\n\n%s", cmd, strings.TrimSpace(outBuf.String())) - log.I(ctx, output) - logID, err := store.UploadString(ctx, stash.Upload{Name: []string{"trace.log"}, Type: []string{"text/plain"}}, output) - if err != nil { - return outputObj, err - } - outputObj.Log = logID - traceID, err := store.UploadFile(ctx, tracefile) - if err != nil { - return outputObj, err - } - outputObj.Trace = traceID - return outputObj, nil -} - -type offlineDevice struct { - bind.Device -} - -func (offlineDevice) Status() bind.Status { - return bind.Status_Offline -} diff --git a/test/robot/trace/doc.go b/test/robot/trace/doc.go deleted file mode 100644 index 86202265eb..0000000000 --- a/test/robot/trace/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package trace holds the code for taking a capture in the robot system. -package trace diff --git a/test/robot/trace/local.go b/test/robot/trace/local.go deleted file mode 100644 index d10207e6e0..0000000000 --- a/test/robot/trace/local.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/record" - "github.com/google/gapid/test/robot/search" -) - -type local struct { - w worker.Manager -} - -func (a *Action) JobID() string { return a.Id } -func (a *Action) JobHost() string { return a.Host } -func (a *Action) JobTarget() string { return a.Target } -func (a *Action) JobInput() worker.Input { return a.Input } -func (a *Action) Init(id string, input worker.Input, w *job.Worker) { - a.Id = id - a.Input = input.(*Input) - a.Host = w.Host - a.Target = w.Target -} -func (t *Task) Init(id string, input worker.Input, w *job.Worker) { - t.Action = id - t.Input = input.(*Input) -} - -// NewLocal builds a new local manager. -func NewLocal(ctx context.Context, library record.Library, jobManager job.Manager) (Manager, error) { - l := &local{} - return l, l.w.Init(ctx, library, jobManager, job.Trace, &Action{}, &Task{}) -} - -// Search implements Manager.Search -// It searches the set of persisted actions, and supports monitoring of actions as they arrive. -func (l *local) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - return l.w.Actions.Search(ctx, query, handler) -} - -// Register implements Manager.Register -// See Workers.Register for more details on the implementation. -func (l *local) Register(ctx context.Context, host *device.Instance, target *device.Instance, handler TaskHandler) error { - return l.w.Workers.Register(ctx, host, target, handler) -} - -// Do implements Manager.Do -// See Workers.Do for more details on the implementation. -func (l *local) Do(ctx context.Context, device string, input *Input) (string, error) { - return l.w.Do(ctx, device, input) -} - -// Update implements Manager.Update -// See Workers.Update for more details on the implementation. -func (l *local) Update(ctx context.Context, action string, status job.Status, output *Output) error { - return l.w.Update(ctx, &Action{Id: action, Status: status, Output: output}) -} diff --git a/test/robot/trace/manager.go b/test/robot/trace/manager.go deleted file mode 100644 index 8b8533511e..0000000000 --- a/test/robot/trace/manager.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/search" -) - -// ActionHandler is a function that handles a stream of Actions. -type ActionHandler func(context.Context, *Action) error - -// TaskHandler is a function that handles a stream of Tasks. -type TaskHandler func(context.Context, *Task) error - -// Manager is the interface to a trace manager. -type Manager interface { - // Search invokes handler with each output that matches the query. - Search(ctx context.Context, query *search.Query, handler ActionHandler) error - // Register a handler that will accept incoming tasks. - Register(ctx context.Context, host *device.Instance, target *device.Instance, handler TaskHandler) error - // Do asks the manager to send a task to a device. - Do(ctx context.Context, device string, input *Input) (string, error) - // Update adjusts the state of an action. - Update(ctx context.Context, action string, status job.Status, output *Output) error -} diff --git a/test/robot/trace/remote.go b/test/robot/trace/remote.go deleted file mode 100644 index f38200a12e..0000000000 --- a/test/robot/trace/remote.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - - "github.com/google/gapid/core/event" - "github.com/google/gapid/core/net/grpcutil" - "github.com/google/gapid/core/os/device" - "github.com/google/gapid/test/robot/job" - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" -) - -type remote struct { - client ServiceClient -} - -// NewRemote returns a Worker that talks to a remote grpc trace service. -func NewRemote(ctx context.Context, conn *grpc.ClientConn) Manager { - return &remote{ - client: NewServiceClient(conn), - } -} - -// Search implements Manager.Search -// It forwards the call through grpc to the remote implementation. -func (m *remote) Search(ctx context.Context, query *search.Query, handler ActionHandler) error { - stream, err := m.client.Search(ctx, query) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Register implements Manager.Register -// It forwards the call through grpc to the remote implementation. -func (m *remote) Register(ctx context.Context, host *device.Instance, target *device.Instance, handler TaskHandler) error { - request := &worker.RegisterRequest{Host: host, Target: target} - stream, err := m.client.Register(ctx, request) - if err != nil { - return err - } - return event.Feed(ctx, event.AsHandler(ctx, handler), grpcutil.ToProducer(stream)) -} - -// Do implements Manager.Do -// It forwards the call through grpc to the remote implementation. -func (m *remote) Do(ctx context.Context, device string, input *Input) (string, error) { - response, err := m.client.Do(ctx, &DoRequest{Device: device, Input: input}) - return response.Id, err -} - -// Update implements Manager.Update -// It forwards the call through grpc to the remote implementation. -func (m *remote) Update(ctx context.Context, action string, status job.Status, output *Output) error { - request := &UpdateRequest{Action: action, Status: status, Output: output} - _, err := m.client.Update(ctx, request) - return err -} diff --git a/test/robot/trace/server.go b/test/robot/trace/server.go deleted file mode 100644 index ee9689a7cc..0000000000 --- a/test/robot/trace/server.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trace - -import ( - "context" - - "github.com/google/gapid/test/robot/job/worker" - "github.com/google/gapid/test/robot/search" - "google.golang.org/grpc" - - xctx "golang.org/x/net/context" -) - -type server struct { - manager Manager -} - -// Serve wraps a manager in a grpc server. -func Serve(ctx context.Context, grpcServer *grpc.Server, manager Manager) error { - RegisterServiceServer(grpcServer, &server{manager: manager}) - return nil -} - -// Search implements ServiceServer.Search -// It delegates the call to the provided Manager implementation. -func (s *server) Search(query *search.Query, stream Service_SearchServer) error { - ctx := stream.Context() - return s.manager.Search(ctx, query, func(ctx context.Context, e *Action) error { return stream.Send(e) }) -} - -// Register implements ServiceServer.Register -// It delegates the call to the provided Manager implementation. -func (s *server) Register(request *worker.RegisterRequest, stream Service_RegisterServer) error { - ctx := stream.Context() - return s.manager.Register(ctx, request.Host, request.Target, func(ctx context.Context, t *Task) error { return stream.Send(t) }) -} - -// Do implements ServiceServer.Do -// It delegates the call to the provided Manager implementation. -func (s *server) Do(ctx xctx.Context, request *DoRequest) (*worker.DoResponse, error) { - id, err := s.manager.Do(ctx, request.Device, request.Input) - return &worker.DoResponse{Id: id}, err -} - -// Update implements ServiceServer.Update -// It delegates the call to the provided Manager implementation. -func (s *server) Update(ctx xctx.Context, request *UpdateRequest) (*worker.UpdateResponse, error) { - if err := s.manager.Update(ctx, request.Action, request.Status, request.Output); err != nil { - return nil, err - } - return &worker.UpdateResponse{}, nil -} diff --git a/test/robot/trace/trace.proto b/test/robot/trace/trace.proto deleted file mode 100644 index bc8155612f..0000000000 --- a/test/robot/trace/trace.proto +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -package trace; -option go_package = "github.com/google/gapid/test/robot/trace"; - -import "test/robot/job/job.proto"; -import "test/robot/job/worker/worker.proto"; -import "test/robot/subject/subject.proto"; -import "test/robot/search/search.proto"; -import "core/os/device/device.proto"; - -// Input describes the inputs to a trace action. -message Input { - // Subject is the stash id of the trace subject. - string subject = 1; - // Gapis is the stash id of the graphics server tool to use. - string gapis = 8; - // Gapit is the stash id of the graphics analysis tool to use. - string gapit = 2; - // GapidApk is the stash id of the gapid.apk to use. - string gapid_apk = 3; - // hints represents the set of trace hints - subject.Hints hints = 4; - // ToolingLayout represents details about what tools we're using to trace. - ToolingLayout tooling_layout = 5; - // Package is the stash id of the package used to trace. - string package = 6; - // Obb is the stash id of the OBB used by the subject in the trace. - string obb = 7; -} - -// ToolingLayout describes tools we use for tracing. -message ToolingLayout { - device.ABI gapid_abi = 1; -} - -// Output describes the outputs of a trace action. -message Output { - // Log is stash id of the generated log file. - string log = 1; - // Trace is the stash id of the generated trace file. - string trace = 2; - // Err is the stderr buffer returned by the call to gapit. - string err = 3; -} - -// Action holds the information about an execution of a task. -message Action { - // Id is the unique id the action. - string id = 1; - // Input is the set of inputs to the action. - Input input = 2; - // Host is the device which hosts the action. - string host = 3; - // Target is the device on which the action will be performed. - string target = 4; - // Status is the status to set for the action - job.Status status = 5; - // Output is the results of the action. - Output output = 6; -} - -// Task holds the information needed to run a trace task in a device. -message Task { - // Action is the id of the action this task should post results to. - string action = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -// Service is the api to the robot device storage. -service Service { - // Search is used to find actions that match the given query. - rpc Search(search.Query) returns (stream Action) { - }; - // Register registers a device for a stream of tasks. - rpc Register(worker.RegisterRequest) returns (stream Task) { - }; - // Do asks the manager to send a task to a device. - rpc Do(DoRequest) returns (worker.DoResponse) { - }; - // Update sets the results of an action. - rpc Update(UpdateRequest) returns (worker.UpdateResponse) { - }; -} - -message DoRequest { - // Device is the device id to perform the task on. - string device = 1; - // Input is the set of inputs to the task. - Input input = 2; -} - -message UpdateRequest { - // Action is the action to update. - string action = 1; - // Status is the status to set for the action - job.Status status = 2; - // Output is the outputs to set on the action. - Output output = 3; -} diff --git a/test/robot/web/BUILD.bazel b/test/robot/web/BUILD.bazel deleted file mode 100644 index 23e300da71..0000000000 --- a/test/robot/web/BUILD.bazel +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (C) 2018 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# gazelle:exclude client - -load("@io_bazel_rules_go//go:def.bzl", "go_library") -load("//tools/build:rules.bzl", "embed") - -embed( - name = "embed", - srcs = glob([ - "www/**/*.html", - "www/**/*.css", - "www/**/*.js", - "www/**/*.png", - ]), - root = "./test/robot/web/", -) - -go_library( - name = "go_default_library", - srcs = [ - "action.go", - "build.go", - "doc.go", - "entity.go", - "grid.go", - "job.go", - "master.go", - "requests.go", - "static.go", - "status.go", - "subject.go", - "web.go", - ":embed", # keep - ], - importpath = "github.com/google/gapid/test/robot/web", - visibility = ["//visibility:public"], - deps = [ - "//core/log:go_default_library", - "//core/os/file:go_default_library", - "//test/robot/build:go_default_library", - "//test/robot/job:go_default_library", - "//test/robot/master:go_default_library", - "//test/robot/monitor:go_default_library", - "//test/robot/replay:go_default_library", - "//test/robot/report:go_default_library", - "//test/robot/search:go_default_library", - "//test/robot/search/query:go_default_library", - "//test/robot/search/script:go_default_library", - "//test/robot/stash:go_default_library", - "//test/robot/subject:go_default_library", - "//test/robot/trace:go_default_library", - ], -) diff --git a/test/robot/web/action.go b/test/robot/web/action.go deleted file mode 100644 index 830649e98c..0000000000 --- a/test/robot/web/action.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package web - -import ( - "context" - "encoding/json" - "net/http" - - "github.com/google/gapid/test/robot/replay" - "github.com/google/gapid/test/robot/report" - "github.com/google/gapid/test/robot/trace" -) - -func (s *Server) handleReplays(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*replay.Action{} - - if query, err := query(w, r); err == nil { - if err = s.Replay.Search(ctx, query, func(ctx context.Context, entry *replay.Action) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - - json.NewEncoder(w).Encode(result) - } -} - -func (s *Server) handleTraces(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*trace.Action{} - - if query, err := query(w, r); err == nil { - if err = s.Trace.Search(ctx, query, func(ctx context.Context, entry *trace.Action) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - - json.NewEncoder(w).Encode(result) - } -} - -func (s *Server) handleReports(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*report.Action{} - - if query, err := query(w, r); err == nil { - if err = s.Report.Search(ctx, query, func(ctx context.Context, entry *report.Action) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - - json.NewEncoder(w).Encode(result) - } -} diff --git a/test/robot/web/build.go b/test/robot/web/build.go deleted file mode 100644 index 7346187178..0000000000 --- a/test/robot/web/build.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package web - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - - "github.com/google/gapid/test/robot/build" - q "github.com/google/gapid/test/robot/search/query" -) - -func (s *Server) handleArtifacts(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*build.Artifact(nil) - - if query, err := query(w, r); err == nil { - if err = s.Build.SearchArtifacts(ctx, query, func(ctx context.Context, entry *build.Artifact) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - json.NewEncoder(w).Encode(result) - } -} - -func (s *Server) handlePackages(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*build.Package(nil) - - if query, err := query(w, r); err == nil { - if err = s.Build.SearchPackages(ctx, query, func(ctx context.Context, entry *build.Package) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - json.NewEncoder(w).Encode(result) - } -} - -func (s *Server) handlePackageChain(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - - head := r.FormValue("head") - if head == "" { - writeError(w, 404, errors.New("The head parameter is required")) - return - } - - pkgs := map[string]*build.Package{} - if err := s.Build.SearchPackages(ctx, q.Bool(true).Query(), func(ctx context.Context, entry *build.Package) error { - pkgs[entry.Id] = entry - return nil - }); err != nil { - writeError(w, 500, err) - return - } - - pkg, ok := pkgs[head] - if !ok { - writeError(w, 404, fmt.Errorf("Package '%s' not found", head)) - return - } - - result := []*build.Package(nil) - for ; pkg != nil; pkg = pkgs[pkg.Parent] { - result = append(result, pkg) - } - - json.NewEncoder(w).Encode(result) -} - -func (s *Server) handleTracks(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - result := []*build.Track(nil) - - if query, err := query(w, r); err == nil { - if err = s.Build.SearchTracks(ctx, query, func(ctx context.Context, entry *build.Track) error { - result = append(result, entry) - return nil - }); err != nil { - writeError(w, 500, err) - return - } - json.NewEncoder(w).Encode(result) - } -} diff --git a/test/robot/web/client/client.go b/test/robot/web/client/client.go deleted file mode 100644 index 4070a9a801..0000000000 --- a/test/robot/web/client/client.go +++ /dev/null @@ -1,556 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "strings" - "time" - - "github.com/google/gapid/test/robot/web/client/dom" - "github.com/google/gapid/test/robot/web/client/widgets/grid" - "github.com/google/gapid/test/robot/web/client/widgets/objview" -) - -type traceInfo struct { - target Item - subject Item -} - -type task struct { - trace traceInfo - - kind Item - host Item - pkg Item - result grid.Result - status grid.Status - - parent *task - - underlying map[string]interface{} -} - -func (t *task) Representation() interface{} { - tr := map[string]interface{}{} - tr["trace target"] = t.trace.target.Underlying() - tr["trace subject"] = t.trace.subject.Underlying() - tr["host"] = t.host.Underlying() - tr["package"] = t.pkg.Underlying() - return []interface{}{tr, t.underlying} -} - -type enum []Item - -func (e enum) indexOf(s Item) int { - for i, v := range e { - if v.Id() == s.Id() { - return i - } - } - return -1 -} - -type dimension struct { - name string - enumData enum - valueOf func(*task) Item - itemMap map[string]Item - enumSrc func() enum - enumSort func(a, b string) bool - defVal func() string -} - -func (d *dimension) getEnum() enum { - if d.enumData == nil { - d.enumData = d.enumSrc() - } - return d.enumData -} - -func (d *dimension) defaultId() string { - if d.defVal != nil { - return d.defVal() - } - return "" -} - -type Item interface { - Id() string - Display() string - Underlying() interface{} -} - -type item struct { - id string - display string - underlying interface{} -} - -func (i item) Underlying() interface{} { - if i.underlying == nil { - return i.Id() - } - return i.underlying -} - -func (i item) Id() string { - return i.id -} - -func (i item) Display() string { - if i.display == "" { - return i.id - } - return i.display -} - -var nilItem = item{id: "", underlying: map[string]interface{}{}} - -func (d *dimension) GetItem(val interface{}) Item { - if val == nil { - return nilItem - } - id := val.(string) - if d.itemMap == nil { - d.itemMap = make(map[string]Item) - for _, it := range d.getEnum() { - d.itemMap[it.Id()] = it - } - } - return d.itemMap[id] -} - -func robotEntityLink(path string, s interface{}) interface{} { - id := s.(string) - a := dom.NewA() - a.Set("href", fmt.Sprintf("/entities/%s", id)) - a.Append(id) - return a -} - -func robotTextPreview(path string, s interface{}) interface{} { - id := s.(string) - - div := dom.NewDiv() - a := robotEntityLink(path, s) - div.Append(a) - textDiv := dom.NewDiv() - textDiv.Element.Style.MaxWidth = 600 - textDiv.Element.Style.MaxHeight = 420 - textDiv.Element.Style.Overflow = "auto" - textDiv.Element.Style.WhiteSpace = "pre" - go func() { - // if the text is larger than a megabyte, cut off early. - fullText, err := queryRestEndpointWithCutoff(fmt.Sprintf("/entities/%s", id), 1024*1024) - if err != nil { - textDiv.Append("Error previewing text:" + err.Error()) - return - } - - textDiv.Append(string(fullText)) - }() - div.Append(textDiv) - return div -} - -func robotVideoView(path string, s interface{}) interface{} { - id := s.(string) - v := dom.NewVideo(600, 420, fmt.Sprintf("/entities/%s", id), "mp4") - v.Append("Your browser does not support embedded video tags") - return v -} - -type filter struct { - selecter *dom.Select - options map[string]string - dim *dimension - sort func(a, b string) bool -} - -type view struct { - div *dom.Div - objView *objview.View - formatters *objview.Formatters - filters []*filter - column *filter - row *filter -} - -func newView() *view { - v := &view{div: dom.NewDiv(), objView: objview.NewView()} - - // The object viewer Representation() for a task looks like: - // [ {"trace host": ..., "trace target": ...,}, {"id": ..., "input": ..., "host": ..., "target": ..., } ] - // We customize the display of some of these. For example '/1/target' means the second element of the top-level - // array, and then the 'target' field in that struct. We format that one as a link to push the target device in - // the viewer, and then collapse the MemoryLayout parts (see devFmts). - devFmts := objview.NewFormatters().Add("/information/Configuration/ABIs/\\d+/MemoryLayout", v.objView.Expandable) - v.formatters = objview.NewFormatters().Add( - "/1/trace_target", - func(path string, a interface{}) interface{} { - id := a.(string) - return v.objView.NewPusher(id, "trace_target", targetDimension.GetItem(id).Underlying, devFmts) - }, - ).Add( - "/1/host", - func(path string, a interface{}) interface{} { - id := a.(string) - return v.objView.NewPusher(id, "host", hostDimension.GetItem(id).Underlying, devFmts) - }, - ).Add("/1/input/((gapi[irst])|gapid_apk|trace|subject|interceptor|vulkanLayer)", robotEntityLink). - Add("/1/input/layout", v.objView.Expandable). - Add("/1/output/(log|report)", robotTextPreview). - Add("/1/output/err", func(path string, a interface{}) interface{} { - err := a.(string) - div := dom.NewDiv() - div.Element.Style.MaxWidth = 600 - div.Element.Style.MaxHeight = 420 - div.Element.Style.Overflow = "auto" - div.Element.Style.WhiteSpace = "pre" - div.Append(err) - return div - }). - Add("/1/output/video", robotVideoView). - Add("/0/", v.objView.Expandable) - - body := dom.Doc().Body() - body.Style.BackgroundColor = dom.RGB(0.98, 0.98, 0.98) - v.objView.Div.Element.Style.Position = "sticky" - v.objView.Div.Element.Style.Top = "0" - v.objView.Div.Element.Style.Float = "right" - body.Append(v.objView) - body.Append(v.div) - - return v -} - -func (v *view) optAllValue() string { - return "!!all" -} - -func (v *view) optXAxisValue() string { - return "!!x-axis" -} - -func (v *view) optYAxisValue() string { - return "!!y-axis" -} - -func (v *view) addFilter(d *dimension) *filter { - row := dom.NewDiv() - label := dom.NewSpan() - label.Text().Set(d.name + ": ") - selecter := dom.NewSelect() - selecter.Append(dom.NewOption("", v.optAllValue())) - selecter.Append(dom.NewOption("", v.optXAxisValue())) - selecter.Append(dom.NewOption("", v.optYAxisValue())) - - f := &filter{ - selecter: selecter, - options: make(map[string]string), - dim: d, - sort: d.enumSort, - } - - for _, e := range d.getEnum() { - selecter.Append(dom.NewOption(e.Display(), e.Id())) - f.options[e.Display()] = e.Id() - } - - if id := d.defaultId(); id != "" { - f.selecter.Value = id - } else if v.column == nil { - f.selecter.Value = v.optXAxisValue() - v.column = f - } else if v.row == nil { - f.selecter.Value = v.optYAxisValue() - v.row = f - } else { - f.selecter.Value = v.optAllValue() - } - - v.filters = append(v.filters, f) - - row.Append(label) - row.Append(selecter) - v.div.Append(row) - - return f -} - -func (v *view) setAxis(f *filter) *filter { - if f.selecter.Value == v.optXAxisValue() { - if v.column == f { - // no change - return nil - } else if v.row == f { - // perform a swap - return nil - } else { - oldAxis := v.column - v.column = f - return oldAxis - } - } else if f.selecter.Value == v.optYAxisValue() { - if v.row == f { - // no change - return nil - } else if v.column == f { - // perform a swap - return nil - } else { - oldAxis := v.row - v.row = f - return oldAxis - } - } else { - return nil - } -} - -func (v *view) refreshGrid(tasks []*task, g *grid.Grid) { - data := grid.Data{ - Columns: map[grid.Key]*grid.HeaderData{}, - Rows: map[grid.Key]*grid.HeaderData{}, - Cells: map[grid.CellIndex]*grid.CellData{}, - } - - for d, v := range v.column.options { - data.Columns[v] = &grid.HeaderData{Name: d} - } - - for d, v := range v.row.options { - data.Rows[v] = &grid.HeaderData{Name: d} - } - -nextTask: - for _, task := range tasks { - t := grid.Task{Result: task.result, Status: task.status, Data: task} - colKey, rowKey := "", "" - for _, f := range v.filters { - if f.selecter.Value == v.optAllValue() { - continue - } - dimValue := f.dim.valueOf(task).Id() - switch f.selecter.Value { - case v.optXAxisValue(): - colKey = dimValue - case v.optYAxisValue(): - rowKey = dimValue - default: - if f.selecter.Value != dimValue { - // doesn't match the filter, don't add this task - continue nextTask - } - } - } - col := data.Columns[colKey] - col.Tasks = append(col.Tasks, t) - row := data.Rows[rowKey] - row.Tasks = append(row.Tasks, t) - idx := grid.CellIndex{Column: colKey, Row: rowKey} - if cell, ok := data.Cells[idx]; !ok { - cell = &grid.CellData{Key: idx, Tasks: grid.TaskList{t}} - data.Cells[idx] = cell - } else { - cell.Tasks = append(cell.Tasks, t) - } - } - - g.SetData(data, v.column.sort, v.row.sort) -} - -type controller struct { - tasks []*task - free map[*filter]*filter - v *view - g *grid.Grid -} - -func newController(tasks []*task) *controller { - return &controller{ - tasks: tasks, - free: map[*filter]*filter{}, - v: newView(), - g: nil, - } -} - -func (c *controller) nextFree() *filter { - for _, k := range c.free { - return k - } - return nil -} - -func (c *controller) resolveFilter(changed *filter) { - switch changed.selecter.Value { - case c.v.optAllValue(): - c.free[changed] = changed - case c.v.optXAxisValue(), c.v.optYAxisValue(): - if axis := c.v.setAxis(changed); axis != nil { - c.free[axis] = axis - delete(c.free, changed) - } - default: - delete(c.free, changed) - } -} - -func (c *controller) resolveAxis(oldAxis *filter, newValue string) *filter { - if f := c.nextFree(); f != nil { - switch oldAxis.selecter.Value { - case c.v.optXAxisValue(): - f.selecter.Value = c.v.optXAxisValue() - case c.v.optYAxisValue(): - f.selecter.Value = c.v.optYAxisValue() - default: - return nil - } - c.resolveFilter(f) - c.setFilterValue(oldAxis, newValue) - return f - } - return nil -} - -func (c *controller) setFilterValue(f *filter, newValue string) { - if c.v.column == f || c.v.row == f { - c.resolveAxis(f, newValue) - } else { - f.selecter.Value = newValue - c.resolveFilter(f) - } -} - -func (c *controller) addDimension(d *dimension) { - filter := c.v.addFilter(d) - - c.resolveFilter(filter) - - filter.selecter.OnChange(func() { - c.resolveFilter(filter) - c.commitViewState() - }) -} - -func (c *controller) addGrid() { - c.g = grid.New() - - c.g.OnColumnClicked = func(k grid.Key, _ *grid.HeaderData) { - c.resolveAxis(c.v.column, k.(string)) - c.commitViewState() - } - c.g.OnRowClicked = func(k grid.Key, _ *grid.HeaderData) { - c.resolveAxis(c.v.row, k.(string)) - c.commitViewState() - } - c.g.OnCellClicked = func(i grid.CellIndex, d *grid.CellData) { - if len(d.Tasks) == 1 { - t := d.Tasks[0].Data.(*task) - c.v.objView.Set(t.kind.Display(), t, c.v.formatters) - return - } - c.resolveAxis(c.v.column, i.Column.(string)) - c.resolveAxis(c.v.row, i.Row.(string)) - c.commitViewState() - } - - c.v.div.Append(c.g) -} - -func (c *controller) commitViewState() { - c.v.refreshGrid(c.tasks, c.g) - - if c.v.column == nil || c.v.row == nil { - panic("column or row not set! This should not happen.") - } - - parts := []string{} - parts = append(parts, "columns="+c.v.column.dim.name) - parts = append(parts, "rows="+c.v.row.dim.name) - for _, f := range c.v.filters { - if _, ok := c.free[f]; !ok { - parts = append(parts, f.dim.name+"="+f.selecter.Value) - } - } - dom.Win.Location.Hash = strings.Join(parts, "&") -} - -func (c *controller) decodeViewState() { - s := strings.TrimLeft(dom.Win.Location.Hash, "#") - vals := map[string]string{} - for _, s := range strings.Split(s, "&") { - pair := strings.Split(s, "=") - if len(pair) != 2 { - continue - } - vals[pair[0]] = string(pair[1]) - } - - for _, f := range c.v.filters { - if name, ok := vals["columns"]; ok && f.dim.name == string(name) { - c.setFilterValue(f, c.v.optXAxisValue()) - } else if name, ok := vals["rows"]; ok && f.dim.name == string(name) { - c.setFilterValue(f, c.v.optYAxisValue()) - } else if value, ok := vals[f.dim.name]; ok { - c.setFilterValue(f, value) - } else { - c.setFilterValue(f, c.v.optAllValue()) - } - } - - c.commitViewState() - dom.Win.Location.OnHashChange(func(dom.HashChangeEvent) { c.decodeViewState() }) -} - -func setupController(tasks []*task) *controller { - c := newController(tasks) - for _, d := range dimensions { - c.addDimension(d) - } - c.addGrid() - c.commitViewState() - c.decodeViewState() - return c -} - -func main() { - dom.Win.OnLoad(func() { - go func() { - var seenSeq int64 = -1 - var c *controller - for ticker := time.Tick(time.Second * 10); true; <-ticker { - // TODO: error handling so we can come back on server restart - seenData := queryObject(fmt.Sprintf("/status/?seen=%d", seenSeq)) - receivedSeq := (int64)(seenData["seq"].(float64)) - if seenSeq != receivedSeq { - seenSeq = receivedSeq - - clearDimensionData() - tasks := getRobotTasks() - - if c == nil { - c = setupController(tasks) - } else { - c.tasks = tasks - c.v.refreshGrid(c.tasks, c.g) - } - } - } - }() - }) -} diff --git a/test/robot/web/client/data.go b/test/robot/web/client/data.go deleted file mode 100644 index be1404763a..0000000000 --- a/test/robot/web/client/data.go +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "html/template" - "io/ioutil" - "net/http" - "reflect" - "time" - - "os" - - "github.com/google/gapid/test/robot/web/client/widgets/grid" -) - -type trackInfo struct { - track Item - packageDisplayToOrder map[string]int - packageList []string - headPackage string -} - -var ( - traceKind = item{id: "trace"} - reportKind = item{id: "report"} - replayKind = item{id: "replay"} - - packageDisplayTemplate = "{{if .information.tag}}{{.information.tag}}" + - "{{else if and (isUserType .information.type) (.information.cl)}}{{.information.cl}}" + - "{{else if .information.uploader}}{{.information.uploader}} - {{.id}}" + - "{{else}}unknown - {{.id}}" + - "{{end}}" - - machineDisplayTemplate = "{{if .information.Name}}{{.information.Name}}" + - "{{else if .information.Configuration.Hardware.Name}}{{.information.Configuration.Hardware.Name}}" + - "{{else}}{{.information.Configuration.OS}} - {{.information.id.data}}" + - "{{end}}" - - kindDimension = &dimension{ - name: "kind", - enumData: enum{traceKind, replayKind, reportKind}, - valueOf: func(t *task) Item { - return t.kind - }, - } - subjectDimension = &dimension{ - name: "subject", - valueOf: func(t *task) Item { - return t.trace.subject - }, - enumSrc: func() enum { - return itemGetter("{{.id}}", "{{.Information.APK.package}}", template.FuncMap{})(queryArray("/subjects/")) - }, - } - targetDimension = &dimension{ - name: "traceTarget", - valueOf: func(t *task) Item { - return t.trace.target - }, - enumSrc: func() enum { - result := enum{} - devices := itemGetter("{{.id}}", machineDisplayTemplate, template.FuncMap{})(queryArray("/devices/")) - targets := itemGetter("{{.target}}", "{{.target}}", template.FuncMap{})(queryArray("/workers/")) - for _, d := range devices { - for _, t := range targets { - if d.Id() == t.Id() { - result = append(result, d) - break - } - } - } - return result - }, - } - hostDimension = &dimension{ - name: "host", - valueOf: func(t *task) Item { - return t.host - }, - enumSrc: func() enum { - result := enum{} - devices := itemGetter("{{.id}}", machineDisplayTemplate, template.FuncMap{})(queryArray("/devices/")) - hosts := itemGetter("{{.host}}", "{{.host}}", template.FuncMap{})(queryArray("/workers/")) - for _, d := range devices { - for _, h := range hosts { - if d.Id() == h.Id() { - result = append(result, d) - break - } - } - } - return result - }, - } - - tracks = map[string]*trackInfo{"auto": &trackInfo{ - track: item{ - id: "", - display: "auto", - underlying: map[string]string{"id": "", "name": "auto", "head": ""}, - }, - packageList: []string{}, - headPackage: "", - }} - packageDisplayToOrder = map[string]int{} - packageToTrack = map[string]*trackInfo{} - - packageDimension = &dimension{ - name: "package", - valueOf: func(t *task) Item { - return t.pkg - }, - enumSrc: func() enum { - result := itemGetter("{{.id}}", packageDisplayTemplate, template.FuncMap{"isUserType": isUserType})(queryArray("/packages/")) - trackItems := itemGetter("{{.id}}", "{{.name}}", template.FuncMap{})(queryArray("/tracks/")) - itemMap := map[string]Item{} - childMap := map[string]string{} - rootPkgs := []string{} - for _, it := range result { - pkgRoot := it.Underlying().(map[string]interface{}) - pkgID, ok := pkgRoot["id"].(string) - itemMap[pkgID] = it - if !ok { - continue - } - if parentMem, ok := pkgRoot["parent"]; ok { - parentID, ok := parentMem.(string) - if !ok { - continue - } - childMap[parentID] = pkgID - } else { - rootPkgs = append(rootPkgs, pkgID) - } - } - for _, root := range rootPkgs { - packageList := []string{} - packageDisplayToOrder[itemMap[root].Display()] = len(packageDisplayToOrder) - packageList = append(packageList, root) - for childID, ok := childMap[root]; ok; childID, ok = childMap[root] { - packageDisplayToOrder[itemMap[childID].Display()] = len(packageDisplayToOrder) - // want tracks stored from Root -> Head - packageList = append(packageList, childID) - root = childID - } - - head := root - foundTrack := false - for _, destTrackItem := range trackItems { - destTrack := destTrackItem.Underlying().(map[string]interface{}) - trackHead, ok := destTrack["head"].(string) - if !ok { - continue - } - if trackHead == head { - if trackName, ok := destTrack["name"].(string); ok { - tInfo := &trackInfo{ - track: destTrackItem, - packageList: packageList, - headPackage: head, - } - tracks[trackName] = tInfo - for _, p := range packageList { - packageToTrack[p] = tInfo - } - foundTrack = true - break - } - } - } - if !foundTrack { - // We append all packages to the "auto" track that didn't match an existing track - tracks["auto"].packageList = append(tracks["auto"].packageList, packageList...) - tracks["auto"].headPackage = packageList[len(packageList)-1] - } - } - return result - }, - enumSort: func(a, b string) bool { - if ao, ok := packageDisplayToOrder[a]; ok { - if bo, ok := packageDisplayToOrder[b]; ok { - return ao < bo - } - } - return a < b - }, - defVal: func() string { - if m, found := tracks["master"]; found { - return m.headPackage - } else if len(tracks["auto"].packageList) != 0 { - return tracks["auto"].headPackage - } else { - return "" - } - }, - } - - trackDimension = &dimension{ - name: "track", - valueOf: func(t *task) Item { - tInfo, ok := packageToTrack[t.pkg.Id()] - if !ok { - return tracks["auto"].track - } - return tInfo.track - }, - enumSrc: func() enum { - // Ensure the tracks are properly initialized. - packageDimension.getEnum() - var result enum - for _, it := range tracks { - trackItem := it.track - result = append(result, trackItem) - } - return result - }, - defVal: func() string { - if m, found := tracks["master"]; found { - return m.track.Id() - } else if len(tracks["auto"].packageList) != 0 { - return tracks["auto"].track.Id() - } else { - return "" - } - }, - } - - dimensions = []*dimension{kindDimension, subjectDimension, packageDimension, trackDimension, targetDimension, hostDimension} -) - -func isUserType(t reflect.Value) bool { - // cannot currently use build.Type_UserType to check the type need to fix that. - return t.Kind() == reflect.Float64 && t.Float() == float64(2) -} - -func itemGetter(idPattern string, displayPattern string, functions template.FuncMap) func([]interface{}) enum { - mustTemplate := func(s string) *template.Template { - return template.Must(template.New(fmt.Sprintf("t%d", time.Now().Unix())).Funcs(functions).Parse(s)) - } - exec := func(t *template.Template, item interface{}) string { - var b bytes.Buffer - t.Execute(&b, item) - return b.String() - } - idt := mustTemplate(idPattern) - dispt := mustTemplate(displayPattern) - return func(entries []interface{}) enum { - result := enum{} - for _, it := range entries { - result = append(result, item{id: exec(idt, it), display: exec(dispt, it), underlying: it}) - } - return result - } -} - -func queryRestEndpointWithCutoff(path string, cutoff int64) ([]byte, error) { - head, err := http.Head(path) - if err != nil { - return nil, err - } else if head.ContentLength > cutoff { - return nil, fmt.Errorf("Content Length (%d) is larger than cutoff (%d)", head.ContentLength, cutoff) - } - return queryRestEndpoint(path) -} - -func queryRestEndpoint(path string) ([]byte, error) { - resp, err := http.Get(path) - if err != nil { - return nil, err - } - defer resp.Body.Close() - return ioutil.ReadAll(resp.Body) -} - -func queryArray(path string) []interface{} { - // TODO: Cache this, as we're using the same path for multiple dimensions. - body, err := queryRestEndpoint(path) - if err != nil { - panic(err) - } - - arr := []interface{}{} - if err := json.Unmarshal(body, &arr); err != nil { - panic(err) - } - return arr -} - -func queryObject(path string) map[string]interface{} { - resp, err := http.Get(path) - if err != nil { - panic(err) - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - panic(err) - } - - arr := map[string]interface{}{} - if err := json.Unmarshal(body, &arr); err != nil { - panic(err) - } - return arr -} - -func clearDimensionData() { - for _, d := range dimensions { - if d.enumSrc != nil { - d.enumData = nil - } - d.itemMap = nil - } -} - -func newTask(entry map[string]interface{}, kind Item) *task { - t := &task{ - underlying: entry, - trace: traceInfo{target: nilItem, subject: nilItem}, - kind: kind, - host: nilItem, - pkg: nilItem, - parent: nil, - } - - if st, ok := entry["status"].(float64); ok { - switch int(st) { - case 1: - t.status = grid.InProgress - t.result = grid.Unknown - case 2: - t.status = grid.Current - t.result = grid.Succeeded - case 3: - t.status = grid.Current - t.result = grid.Failed - } - } else { - t.status = grid.Stale - t.result = grid.Unknown - } - return t -} - -func compareTasksSimilar(t1 *task, t2 *task) bool { - // similar tasks can have different packages, but have the same target, subject, and host. - if t1.trace.target.Id() == t2.trace.target.Id() && t1.trace.subject.Id() == t2.trace.subject.Id() && t1.host.Id() == t2.host.Id() { - return true - } - return false -} - -func connectTaskParentChild(childListMap map[string][]*task, parentListMap map[string][]*task, t *task) { - findParentPkgIdInList := func(idList []string, childId string) string { - // it is the index of id's parent. - for it, id := range idList[1:] { - if childId == id { - return idList[it] - } - } - return "" - } - pkgId := t.pkg.Id() - parentListMap[pkgId] = append(parentListMap[pkgId], t) - - if parPkgId := findParentPkgIdInList(packageToTrack[pkgId].packageList, pkgId); parPkgId != "" { - childListMap[parPkgId] = append(childListMap[parPkgId], t) - - if parentList, ok := parentListMap[parPkgId]; ok { - for _, parent := range parentList { - if compareTasksSimilar(t, parent) { - t.parent = parent - } - } - } - } - - if childList, ok := childListMap[pkgId]; ok { - for _, child := range childList { - if compareTasksSimilar(t, child) { - if child.parent != nil { - fmt.Fprintf(os.Stderr, "A task's parent was found twice? parent package id: %v; child package id: %v", pkgId, child.pkg.Id()) - } else { - child.parent = t - } - } - } - } -} - -func robotTasksPerKind(kind Item, path string, fun func(map[string]interface{}, *task)) []*task { - tasks := []*task{} - notCurrentTasks := []*task{} - currentTasks := []*task{} - childMap := map[string][]*task{} - parentMap := map[string][]*task{} - - for _, e := range queryArray(path) { - e := e.(map[string]interface{}) - t := newTask(e, kind) - fun(e, t) - connectTaskParentChild(childMap, parentMap, t) - tasks = append(tasks, t) - if t.status != grid.Current { - notCurrentTasks = append(notCurrentTasks, t) - } else { - currentTasks = append(currentTasks, t) - } - } - for _, t := range notCurrentTasks { - if t.parent != nil { - t.result = t.parent.result - } - } - for _, t := range currentTasks { - if t.parent != nil && t.parent.result != t.result { - t.status = grid.Changed - } - } - return tasks -} - -func getRobotTasks() []*task { - traceMap := map[string]*task{} - tasks := []*task{} - - traceProc := func(e map[string]interface{}, t *task) { - ei := e["input"].(map[string]interface{}) - t.trace = traceInfo{ - target: targetDimension.GetItem(e["target"]), - subject: subjectDimension.GetItem(ei["subject"]), - } - t.host = hostDimension.GetItem(e["host"]) - t.pkg = packageDimension.GetItem(ei["package"]) - if eo := e["output"]; eo != nil { - if traceOutput := eo.(map[string]interface{})["trace"]; traceOutput != nil { - traceMap[traceOutput.(string)] = t - } - } - } - tasks = append(tasks, robotTasksPerKind(traceKind, "/traces/", traceProc)...) - - subTaskProc := func(e map[string]interface{}, t *task) { - ei := (e["input"].(map[string]interface{})) - id := ei["trace"].(string) - if traceTask, found := traceMap[id]; found { - t.trace = traceTask.trace - } else { - fmt.Fprintf(os.Stderr, "Trace %s not found when processing action\n", id) - } - t.host = hostDimension.GetItem(e["host"]) - t.pkg = packageDimension.GetItem(ei["package"]) - } - tasks = append(tasks, robotTasksPerKind(replayKind, "/replays/", subTaskProc)...) - tasks = append(tasks, robotTasksPerKind(reportKind, "/reports/", subTaskProc)...) - - return tasks -} diff --git a/test/robot/web/client/dom/a.go b/test/robot/web/client/dom/a.go deleted file mode 100644 index c7ac260a76..0000000000 --- a/test/robot/web/client/dom/a.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dom - -// A represents an HTML element. -type A struct{ *Element } - -// NewA returns a new A element. -func NewA() *A { return &A{newEl("a")} } diff --git a/test/robot/web/client/dom/button.go b/test/robot/web/client/dom/button.go deleted file mode 100644 index c48276f31e..0000000000 --- a/test/robot/web/client/dom/button.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package dom - -// Button represents an HTML