Roll external/skia 87224bbed..bef05a6db (9 commits)
https://skia.googlesource.com/skia.git/+log/87224bbed..bef05a6db
2019-05-23 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial).
2019-05-23 bsalomon@google.com Disable two new tests on two bots while errors investigated
2019-05-23 brianosman@google.com Interpreter: Disassemble during execution when TRACE is enabled
2019-05-23 brianosman@google.com Support larger compound types in the interpreter
2019-05-23 jvanverth@google.com Remove Metal Perf bot from MacBook Air
2019-05-23 bungeman@google.com Add test of char to glyph round tripping.
2019-05-23 reed@google.com split RGB into YUV planes
2019-05-23 fmalita@chromium.org [skottie] Clamp seek() to the valid frame range
2019-05-23 recipe-mega-autoroller@chops-service-accounts.iam.gserviceaccount.com Roll recipe dependencies (trivial).
The AutoRoll server is located here: https://autoroll-internal.skia.org/r/android-master-autoroll
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md
If the roll is causing failures, please contact the current sheriff, who should
be CC'd on the roll, and stop the roller if necessary.
Test: Presubmit checks will test this change.
Change-Id: I488d8837ed27547b51d92f7e3e61a49caef89ccd
Exempt-From-Owner-Approval: The autoroll bot does not require owner approval.
diff --git a/Android.bp b/Android.bp
index bc3286f..4e9f2d1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -271,6 +271,7 @@
"src/core/SkXfermode.cpp",
"src/core/SkXfermodeInterpretation.cpp",
"src/core/SkYUVASizeInfo.cpp",
+ "src/core/SkYUVMath.cpp",
"src/core/SkYUVPlanesCache.cpp",
"src/effects/Sk1DPathEffect.cpp",
"src/effects/Sk2DPathEffect.cpp",
diff --git a/gm/wacky_yuv_formats.cpp b/gm/wacky_yuv_formats.cpp
index ebe64ca..aeba7e9 100644
--- a/gm/wacky_yuv_formats.cpp
+++ b/gm/wacky_yuv_formats.cpp
@@ -1257,3 +1257,125 @@
DEF_GM(return new YUVMakeColorSpaceGM();)
}
+
+///////////////
+
+#include "tools/Resources.h"
+#include "src/core/SkYUVMath.h"
+#include "src/core/SkAutoPixmapStorage.h"
+#include "include/effects/SkColorMatrix.h"
+
+static void draw_into_alpha(const SkImage* img, sk_sp<SkColorFilter> cf, const SkPixmap& dst) {
+ auto canvas = SkCanvas::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes());
+ canvas->scale(1.0f * dst.width() / img->width(), 1.0f * dst.height() / img->height());
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setColorFilter(cf);
+ paint.setBlendMode(SkBlendMode::kSrc);
+ canvas->drawImage(img, 0, 0, &paint);
+}
+
+static void split_into_yuv(const SkImage* img, SkYUVColorSpace cs, const SkPixmap dst[3]) {
+ float m[20];
+ SkColorMatrix_RGB2YUV(cs, m);
+
+ memcpy(m + 15, m + 0, 5 * sizeof(float)); // copy Y into A
+ draw_into_alpha(img, SkColorFilters::Matrix(m), dst[0]);
+
+ memcpy(m + 15, m + 5, 5 * sizeof(float)); // copy U into A
+ draw_into_alpha(img, SkColorFilters::Matrix(m), dst[1]);
+
+ memcpy(m + 15, m + 10, 5 * sizeof(float)); // copy V into A
+ draw_into_alpha(img, SkColorFilters::Matrix(m), dst[2]);
+}
+
+static void draw_diff(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkImage* a, const SkImage* b) {
+ auto sh = SkShaders::Blend(SkBlendMode::kDifference, a->makeShader(), b->makeShader());
+ SkPaint paint;
+ paint.setShader(sh);
+ canvas->save();
+ canvas->translate(x, y);
+ canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
+
+ SkColorMatrix cm;
+ cm.setScale(64, 64, 64);
+ paint.setShader(sh->makeWithColorFilter(SkColorFilters::Matrix(cm)));
+ canvas->translate(0, a->height());
+ canvas->drawRect(SkRect::MakeWH(a->width(), a->height()), paint);
+
+ canvas->restore();
+}
+
+// Exercises SkColorMatrix_RGB2YUV for yuv colorspaces, showing the planes, and the
+// resulting (recombined) images (gpu only for now).
+//
+class YUVSplitterGM : public skiagm::GM {
+ sk_sp<SkImage> fOrig;
+ SkAutoPixmapStorage fStorage[3];
+ SkPixmap fPM[3];
+
+public:
+ YUVSplitterGM() {}
+
+protected:
+
+ SkString onShortName() override {
+ return SkString("yuv_splitter");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(1024, 768);
+ }
+
+ void onOnceBeforeDraw() override {
+ fOrig = GetResourceAsImage("images/mandrill_256.png");
+
+ SkImageInfo info = SkImageInfo::Make(fOrig->width(), fOrig->height(), kAlpha_8_SkColorType,
+ kPremul_SkAlphaType);
+ fStorage[0].alloc(info);
+ if (0) {
+ // if you want to scale U,V down by 1/2
+ info = info.makeWH(info.width()/2, info.height()/2);
+ }
+ fStorage[1].alloc(info);
+ fStorage[2].alloc(info);
+ for (int i = 0; i < 3; ++i) {
+ fPM[i] = fStorage[i];
+ }
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ SkYUVAIndex indices[4];
+ indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
+ indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
+ indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
+ indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
+
+ canvas->translate(fOrig->width(), 0);
+ canvas->save();
+ for (auto cs : {kRec709_SkYUVColorSpace, kRec601_SkYUVColorSpace, kJPEG_SkYUVColorSpace}) {
+ split_into_yuv(fOrig.get(), cs, fPM);
+ auto img = SkImage::MakeFromYUVAPixmaps(canvas->getGrContext(), cs, fPM, indices,
+ fPM[0].info().dimensions(),
+ kTopLeft_GrSurfaceOrigin,
+ false, false, nullptr);
+ if (img) {
+ canvas->drawImage(img, 0, 0, nullptr);
+ draw_diff(canvas, 0, fOrig->height(), fOrig.get(), img.get());
+ }
+ canvas->translate(fOrig->width(), 0);
+ }
+ canvas->restore();
+ canvas->translate(-fOrig->width(), 0);
+
+ canvas->drawImage(SkImage::MakeRasterCopy(fPM[0]), 0, 0, nullptr);
+ canvas->drawImage(SkImage::MakeRasterCopy(fPM[1]), 0, fPM[0].height(), nullptr);
+ canvas->drawImage(SkImage::MakeRasterCopy(fPM[2]),
+ 0, fPM[0].height() + fPM[1].height(), nullptr);
+ }
+
+private:
+ typedef GM INHERITED;
+};
+DEF_GM( return new YUVSplitterGM; )
diff --git a/gn/core.gni b/gn/core.gni
index 12c549c..3b9fe6e 100644
--- a/gn/core.gni
+++ b/gn/core.gni
@@ -403,6 +403,7 @@
"$_src/core/SkYUVPlanesCache.cpp",
"$_src/core/SkYUVPlanesCache.h",
"$_src/core/SkYUVASizeInfo.cpp",
+ "$_src/core/SkYUVMath.cpp",
"$_src/image/SkImage.cpp",
diff --git a/include/effects/SkColorMatrix.h b/include/effects/SkColorMatrix.h
index d7376bb..c86fb68 100644
--- a/include/effects/SkColorMatrix.h
+++ b/include/effects/SkColorMatrix.h
@@ -16,6 +16,14 @@
void setIdentity();
void setScale(float rScale, float gScale, float bScale, float aScale = 1.0f);
+ void setRowMajor(const float src[20]) {
+ memcpy(fMat, src, sizeof(fMat));
+ }
+
+ void getRowMajor(float dst[20]) const {
+ memcpy(dst, fMat, sizeof(fMat));
+ }
+
enum Axis {
kR_Axis = 0,
kG_Axis = 1,
diff --git a/infra/bots/jobs.json b/infra/bots/jobs.json
index 3e963f7..568f081 100644
--- a/infra/bots/jobs.json
+++ b/infra/bots/jobs.json
@@ -289,7 +289,6 @@
"Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Debug-All",
"Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All",
"Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-CommandBuffer",
- "Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal",
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All",
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All-ASAN",
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All-Vulkan",
diff --git a/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus5x-GPU-Adreno418-arm-Release-All-Android_Vulkan.json b/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus5x-GPU-Adreno418-arm-Release-All-Android_Vulkan.json
new file mode 100644
index 0000000..dbb8b37
--- /dev/null
+++ b/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus5x-GPU-Adreno418-arm-Release-All-Android_Vulkan.json
@@ -0,0 +1,1179 @@
+[
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "ensure-directory",
+ "--mode",
+ "0777",
+ "[START_DIR]/tmp"
+ ],
+ "infra_step": true,
+ "name": "makedirs tmp_dir"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "import os\nprint os.environ.get('SWARMING_BOT_ID', '')\n"
+ ],
+ "name": "get swarming bot id",
+ "stdout": "/path/to/tmp/",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_BOT_ID', '')@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "mkdir",
+ "-p",
+ "/sdcard/revenge_of_the_skiabot/resources"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "mkdir /sdcard/revenge_of_the_skiabot/resources"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nhost = sys.argv[1]\ndevice = sys.argv[2]\nfor d, _, fs in os.walk(host):\n p = os.path.relpath(d, host)\n if p != '.' and p.startswith('.'):\n continue\n for f in fs:\n print os.path.join(p,f)\n subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',\n os.path.realpath(os.path.join(host, p, f)),\n os.path.join(device, p, f)])\n",
+ "[START_DIR]/skia/resources",
+ "/sdcard/revenge_of_the_skiabot/resources"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/skia/resources/* /sdcard/revenge_of_the_skiabot/resources",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@host = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@device = sys.argv[2]@@@",
+ "@@@STEP_LOG_LINE@python.inline@for d, _, fs in os.walk(host):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ p = os.path.relpath(d, host)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if p != '.' and p.startswith('.'):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ continue@@@",
+ "@@@STEP_LOG_LINE@python.inline@ for f in fs:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print os.path.join(p,f)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.realpath(os.path.join(host, p, f)),@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.join(device, p, f)])@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/skia/infra/bots/assets/skp/VERSION",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "Get skp VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "42",
+ "[START_DIR]/tmp/SKP_VERSION"
+ ],
+ "infra_step": true,
+ "name": "write SKP_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "cat",
+ "/sdcard/revenge_of_the_skiabot/SKP_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "read /sdcard/revenge_of_the_skiabot/SKP_VERSION",
+ "stdout": "/path/to/tmp/"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-f",
+ "/sdcard/revenge_of_the_skiabot/SKP_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/SKP_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-rf",
+ "/sdcard/revenge_of_the_skiabot/skps"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/skps"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "mkdir",
+ "-p",
+ "/sdcard/revenge_of_the_skiabot/skps"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "mkdir /sdcard/revenge_of_the_skiabot/skps"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nhost = sys.argv[1]\ndevice = sys.argv[2]\nfor d, _, fs in os.walk(host):\n p = os.path.relpath(d, host)\n if p != '.' and p.startswith('.'):\n continue\n for f in fs:\n print os.path.join(p,f)\n subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',\n os.path.realpath(os.path.join(host, p, f)),\n os.path.join(device, p, f)])\n",
+ "[START_DIR]/skp",
+ "/sdcard/revenge_of_the_skiabot/skps"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/skp/* /sdcard/revenge_of_the_skiabot/skps",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@host = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@device = sys.argv[2]@@@",
+ "@@@STEP_LOG_LINE@python.inline@for d, _, fs in os.walk(host):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ p = os.path.relpath(d, host)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if p != '.' and p.startswith('.'):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ continue@@@",
+ "@@@STEP_LOG_LINE@python.inline@ for f in fs:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print os.path.join(p,f)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.realpath(os.path.join(host, p, f)),@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.join(device, p, f)])@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/tmp/SKP_VERSION",
+ "/sdcard/revenge_of_the_skiabot/SKP_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/tmp/SKP_VERSION /sdcard/revenge_of_the_skiabot/SKP_VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/skia/infra/bots/assets/skimage/VERSION",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "Get skimage VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "42",
+ "[START_DIR]/tmp/SK_IMAGE_VERSION"
+ ],
+ "infra_step": true,
+ "name": "write SK_IMAGE_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "cat",
+ "/sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "read /sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION",
+ "stdout": "/path/to/tmp/"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-f",
+ "/sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-rf",
+ "/sdcard/revenge_of_the_skiabot/images"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/images"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "mkdir",
+ "-p",
+ "/sdcard/revenge_of_the_skiabot/images"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "mkdir /sdcard/revenge_of_the_skiabot/images"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nhost = sys.argv[1]\ndevice = sys.argv[2]\nfor d, _, fs in os.walk(host):\n p = os.path.relpath(d, host)\n if p != '.' and p.startswith('.'):\n continue\n for f in fs:\n print os.path.join(p,f)\n subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',\n os.path.realpath(os.path.join(host, p, f)),\n os.path.join(device, p, f)])\n",
+ "[START_DIR]/skimage",
+ "/sdcard/revenge_of_the_skiabot/images"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/skimage/* /sdcard/revenge_of_the_skiabot/images",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@host = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@device = sys.argv[2]@@@",
+ "@@@STEP_LOG_LINE@python.inline@for d, _, fs in os.walk(host):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ p = os.path.relpath(d, host)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if p != '.' and p.startswith('.'):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ continue@@@",
+ "@@@STEP_LOG_LINE@python.inline@ for f in fs:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print os.path.join(p,f)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.realpath(os.path.join(host, p, f)),@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.join(device, p, f)])@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/tmp/SK_IMAGE_VERSION",
+ "/sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/tmp/SK_IMAGE_VERSION /sdcard/revenge_of_the_skiabot/SK_IMAGE_VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[START_DIR]/skia/infra/bots/assets/svg/VERSION",
+ "/path/to/tmp/"
+ ],
+ "infra_step": true,
+ "name": "Get svg VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "42",
+ "[START_DIR]/tmp/SVG_VERSION"
+ ],
+ "infra_step": true,
+ "name": "write SVG_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "cat",
+ "/sdcard/revenge_of_the_skiabot/SVG_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "read /sdcard/revenge_of_the_skiabot/SVG_VERSION",
+ "stdout": "/path/to/tmp/"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-f",
+ "/sdcard/revenge_of_the_skiabot/SVG_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/SVG_VERSION"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-rf",
+ "/sdcard/revenge_of_the_skiabot/svgs"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/svgs"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "mkdir",
+ "-p",
+ "/sdcard/revenge_of_the_skiabot/svgs"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "mkdir /sdcard/revenge_of_the_skiabot/svgs"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nhost = sys.argv[1]\ndevice = sys.argv[2]\nfor d, _, fs in os.walk(host):\n p = os.path.relpath(d, host)\n if p != '.' and p.startswith('.'):\n continue\n for f in fs:\n print os.path.join(p,f)\n subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',\n os.path.realpath(os.path.join(host, p, f)),\n os.path.join(device, p, f)])\n",
+ "[START_DIR]/svg",
+ "/sdcard/revenge_of_the_skiabot/svgs"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/svg/* /sdcard/revenge_of_the_skiabot/svgs",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@host = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@device = sys.argv[2]@@@",
+ "@@@STEP_LOG_LINE@python.inline@for d, _, fs in os.walk(host):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ p = os.path.relpath(d, host)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if p != '.' and p.startswith('.'):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ continue@@@",
+ "@@@STEP_LOG_LINE@python.inline@ for f in fs:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print os.path.join(p,f)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ subprocess.check_call(['/usr/bin/adb.1.0.35', 'push',@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.realpath(os.path.join(host, p, f)),@@@",
+ "@@@STEP_LOG_LINE@python.inline@ os.path.join(device, p, f)])@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/tmp/SVG_VERSION",
+ "/sdcard/revenge_of_the_skiabot/SVG_VERSION"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/tmp/SVG_VERSION /sdcard/revenge_of_the_skiabot/SVG_VERSION"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "rmtree",
+ "[START_DIR]/test"
+ ],
+ "infra_step": true,
+ "name": "rmtree test"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "ensure-directory",
+ "--mode",
+ "0777",
+ "[START_DIR]/test"
+ ],
+ "infra_step": true,
+ "name": "makedirs test"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "rm",
+ "-rf",
+ "/sdcard/revenge_of_the_skiabot/dm_out"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "rm /sdcard/revenge_of_the_skiabot/dm_out"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "shell",
+ "mkdir",
+ "-p",
+ "/sdcard/revenge_of_the_skiabot/dm_out"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "mkdir /sdcard/revenge_of_the_skiabot/dm_out"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport contextlib\nimport math\nimport socket\nimport sys\nimport time\nimport urllib2\n\nHASHES_URL = sys.argv[1]\nRETRIES = 5\nTIMEOUT = 60\nWAIT_BASE = 15\n\nsocket.setdefaulttimeout(TIMEOUT)\nfor retry in range(RETRIES):\n try:\n with contextlib.closing(\n urllib2.urlopen(HASHES_URL, timeout=TIMEOUT)) as w:\n hashes = w.read()\n with open(sys.argv[2], 'w') as f:\n f.write(hashes)\n break\n except Exception as e:\n print 'Failed to get uninteresting hashes from %s:' % HASHES_URL\n print e\n if retry == RETRIES:\n raise\n waittime = WAIT_BASE * math.pow(2, retry)\n print 'Retry in %d seconds.' % waittime\n time.sleep(waittime)\n",
+ "https://example.com/hashes.txt",
+ "[START_DIR]/tmp/uninteresting_hashes.txt"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "get uninteresting hashes",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import contextlib@@@",
+ "@@@STEP_LOG_LINE@python.inline@import math@@@",
+ "@@@STEP_LOG_LINE@python.inline@import socket@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@import urllib2@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@HASHES_URL = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@RETRIES = 5@@@",
+ "@@@STEP_LOG_LINE@python.inline@TIMEOUT = 60@@@",
+ "@@@STEP_LOG_LINE@python.inline@WAIT_BASE = 15@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@socket.setdefaulttimeout(TIMEOUT)@@@",
+ "@@@STEP_LOG_LINE@python.inline@for retry in range(RETRIES):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ try:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ with contextlib.closing(@@@",
+ "@@@STEP_LOG_LINE@python.inline@ urllib2.urlopen(HASHES_URL, timeout=TIMEOUT)) as w:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ hashes = w.read()@@@",
+ "@@@STEP_LOG_LINE@python.inline@ with open(sys.argv[2], 'w') as f:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ f.write(hashes)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ break@@@",
+ "@@@STEP_LOG_LINE@python.inline@ except Exception as e:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'Failed to get uninteresting hashes from %s:' % HASHES_URL@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print e@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if retry == RETRIES:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise@@@",
+ "@@@STEP_LOG_LINE@python.inline@ waittime = WAIT_BASE * math.pow(2, retry)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'Retry in %d seconds.' % waittime@@@",
+ "@@@STEP_LOG_LINE@python.inline@ time.sleep(waittime)@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/tmp/uninteresting_hashes.txt",
+ "/sdcard/revenge_of_the_skiabot/uninteresting_hashes.txt"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push [START_DIR]/tmp/uninteresting_hashes.txt /sdcard/revenge_of_the_skiabot/uninteresting_hashes.txt"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "import os\nprint os.environ.get('SWARMING_TASK_ID', '')\n"
+ ],
+ "name": "get swarming task id",
+ "stdout": "/path/to/tmp/",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_TASK_ID', '')@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\nvalue = int(sys.argv[3])\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\n# If we try to echo 1 to an already online cpu, adb returns exit code 1.\n# So, check the value before trying to write it.\nprior_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif prior_status == str(value):\n print 'CPU %d online already %d' % (cpu, value)\n sys.exit()\n\nsubprocess.check_output([ADB, 'shell', 'echo %s > '\n '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])\nactual_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif actual_status != str(value):\n raise Exception('(actual, expected) (%s, %d)'\n % (actual_status, value))\n",
+ "/usr/bin/adb.1.0.35",
+ "0",
+ "1"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Enabling CPU 0",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@value = int(sys.argv[3])@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@# If we try to echo 1 to an already online cpu, adb returns exit code 1.@@@",
+ "@@@STEP_LOG_LINE@python.inline@# So, check the value before trying to write it.@@@",
+ "@@@STEP_LOG_LINE@python.inline@prior_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if prior_status == str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'CPU %d online already %d' % (cpu, value)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit()@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo %s > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_status != str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %d)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_status, value))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\nvalue = int(sys.argv[3])\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\n# If we try to echo 1 to an already online cpu, adb returns exit code 1.\n# So, check the value before trying to write it.\nprior_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif prior_status == str(value):\n print 'CPU %d online already %d' % (cpu, value)\n sys.exit()\n\nsubprocess.check_output([ADB, 'shell', 'echo %s > '\n '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])\nactual_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif actual_status != str(value):\n raise Exception('(actual, expected) (%s, %d)'\n % (actual_status, value))\n",
+ "/usr/bin/adb.1.0.35",
+ "1",
+ "1"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Enabling CPU 1",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@value = int(sys.argv[3])@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@# If we try to echo 1 to an already online cpu, adb returns exit code 1.@@@",
+ "@@@STEP_LOG_LINE@python.inline@# So, check the value before trying to write it.@@@",
+ "@@@STEP_LOG_LINE@python.inline@prior_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if prior_status == str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'CPU %d online already %d' % (cpu, value)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit()@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo %s > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_status != str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %d)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_status, value))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\nvalue = int(sys.argv[3])\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\n# If we try to echo 1 to an already online cpu, adb returns exit code 1.\n# So, check the value before trying to write it.\nprior_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif prior_status == str(value):\n print 'CPU %d online already %d' % (cpu, value)\n sys.exit()\n\nsubprocess.check_output([ADB, 'shell', 'echo %s > '\n '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])\nactual_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif actual_status != str(value):\n raise Exception('(actual, expected) (%s, %d)'\n % (actual_status, value))\n",
+ "/usr/bin/adb.1.0.35",
+ "2",
+ "1"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Enabling CPU 2",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@value = int(sys.argv[3])@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@# If we try to echo 1 to an already online cpu, adb returns exit code 1.@@@",
+ "@@@STEP_LOG_LINE@python.inline@# So, check the value before trying to write it.@@@",
+ "@@@STEP_LOG_LINE@python.inline@prior_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if prior_status == str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'CPU %d online already %d' % (cpu, value)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit()@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo %s > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_status != str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %d)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_status, value))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\nvalue = int(sys.argv[3])\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\n# If we try to echo 1 to an already online cpu, adb returns exit code 1.\n# So, check the value before trying to write it.\nprior_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif prior_status == str(value):\n print 'CPU %d online already %d' % (cpu, value)\n sys.exit()\n\nsubprocess.check_output([ADB, 'shell', 'echo %s > '\n '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])\nactual_status = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()\nif actual_status != str(value):\n raise Exception('(actual, expected) (%s, %d)'\n % (actual_status, value))\n",
+ "/usr/bin/adb.1.0.35",
+ "3",
+ "1"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Enabling CPU 3",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@value = int(sys.argv[3])@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@# If we try to echo 1 to an already online cpu, adb returns exit code 1.@@@",
+ "@@@STEP_LOG_LINE@python.inline@# So, check the value before trying to write it.@@@",
+ "@@@STEP_LOG_LINE@python.inline@prior_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if prior_status == str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print 'CPU %d online already %d' % (cpu, value)@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit()@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo %s > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_status = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_status != str(value):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %d)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_status, value))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\ngov = sys.argv[3]\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\nsubprocess.check_output([ADB, 'shell', 'echo \"%s\" > '\n '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)])\nactual_gov = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip()\nif actual_gov != gov:\n raise Exception('(actual, expected) (%s, %s)'\n % (actual_gov, gov))\n",
+ "/usr/bin/adb.1.0.35",
+ "4",
+ "ondemand"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Set CPU 4's governor to ondemand",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@gov = sys.argv[3]@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo \"%s\" > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_gov = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_gov != gov:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %s)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_gov, gov))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nimport time\nADB = sys.argv[1]\ncpu = int(sys.argv[2])\ngov = sys.argv[3]\n\nlog = subprocess.check_output([ADB, 'root'])\n# check for message like 'adbd cannot run as root in production builds'\nprint log\nif 'cannot' in log:\n raise Exception('adb root failed')\n\nsubprocess.check_output([ADB, 'shell', 'echo \"%s\" > '\n '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)])\nactual_gov = subprocess.check_output([ADB, 'shell', 'cat '\n '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip()\nif actual_gov != gov:\n raise Exception('(actual, expected) (%s, %s)'\n % (actual_gov, gov))\n",
+ "/usr/bin/adb.1.0.35",
+ "0",
+ "ondemand"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "Set CPU 0's governor to ondemand",
+ "timeout": 30,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@import time@@@",
+ "@@@STEP_LOG_LINE@python.inline@ADB = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@cpu = int(sys.argv[2])@@@",
+ "@@@STEP_LOG_LINE@python.inline@gov = sys.argv[3]@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output([ADB, 'root'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@# check for message like 'adbd cannot run as root in production builds'@@@",
+ "@@@STEP_LOG_LINE@python.inline@print log@@@",
+ "@@@STEP_LOG_LINE@python.inline@if 'cannot' in log:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('adb root failed')@@@",
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_output([ADB, 'shell', 'echo \"%s\" > '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)])@@@",
+ "@@@STEP_LOG_LINE@python.inline@actual_gov = subprocess.check_output([ADB, 'shell', 'cat '@@@",
+ "@@@STEP_LOG_LINE@python.inline@ '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip()@@@",
+ "@@@STEP_LOG_LINE@python.inline@if actual_gov != gov:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ raise Exception('(actual, expected) (%s, %s)'@@@",
+ "@@@STEP_LOG_LINE@python.inline@ % (actual_gov, gov))@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/build/dm",
+ "/data/local/tmp/"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push dm"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "set -x; /data/local/tmp/dm --resourcePath /sdcard/revenge_of_the_skiabot/resources --skps /sdcard/revenge_of_the_skiabot/skps --images /sdcard/revenge_of_the_skiabot/images/dm --colorImages /sdcard/revenge_of_the_skiabot/images/colorspace --nameByHash --properties gitHash abc123 builder Test-Android-Clang-Nexus5x-GPU-Adreno418-arm-Release-All-Android_Vulkan buildbucket_build_id 123454321 task_id task_12345 swarming_bot_id skia-bot-123 swarming_task_id 123456 --svgs /sdcard/revenge_of_the_skiabot/svgs --key arch arm compiler Clang configuration Release cpu_or_gpu GPU cpu_or_gpu_value Adreno418 extra_config Android_Vulkan model Nexus5x os Android style default --uninterestingHashesFile /sdcard/revenge_of_the_skiabot/uninteresting_hashes.txt --writePath /sdcard/revenge_of_the_skiabot/dm_out --dont_write pdf --nocpu --config vk vkmsaa4 --src tests gm image colorImage svg --blacklist _ gm _ savelayer_clipmask _ test _ ReplaceSurfaceBackendTexture _ svg _ svgparse_ _ image gen_platf error _ test _ GrShape _ image _ interlaced1.png _ image _ interlaced2.png _ image _ interlaced3.png _ image _ .arw _ image _ .cr2 _ image _ .dng _ image _ .nef _ image _ .nrw _ image _ .orf _ image _ .raf _ image _ .rw2 _ image _ .pef _ image _ .srw _ image _ .ARW _ image _ .CR2 _ image _ .DNG _ image _ .NEF _ image _ .NRW _ image _ .ORF _ image _ .RAF _ image _ .RW2 _ image _ .PEF _ image _ .SRW _ gm _ encode-platform --match ~WritePixelsNonTextureMSAA_Gpu ~WritePixelsMSAA_Gpu --noRAW_threading --nonativeFonts --verbose; echo $? >/data/local/tmp/rc",
+ "[START_DIR]/tmp/dm.sh"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "write dm.sh"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "push",
+ "[START_DIR]/tmp/dm.sh",
+ "/data/local/tmp/"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "push dm.sh"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "logcat",
+ "-c"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "clear log"
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport subprocess\nimport sys\nbin_dir = sys.argv[1]\nsh = sys.argv[2]\nsubprocess.check_call(['/usr/bin/adb.1.0.35', 'shell', 'sh', bin_dir + sh])\ntry:\n sys.exit(int(subprocess.check_output(['/usr/bin/adb.1.0.35', 'shell', 'cat',\n bin_dir + 'rc'])))\nexcept ValueError:\n print \"Couldn't read the return code. Probably killed for OOM.\"\n sys.exit(1)\n",
+ "/data/local/tmp/",
+ "dm.sh"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "name": "dm",
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@bin_dir = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@sh = sys.argv[2]@@@",
+ "@@@STEP_LOG_LINE@python.inline@subprocess.check_call(['/usr/bin/adb.1.0.35', 'shell', 'sh', bin_dir + sh])@@@",
+ "@@@STEP_LOG_LINE@python.inline@try:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit(int(subprocess.check_output(['/usr/bin/adb.1.0.35', 'shell', 'cat',@@@",
+ "@@@STEP_LOG_LINE@python.inline@ bin_dir + 'rc'])))@@@",
+ "@@@STEP_LOG_LINE@python.inline@except ValueError:@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print \"Couldn't read the return code. Probably killed for OOM.\"@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sys.exit(1)@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [],
+ "name": "adb pull"
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "pull",
+ "/sdcard/revenge_of_the_skiabot/dm_out",
+ "[CLEANUP]/adb_pull_tmp_1"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "adb pull.pull /sdcard/revenge_of_the_skiabot/dm_out",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "glob",
+ "[CLEANUP]/adb_pull_tmp_1",
+ "dm_out/*"
+ ],
+ "infra_step": true,
+ "name": "adb pull.list pulled files",
+ "stdout": "/path/to/tmp/",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@",
+ "@@@STEP_LOG_LINE@glob@[CLEANUP]/adb_pull_tmp_1/1.png@@@",
+ "@@@STEP_LOG_LINE@glob@[CLEANUP]/adb_pull_tmp_1/2.png@@@",
+ "@@@STEP_LOG_END@glob@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[CLEANUP]/adb_pull_tmp_1/1.png",
+ "[START_DIR]/[SWARM_OUT_DIR]"
+ ],
+ "infra_step": true,
+ "name": "adb pull.copy 1.png",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "copy",
+ "[CLEANUP]/adb_pull_tmp_1/2.png",
+ "[START_DIR]/[SWARM_OUT_DIR]"
+ ],
+ "infra_step": true,
+ "name": "adb pull.copy 2.png",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py",
+ "--json-output",
+ "/path/to/tmp/json",
+ "rmtree",
+ "[CLEANUP]/adb_pull_tmp_1"
+ ],
+ "infra_step": true,
+ "name": "adb pull.rmtree [CLEANUP]/adb_pull_tmp_1",
+ "~followup_annotations": [
+ "@@@STEP_NEST_LEVEL@1@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "python",
+ "-u",
+ "\nimport os\nimport subprocess\nimport sys\nout = sys.argv[1]\nlog = subprocess.check_output(['/usr/bin/adb.1.0.35', 'logcat', '-d'])\nfor line in log.split('\\n'):\n tokens = line.split()\n if len(tokens) == 11 and tokens[-7] == 'F' and tokens[-3] == 'pc':\n addr, path = tokens[-2:]\n local = os.path.join(out, os.path.basename(path))\n if os.path.exists(local):\n sym = subprocess.check_output(['addr2line', '-Cfpe', local, addr])\n line = line.replace(addr, addr + ' ' + sym.strip())\n print line\n",
+ "[START_DIR]/build"
+ ],
+ "env": {
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "dump log",
+ "timeout": 300,
+ "~followup_annotations": [
+ "@@@STEP_LOG_LINE@python.inline@@@@",
+ "@@@STEP_LOG_LINE@python.inline@import os@@@",
+ "@@@STEP_LOG_LINE@python.inline@import subprocess@@@",
+ "@@@STEP_LOG_LINE@python.inline@import sys@@@",
+ "@@@STEP_LOG_LINE@python.inline@out = sys.argv[1]@@@",
+ "@@@STEP_LOG_LINE@python.inline@log = subprocess.check_output(['/usr/bin/adb.1.0.35', 'logcat', '-d'])@@@",
+ "@@@STEP_LOG_LINE@python.inline@for line in log.split('\\n'):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ tokens = line.split()@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if len(tokens) == 11 and tokens[-7] == 'F' and tokens[-3] == 'pc':@@@",
+ "@@@STEP_LOG_LINE@python.inline@ addr, path = tokens[-2:]@@@",
+ "@@@STEP_LOG_LINE@python.inline@ local = os.path.join(out, os.path.basename(path))@@@",
+ "@@@STEP_LOG_LINE@python.inline@ if os.path.exists(local):@@@",
+ "@@@STEP_LOG_LINE@python.inline@ sym = subprocess.check_output(['addr2line', '-Cfpe', local, addr])@@@",
+ "@@@STEP_LOG_LINE@python.inline@ line = line.replace(addr, addr + ' ' + sym.strip())@@@",
+ "@@@STEP_LOG_LINE@python.inline@ print line@@@",
+ "@@@STEP_LOG_END@python.inline@@@"
+ ]
+ },
+ {
+ "cmd": [
+ "/usr/bin/adb.1.0.35",
+ "kill-server"
+ ],
+ "cwd": "[START_DIR]/skia",
+ "env": {
+ "ADB_VENDOR_KEYS": "/home/chrome-bot/.android/adbkey",
+ "CHROME_HEADLESS": "1",
+ "PATH": "<PATH>:RECIPE_REPO[depot_tools]"
+ },
+ "infra_step": true,
+ "name": "kill adb server"
+ },
+ {
+ "jsonResult": null,
+ "name": "$result"
+ }
+]
\ No newline at end of file
diff --git a/infra/bots/recipes/test.expected/Test-Mac10.13-Clang-MacMini7.1-GPU-IntelIris5100-x86_64-Debug-All-CommandBuffer.json b/infra/bots/recipes/test.expected/Test-Mac10.13-Clang-MacMini7.1-GPU-IntelIris5100-x86_64-Debug-All-CommandBuffer.json
index 6732f78..1737d0d 100644
--- a/infra/bots/recipes/test.expected/Test-Mac10.13-Clang-MacMini7.1-GPU-IntelIris5100-x86_64-Debug-All-CommandBuffer.json
+++ b/infra/bots/recipes/test.expected/Test-Mac10.13-Clang-MacMini7.1-GPU-IntelIris5100-x86_64-Debug-All-CommandBuffer.json
@@ -266,6 +266,10 @@
"svg",
"--blacklist",
"_",
+ "test",
+ "_",
+ "AsyncReadPixels",
+ "_",
"svg",
"_",
"svgparse_",
diff --git a/infra/bots/recipes/test.py b/infra/bots/recipes/test.py
index 8b80854..3899a2b 100644
--- a/infra/bots/recipes/test.py
+++ b/infra/bots/recipes/test.py
@@ -232,6 +232,15 @@
'Chorizo' in bot):
blacklist(['_', 'gm', '_', 'savelayer_clipmask'])
+ # skbug.com/9124
+ if 'GPU' in bot and 'Nexus5x' in bot and "Vulkan" in bot and 'Release' in bot:
+ blacklist(['_', 'test', '_', 'ReplaceSurfaceBackendTexture'])
+
+
+ # skbug.com/9123
+ if 'CommandBuffer' in bot and 'IntelIris5100' in bot:
+ blacklist(['_', 'test', '_', 'AsyncReadPixels'])
+
# skbug.com/9043 - these devices render this test incorrectly
# when opList splitting reduction is enabled
if 'GPU' in bot and 'Vulkan' in bot and ('MoltenVK' in bot or
@@ -1091,6 +1100,7 @@
'Test-Win2016-Clang-GCE-CPU-AVX2-x86_64-Debug-All-FSAA',
'Test-Win2016-MSVC-GCE-CPU-AVX2-x86_64-Debug-All-MSRTC',
'Test-iOS-Clang-iPadPro-GPU-PowerVRGT7800-arm64-Release-All',
+ 'Test-Android-Clang-Nexus5x-GPU-Adreno418-arm-Release-All-Android_Vulkan',
]
diff --git a/infra/bots/tasks.json b/infra/bots/tasks.json
index c34c9f2..86dcc40 100755
--- a/infra/bots/tasks.json
+++ b/infra/bots/tasks.json
@@ -1464,11 +1464,6 @@
],
"trigger": "master"
},
- "Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal": {
- "tasks": [
- "Upload-Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal"
- ]
- },
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All": {
"tasks": [
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All"
@@ -36984,117 +36979,6 @@
"perf"
]
},
- "Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal": {
- "caches": [
- {
- "name": "vpython",
- "path": "cache/vpython"
- }
- ],
- "cipd_packages": [
- {
- "name": "infra/tools/luci/kitchen/${platform}",
- "path": ".",
- "version": "git_revision:d8f38ca9494b5af249942631f9cee45927f6b4bc"
- },
- {
- "name": "infra/tools/luci-auth/${platform}",
- "path": "cipd_bin_packages",
- "version": "git_revision:2c805f1c716f6c5ad2126b27ec88b8585a09481e"
- },
- {
- "name": "infra/tools/luci/vpython/${platform}",
- "path": "cipd_bin_packages",
- "version": "git_revision:96f81e737868d43124b4661cf1c325296ca04944"
- },
- {
- "name": "skia/bots/skimage",
- "path": "skimage",
- "version": "version:39"
- },
- {
- "name": "skia/bots/skp",
- "path": "skp",
- "version": "version:187"
- },
- {
- "name": "skia/bots/svg",
- "path": "svg",
- "version": "version:9"
- }
- ],
- "command": [
- "./kitchen${EXECUTABLE_SUFFIX}",
- "cook",
- "-checkout-dir",
- "recipe_bundle",
- "-mode",
- "swarming",
- "-luci-system-account",
- "system",
- "-cache-dir",
- "cache",
- "-temp-dir",
- "tmp",
- "-known-gerrit-host",
- "android.googlesource.com",
- "-known-gerrit-host",
- "boringssl.googlesource.com",
- "-known-gerrit-host",
- "chromium.googlesource.com",
- "-known-gerrit-host",
- "dart.googlesource.com",
- "-known-gerrit-host",
- "fuchsia.googlesource.com",
- "-known-gerrit-host",
- "go.googlesource.com",
- "-known-gerrit-host",
- "llvm.googlesource.com",
- "-known-gerrit-host",
- "skia.googlesource.com",
- "-known-gerrit-host",
- "webrtc.googlesource.com",
- "-output-result-json",
- "${ISOLATED_OUTDIR}/build_result_filename",
- "-workdir",
- ".",
- "-recipe",
- "perf",
- "-properties",
- "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"perf\",\"task_id\":\"<(TASK_ID)\"}",
- "-logdog-annotation-url",
- "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
- ],
- "dependencies": [
- "Housekeeper-PerCommit-BundleRecipes",
- "Build-Mac-Clang-x86_64-Release-Metal"
- ],
- "dimensions": [
- "gpu:8086:1626",
- "os:Mac-10.14.3",
- "pool:Skia"
- ],
- "env_prefixes": {
- "PATH": [
- "cipd_bin_packages",
- "cipd_bin_packages/bin"
- ],
- "VPYTHON_VIRTUALENV_ROOT": [
- "cache/vpython"
- ]
- },
- "execution_timeout_ns": 14400000000000,
- "expiration_ns": 72000000000000,
- "extra_tags": {
- "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
- },
- "io_timeout_ns": 14400000000000,
- "isolate": "perf_skia_bundled.isolate",
- "max_attempts": 2,
- "outputs": [
- "perf"
- ]
- },
"Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Debug-All": {
"caches": [
{
@@ -89526,106 +89410,6 @@
"max_attempts": 2,
"service_account": "skia-external-nano-uploader@skia-swarming-bots.iam.gserviceaccount.com"
},
- "Upload-Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal": {
- "caches": [
- {
- "name": "vpython",
- "path": "cache/vpython"
- }
- ],
- "cipd_packages": [
- {
- "name": "infra/tools/luci/kitchen/${platform}",
- "path": ".",
- "version": "git_revision:d8f38ca9494b5af249942631f9cee45927f6b4bc"
- },
- {
- "name": "infra/tools/luci-auth/${platform}",
- "path": "cipd_bin_packages",
- "version": "git_revision:2c805f1c716f6c5ad2126b27ec88b8585a09481e"
- },
- {
- "name": "infra/tools/luci/vpython/${platform}",
- "path": "cipd_bin_packages",
- "version": "git_revision:96f81e737868d43124b4661cf1c325296ca04944"
- },
- {
- "name": "infra/gsutil",
- "path": "cipd_bin_packages",
- "version": "version:4.28"
- }
- ],
- "command": [
- "./kitchen${EXECUTABLE_SUFFIX}",
- "cook",
- "-checkout-dir",
- "recipe_bundle",
- "-mode",
- "swarming",
- "-luci-system-account",
- "system",
- "-cache-dir",
- "cache",
- "-temp-dir",
- "tmp",
- "-known-gerrit-host",
- "android.googlesource.com",
- "-known-gerrit-host",
- "boringssl.googlesource.com",
- "-known-gerrit-host",
- "chromium.googlesource.com",
- "-known-gerrit-host",
- "dart.googlesource.com",
- "-known-gerrit-host",
- "fuchsia.googlesource.com",
- "-known-gerrit-host",
- "go.googlesource.com",
- "-known-gerrit-host",
- "llvm.googlesource.com",
- "-known-gerrit-host",
- "skia.googlesource.com",
- "-known-gerrit-host",
- "webrtc.googlesource.com",
- "-output-result-json",
- "${ISOLATED_OUTDIR}/build_result_filename",
- "-workdir",
- ".",
- "-recipe",
- "upload_nano_results",
- "-properties",
- "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal\",\"gs_bucket\":\"skia-perf\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\",\"task_id\":\"<(TASK_ID)\"}",
- "-logdog-annotation-url",
- "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
- ],
- "dependencies": [
- "Housekeeper-PerCommit-BundleRecipes",
- "Perf-Mac10.14-Clang-MacBookAir7.2-GPU-IntelHD6000-x86_64-Release-All-Metal"
- ],
- "dimensions": [
- "cpu:x86-64-Haswell_GCE",
- "gpu:none",
- "machine_type:n1-highmem-2",
- "os:Debian-9.8",
- "pool:Skia"
- ],
- "env_prefixes": {
- "PATH": [
- "cipd_bin_packages",
- "cipd_bin_packages/bin"
- ],
- "VPYTHON_VIRTUALENV_ROOT": [
- "cache/vpython"
- ]
- },
- "execution_timeout_ns": 3600000000000,
- "extra_tags": {
- "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations"
- },
- "io_timeout_ns": 3600000000000,
- "isolate": "swarm_recipe.isolate",
- "max_attempts": 2,
- "service_account": "skia-external-nano-uploader@skia-swarming-bots.iam.gserviceaccount.com"
- },
"Upload-Perf-Ubuntu18-Clang-Golo-GPU-QuadroP400-x86_64-Release-All": {
"caches": [
{
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 1956639..5dfaf07 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -14,12 +14,12 @@
"deps": {
"depot_tools": {
"branch": "master",
- "revision": "181e44c231854a3f201ef0884f6f8462f321ea15",
+ "revision": "94515755316be3fb4fa59d984511c1aeaba40ffb",
"url": "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
},
"recipe_engine": {
"branch": "master",
- "revision": "71751d787ce1cce2996836a9af823cf961638ccf",
+ "revision": "96bcf6aaa92a254a19c1120b446dd6b35e8dc902",
"url": "https://chromium.googlesource.com/infra/luci/recipes-py.git"
}
},
diff --git a/modules/skottie/src/Skottie.cpp b/modules/skottie/src/Skottie.cpp
index 2f8d4f2..5ac0402 100644
--- a/modules/skottie/src/Skottie.cpp
+++ b/modules/skottie/src/Skottie.cpp
@@ -598,7 +598,10 @@
if (!fScene)
return;
- fScene->animate(fInPoint + SkTPin(t, 0.0f, 1.0f) * (fOutPoint - fInPoint));
+ // Per AE/Lottie semantics out_point is exclusive.
+ const auto kLastValidFrame = std::nextafter(fOutPoint, fInPoint);
+
+ fScene->animate(SkTPin(fInPoint + t * (fOutPoint - fInPoint), fInPoint, kLastValidFrame));
}
sk_sp<Animation> Animation::Make(const char* data, size_t length) {
diff --git a/src/core/SkYUVMath.cpp b/src/core/SkYUVMath.cpp
new file mode 100644
index 0000000..f074515
--- /dev/null
+++ b/src/core/SkYUVMath.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkYUVMath.h"
+#include "include/core/SkMatrix44.h"
+
+// in SkColorMatrix order (row-major)
+// Created by running SkColorMatrix_DumpYUVMatrixTables()
+
+const float Rec709_rgb_to_yuv[] = {
+ 0.182586f, 0.614231f, 0.062007f, 0.000000f, 0.062745f,
+ -0.100644f, -0.338572f, 0.439216f, 0.000000f, 0.501961f,
+ 0.439216f, -0.398942f, -0.040274f, 0.000000f, 0.501961f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+const float Rec709_yuv_to_rgb[] = {
+ 1.164384f, 0.000000f, 1.792741f, 0.000000f, -0.972945f,
+ 1.164384f, -0.213249f, -0.532909f, 0.000000f, 0.301483f,
+ 1.164384f, 2.112402f, 0.000000f, 0.000000f, -1.133402f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+const float Rec601_rgb_to_yuv[] = {
+ 0.256788f, 0.504129f, 0.097906f, 0.000000f, 0.062745f,
+ -0.148223f, -0.290993f, 0.439216f, 0.000000f, 0.501961f,
+ 0.439216f, -0.367788f, -0.071427f, 0.000000f, 0.501961f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+const float Rec601_yuv_to_rgb[] = {
+ 1.164384f, 0.000000f, 1.596027f, 0.000000f, -0.874202f,
+ 1.164384f, -0.391762f, -0.812968f, 0.000000f, 0.531668f,
+ 1.164384f, 2.017232f, 0.000000f, 0.000000f, -1.085631f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+const float JPEG_rgb_to_yuv[] = {
+ 0.299000f, 0.587000f, 0.114000f, 0.000000f, 0.000000f,
+ -0.168736f, -0.331264f, 0.500000f, 0.000000f, 0.501961f,
+ 0.500000f, -0.418688f, -0.081312f, 0.000000f, 0.501961f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+const float JPEG_yuv_to_rgb[] = {
+ 1.000000f, 0.000000f, 1.402000f, 0.000000f, -0.703749f,
+ 1.000000f, -0.344136f, -0.714136f, 0.000000f, 0.531211f,
+ 1.000000f, 1.772000f, 0.000000f, 0.000000f, -0.889475f,
+ 0.000000f, 0.000000f, 0.000000f, 1.000000f, 0.000000f,
+};
+
+static_assert(kJPEG_SkYUVColorSpace == 0, "");
+static_assert(kRec601_SkYUVColorSpace == 1, "");
+static_assert(kRec709_SkYUVColorSpace == 2, "");
+
+const float* yuv_to_rgb_array[] = {
+ JPEG_yuv_to_rgb,
+ Rec601_yuv_to_rgb,
+ Rec709_yuv_to_rgb,
+};
+
+const float* rgb_to_yuv_array[] = {
+ JPEG_rgb_to_yuv,
+ Rec601_rgb_to_yuv,
+ Rec709_rgb_to_yuv,
+};
+
+constexpr size_t kSizeOfColorMatrix = 20 * sizeof(float);
+
+void SkColorMatrix_RGB2YUV(SkYUVColorSpace cs, float m[20]) {
+ if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
+ memcpy(m, rgb_to_yuv_array[(unsigned)cs], kSizeOfColorMatrix);
+ } else {
+ memset(m, 0, kSizeOfColorMatrix);
+ m[0] = m[6] = m[12] = m[18] = 1;
+ }
+}
+
+void SkColorMatrix_YUV2RGB(SkYUVColorSpace cs, float m[20]) {
+ if ((unsigned)cs < (unsigned)kIdentity_SkYUVColorSpace) {
+ memcpy(m, yuv_to_rgb_array[(unsigned)cs], kSizeOfColorMatrix);
+ } else {
+ memset(m, 0, kSizeOfColorMatrix);
+ m[0] = m[6] = m[12] = m[18] = 1;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+// we just drop the alpha rol/col from the colormatrix
+// output is | tr |
+// | 3x3 tg |
+// | tb |
+// | 0 0 0 1 |
+static void colormatrix_to_matrix44(const float src[20], SkMatrix44* dst) {
+ for (int r = 0; r < 3; ++r) {
+ for (int c = 0; c < 3; ++c) {
+ dst->set(r, c, src[r*5 + c]);
+ }
+ dst->set(r, 3, src[r*5 + 4]);
+ }
+ dst->set(3, 0, 0);
+ dst->set(3, 1, 0);
+ dst->set(3, 2, 0);
+ dst->set(3, 3, 1);
+}
+
+// input: ignore the bottom row
+// output: inject identity row/column for alpha
+static void matrix44_to_colormatrix(const SkMatrix44& src, float dst[20]) {
+ for (int r = 0; r < 3; ++r) {
+ for (int c = 0; c < 3; ++c) {
+ dst[r*5 + c] = src.get(r, c);
+ }
+ dst[r*5 + 3] = 0; // scale alpha
+ dst[r*5 + 4] = src.get(r, 3); // translate
+ }
+ dst[15] = dst[16] = dst[17] = dst[19] = 0;
+ dst[18] = 1;
+}
+
+static void scale3(float m[], float s) {
+ for (int i = 0; i < 3; ++i) {
+ m[i] *= s;
+ }
+}
+
+namespace {
+struct YUVCoeff {
+ float Kr, Kb;
+ float Cr, Cb;
+ float scaleY, addY;
+ float scaleUV;
+};
+} // namespace
+
+const YUVCoeff gCoeff[] = {
+ // kJPEG_SkYUVColorSpace
+ { 0.299f, 0.114f, 1/1.772f, 1/1.402f, 1, 0, 1, },
+
+ // kRec601_SkYUVColorSpace
+ { 0.299f, 0.114f, 1/1.772f, 1/1.402f, 219/255.f, 16/255.f, 224/255.f, },
+
+ // kRec709_SkYUVColorSpace
+ { 0.2126f, 0.0722f, 1/1.8556f, 1/1.5748f, 219/255.f, 16/255.f, 224/255.f, },
+};
+
+static void make_rgb_to_yuv_matrix(float mx[20], const YUVCoeff& c) {
+ const float Kr = c.Kr;
+ const float Kb = c.Kb;
+ const float Kg = 1.0f - Kr - Kb;
+
+ float m[20] = {
+ Kr, Kg, Kb, 0, c.addY,
+ -Kr, -Kg, 1-Kb, 0, 128/255.f,
+ 1-Kr, -Kg, -Kb, 0, 128/255.f,
+ 0, 0, 0, 1, 0,
+ };
+ memcpy(mx, m, sizeof(m));
+ scale3(mx + 0, c.scaleY);
+ scale3(mx + 5, c.Cr * c.scaleUV);
+ scale3(mx + 10, c.Cb * c.scaleUV);
+}
+
+static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv) {
+ const char* names[] = {
+ "JPEG", "Rec601", "Rec709",
+ };
+ const char* dirnames[] = {
+ "yuv_to_rgb", "rgb_to_yuv",
+ };
+ SkDebugf("const float %s_%s[] = {\n", names[cs], dirnames[rgb2yuv]);
+ for (int i = 0; i < 4; ++i) {
+ SkDebugf(" ");
+ for (int j = 0; j < 5; ++j) {
+ SkDebugf(" %9.6ff,", m[i * 5 + j]);
+ }
+ SkDebugf("\n");
+ }
+ SkDebugf("};\n");
+}
+
+// Used to create the prebuilt tables for each colorspace.
+// Don't remove this function, in case we want to recompute those tables in the future.
+void SkColorMatrix_DumpYUVMatrixTables() {
+ for (auto cs : {kRec709_SkYUVColorSpace, kRec601_SkYUVColorSpace, kJPEG_SkYUVColorSpace}) {
+ float m[20];
+ make_rgb_to_yuv_matrix(m, gCoeff[(unsigned)cs]);
+ dump(m, cs, true);
+ SkMatrix44 m44, im44;
+ colormatrix_to_matrix44(m, &m44);
+ float im[20];
+#ifdef SK_DEBUG
+ // be sure our coversion between matrix44 and colormatrix is perfect
+ matrix44_to_colormatrix(m44, im);
+ SkASSERT(memcmp(m, im, sizeof(im)) == 0);
+#endif
+ SkAssertResult(m44.invert(&im44));
+ matrix44_to_colormatrix(im44, im);
+ dump(im, cs, false);
+ }
+}
diff --git a/src/core/SkYUVMath.h b/src/core/SkYUVMath.h
new file mode 100644
index 0000000..9ecd2c8
--- /dev/null
+++ b/src/core/SkYUVMath.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkYUVMath_DEFINED
+#define SkYUVMath_DEFINED
+
+#include "include/core/SkImageInfo.h"
+
+void SkColorMatrix_RGB2YUV(SkYUVColorSpace, float m[20]);
+void SkColorMatrix_YUV2RGB(SkYUVColorSpace, float m[20]);
+
+// Used to create the pre-compiled tables in SkYUVMath.cpp
+void SkColorMatrix_DumpYUVMatrixTables();
+
+#endif
diff --git a/src/image/SkImage_GpuYUVA.cpp b/src/image/SkImage_GpuYUVA.cpp
index 146e9f5..fb02f34 100644
--- a/src/image/SkImage_GpuYUVA.cpp
+++ b/src/image/SkImage_GpuYUVA.cpp
@@ -240,6 +240,10 @@
GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[],
const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin,
bool buildMips, bool limitToMaxTextureSize, sk_sp<SkColorSpace> imageColorSpace) {
+ if (!context) {
+ return nullptr; // until we impl this for raster backend
+ }
+
int numPixmaps;
if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numPixmaps)) {
return nullptr;
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
index ae53f6a..cd0f29a 100644
--- a/src/ports/SkFontHost_mac.cpp
+++ b/src/ports/SkFontHost_mac.cpp
@@ -1597,7 +1597,10 @@
if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) {
SkASSERT(glyphs[1] == 0);
SkASSERT(glyphs[0] < glyphCount);
- if (glyphToUnicode[glyphs[0]] == 0) {
+ // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support'
+ // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20?
+ // Prefer mappings to codepoints at or above 0x20.
+ if (glyphToUnicode[glyphs[0]] < 0x20) {
glyphToUnicode[glyphs[0]] = codepoint;
}
}
@@ -1605,8 +1608,6 @@
}
}
// Construct Glyph to Unicode table.
-// Unicode code points that require conjugate pairs in utf16 are not
-// supported.
static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
SkUnichar* glyphToUnicode) {
sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp
index 0d35136..111bebb 100644
--- a/src/ports/SkFontHost_win.cpp
+++ b/src/ports/SkFontHost_win.cpp
@@ -1889,7 +1889,27 @@
WORD outGlyphs[maxGlyphs];
WORD logClust[numWCHAR];
int numGlyphs;
- HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
+ SCRIPT_ANALYSIS& script = si[0].a;
+ script.eScript = SCRIPT_UNDEFINED;
+ script.fRTL = FALSE;
+ script.fLayoutRTL = FALSE;
+ script.fLinkBefore = FALSE;
+ script.fLinkAfter = FALSE;
+ script.fLogicalOrder = FALSE;
+ script.fNoGlyphIndex = FALSE;
+ script.s.uBidiLevel = 0;
+ script.s.fOverrideDirection = 0;
+ script.s.fInhibitSymSwap = TRUE;
+ script.s.fCharShape = FALSE;
+ script.s.fDigitSubstitute = FALSE;
+ script.s.fInhibitLigate = FALSE;
+ script.s.fDisplayZWG = TRUE;
+ script.s.fArabicNumContext = FALSE;
+ script.s.fGcpClusters = FALSE;
+ script.s.fReserved = 0;
+ script.s.fEngineReserved = 0;
+ // For the future, 0x80040200 from here is USP_E_SCRIPT_NOT_IN_FONT
+ HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &script,
outGlyphs, logClust, vsa, &numGlyphs),
"Could not shape character.");
if (1 == numGlyphs) {
diff --git a/src/sksl/SkSLByteCode.h b/src/sksl/SkSLByteCode.h
index 852b477..fe1474e 100644
--- a/src/sksl/SkSLByteCode.h
+++ b/src/sksl/SkSLByteCode.h
@@ -61,12 +61,18 @@
VECTOR(kDivideU),
// Duplicates the top stack value
VECTOR(kDup),
- // All kLoad* are followed by a byte indicating the local/global slot to load
+ // Followed by count byte. Duplicates that many values
+ kDupN,
+ // kLoad/kLoadGlobal are followed by a byte indicating the local/global slot to load
VECTOR(kLoad),
VECTOR(kLoadGlobal),
- // As above, then a count byte (1-4), and then one byte per swizzle component (0-3).
+ // As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3).
kLoadSwizzle,
kLoadSwizzleGlobal,
+ // kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a
+ // count byte, and get the slot to load from the top of the stack.
+ kLoadExtended,
+ kLoadExtendedGlobal,
VECTOR(kNegateF),
VECTOR(kNegateI),
VECTOR(kMultiplyF),
@@ -75,6 +81,8 @@
VECTOR(kOrB),
VECTOR(kOrI),
VECTOR(kPop),
+ // Followed by count byte
+ kPopN,
// Followed by a 32 bit value containing the value to push
kPushImmediate,
// Followed by a byte indicating external value to read
@@ -86,14 +94,20 @@
kReturn,
VECTOR(kSin),
VECTOR(kSqrt),
- // All kStore* are followed by a byte indicating the local/global slot to store
+ // kStore/kStoreGlobal are followed by a byte indicating the local/global slot to store
VECTOR(kStore),
VECTOR(kStoreGlobal),
- // As above, then a count byte (1-4), and then one byte per swizzle component (0-3).
+ // Fallback stores. Followed by count byte, and get the slot to store from the top of the stack
+ kStoreExtended,
+ kStoreExtendedGlobal,
+ // As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3).
// Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the
// number of swizzle components. After the store, all v's are popped from the stack.
kStoreSwizzle,
kStoreSwizzleGlobal,
+ // As above, but gets the store slot from the top of the stack (before values to be stored)
+ kStoreSwizzleIndirect,
+ kStoreSwizzleIndirectGlobal,
// Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first
// count byte provides the current vector size (the vector is the top n stack elements), and the
// second count byte provides the swizzle component count.
diff --git a/src/sksl/SkSLByteCodeGenerator.cpp b/src/sksl/SkSLByteCodeGenerator.cpp
index bc3aaea..0070674 100644
--- a/src/sksl/SkSLByteCodeGenerator.cpp
+++ b/src/sksl/SkSLByteCodeGenerator.cpp
@@ -21,8 +21,23 @@
fIntrinsics["tan"] = ByteCodeInstruction::kTan;
}
-static int slot_count(const Type& type) {
- return type.columns() * type.rows();
+int ByteCodeGenerator::SlotCount(const Type& type) {
+ if (type.kind() == Type::kStruct_Kind) {
+ int slots = 0;
+ for (const auto& f : type.fields()) {
+ slots += SlotCount(*f.fType);
+ }
+ SkASSERT(slots <= 255);
+ return slots;
+ } else if (type.kind() == Type::kArray_Kind) {
+ int columns = type.columns();
+ SkASSERT(columns >= 0);
+ int slots = columns * SlotCount(type.componentType());
+ SkASSERT(slots <= 255);
+ return slots;
+ } else {
+ return type.columns() * type.rows();
+ }
}
bool ByteCodeGenerator::generateCode() {
@@ -44,11 +59,11 @@
continue;
}
if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
- for (int i = slot_count(declVar->fType); i > 0; --i) {
+ for (int i = SlotCount(declVar->fType); i > 0; --i) {
fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
}
} else {
- fOutput->fGlobalCount += slot_count(declVar->fType);
+ fOutput->fGlobalCount += SlotCount(declVar->fType);
}
}
break;
@@ -70,7 +85,7 @@
std::unique_ptr<ByteCodeFunction> result(new ByteCodeFunction(&f.fDeclaration));
fParameterCount = 0;
for (const auto& p : f.fDeclaration.fParameters) {
- fParameterCount += p->fType.columns() * p->fType.rows();
+ fParameterCount += SlotCount(p->fType);
}
fCode = &result->fCode;
this->writeStatement(*f.fBody);
@@ -80,7 +95,7 @@
result->fLocalCount = fLocals.size();
const Type& returnType = f.fDeclaration.fReturnType;
if (returnType != *fContext.fVoid_Type) {
- result->fReturnCount = returnType.columns() * returnType.rows();
+ result->fReturnCount = SlotCount(returnType);
}
fLocals.clear();
fFunction = nullptr;
@@ -127,7 +142,7 @@
}
int result = fParameterCount + fLocals.size();
fLocals.push_back(&var);
- for (int i = 0; i < slot_count(var.fType) - 1; ++i) {
+ for (int i = 0; i < SlotCount(var.fType) - 1; ++i) {
fLocals.push_back(nullptr);
}
SkASSERT(result <= 255);
@@ -140,7 +155,7 @@
SkASSERT(offset <= 255);
return offset;
}
- offset += slot_count(p->fType);
+ offset += SlotCount(p->fType);
}
SkASSERT(false);
return 0;
@@ -159,7 +174,7 @@
SkASSERT(offset <= 255);
return offset;
}
- offset += slot_count(declVar->fType);
+ offset += SlotCount(declVar->fType);
}
}
}
@@ -172,6 +187,62 @@
}
}
+int ByteCodeGenerator::getLocation(const Expression& expr, Variable::Storage* storage) {
+ switch (expr.fKind) {
+ case Expression::kFieldAccess_Kind: {
+ const FieldAccess& f = (const FieldAccess&)expr;
+ int baseAddr = this->getLocation(*f.fBase, storage);
+ int offset = 0;
+ for (int i = 0; i < f.fFieldIndex; ++i) {
+ offset += SlotCount(*f.fBase->fType.fields()[i].fType);
+ }
+ if (baseAddr < 0) {
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(offset);
+ this->write(ByteCodeInstruction::kAddI);
+ return -1;
+ } else {
+ return baseAddr + offset;
+ }
+ }
+ case Expression::kIndex_Kind: {
+ const IndexExpression& i = (const IndexExpression&)expr;
+ int stride = SlotCount(i.fType);
+ int offset = -1;
+ if (i.fIndex->isConstant()) {
+ offset = i.fIndex->getConstantInt() * stride;
+ } else {
+ this->writeExpression(*i.fIndex);
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(stride);
+ this->write(ByteCodeInstruction::kMultiplyI);
+ }
+ int baseAddr = this->getLocation(*i.fBase, storage);
+ if (baseAddr >= 0 && offset >= 0) {
+ return baseAddr + offset;
+ }
+ if (baseAddr >= 0) {
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(baseAddr);
+ }
+ if (offset >= 0) {
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(offset);
+ }
+ this->write(ByteCodeInstruction::kAddI);
+ return -1;
+ }
+ case Expression::kVariableReference_Kind: {
+ const Variable& var = ((const VariableReference&)expr).fVariable;
+ *storage = var.fStorage;
+ return this->getLocation(var);
+ }
+ default:
+ SkASSERT(false);
+ return 0;
+ }
+}
+
void ByteCodeGenerator::write8(uint8_t b) {
fCode->push_back(b);
}
@@ -193,6 +264,7 @@
}
static ByteCodeInstruction vector_instruction(ByteCodeInstruction base, int count) {
+ SkASSERT(count >= 1 && count <= 4);
return ((ByteCodeInstruction) ((int) base + count - 1));
}
@@ -244,7 +316,7 @@
this->write(ByteCodeInstruction::kDup);
}
}
- int count = slot_count(b.fType);
+ int count = SlotCount(b.fType);
switch (op) {
case Token::Kind::EQEQ:
this->writeTypedInstruction(b.fLeft->fType, ByteCodeInstruction::kCompareIEQ,
@@ -364,12 +436,12 @@
int argumentCount = 0;
for (const auto& arg : f.fArguments) {
this->writeExpression(*arg);
- argumentCount += slot_count(arg->fType);
+ argumentCount += SlotCount(arg->fType);
}
this->write(ByteCodeInstruction::kCallExternal);
SkASSERT(argumentCount <= 255);
this->write8(argumentCount);
- this->write8(slot_count(f.fType));
+ this->write8(SlotCount(f.fType));
int index = fOutput->fExternalValues.size();
fOutput->fExternalValues.push_back(f.fFunction);
SkASSERT(index <= 255);
@@ -378,16 +450,32 @@
void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) {
this->write(vector_instruction(ByteCodeInstruction::kReadExternal,
- slot_count(e.fValue->type())));
+ SlotCount(e.fValue->type())));
int index = fOutput->fExternalValues.size();
fOutput->fExternalValues.push_back(e.fValue);
SkASSERT(index <= 255);
this->write8(index);
}
-void ByteCodeGenerator::writeFieldAccess(const FieldAccess& f) {
- // not yet implemented
- abort();
+void ByteCodeGenerator::writeVariableExpression(const Expression& expr) {
+ Variable::Storage storage;
+ int location = this->getLocation(expr, &storage);
+ bool isGlobal = storage == Variable::kGlobal_Storage;
+ int count = SlotCount(expr.fType);
+ if (location < 0 || count > 4) {
+ if (location >= 0) {
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(location);
+ }
+ this->write(isGlobal ? ByteCodeInstruction::kLoadExtendedGlobal
+ : ByteCodeInstruction::kLoadExtended);
+ this->write8(count);
+ } else {
+ this->write(vector_instruction(isGlobal ? ByteCodeInstruction::kLoadGlobal
+ : ByteCodeInstruction::kLoad,
+ count));
+ this->write8(location);
+ }
}
void ByteCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
@@ -408,7 +496,7 @@
case ByteCodeInstruction::kTan:
SkASSERT(c.fArguments.size() == 1);
this->write((ByteCodeInstruction) ((int) found->second +
- slot_count(c.fArguments[0]->fType) - 1));
+ SlotCount(c.fArguments[0]->fType) - 1));
break;
default:
SkASSERT(false);
@@ -427,11 +515,6 @@
fCallTargets.emplace_back(this, f.fFunction);
}
-void ByteCodeGenerator::writeIndexExpression(const IndexExpression& i) {
- // not yet implemented
- abort();
-}
-
void ByteCodeGenerator::writeIntLiteral(const IntLiteral& i) {
this->write(ByteCodeInstruction::kPushImmediate);
this->write32(i.fValue);
@@ -446,7 +529,7 @@
switch (p.fOperator) {
case Token::Kind::PLUSPLUS: // fall through
case Token::Kind::MINUSMINUS: {
- SkASSERT(slot_count(p.fOperand->fType) == 1);
+ SkASSERT(SlotCount(p.fOperand->fType) == 1);
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
lvalue->load();
this->write(ByteCodeInstruction::kPushImmediate);
@@ -474,7 +557,7 @@
ByteCodeInstruction::kNegateI,
ByteCodeInstruction::kNegateI,
ByteCodeInstruction::kNegateF,
- slot_count(p.fOperand->fType));
+ SlotCount(p.fOperand->fType));
break;
}
default:
@@ -486,7 +569,7 @@
switch (p.fOperator) {
case Token::Kind::PLUSPLUS: // fall through
case Token::Kind::MINUSMINUS: {
- SkASSERT(slot_count(p.fOperand->fType) == 1);
+ SkASSERT(SlotCount(p.fOperand->fType) == 1);
std::unique_ptr<LValue> lvalue = this->getLValue(*p.fOperand);
lvalue->load();
this->write(ByteCodeInstruction::kDup);
@@ -540,14 +623,6 @@
}
}
-void ByteCodeGenerator::writeVariableReference(const VariableReference& v) {
- this->write(vector_instruction(v.fVariable.fStorage == Variable::kGlobal_Storage
- ? ByteCodeInstruction::kLoadGlobal
- : ByteCodeInstruction::kLoad,
- slot_count(v.fType)));
- this->write8(this->getLocation(v.fVariable));
-}
-
void ByteCodeGenerator::writeTernaryExpression(const TernaryExpression& t) {
this->writeExpression(*t.fTest);
this->write(ByteCodeInstruction::kConditionalBranch);
@@ -578,7 +653,9 @@
this->writeExternalValue((ExternalValueReference&) e);
break;
case Expression::kFieldAccess_Kind:
- this->writeFieldAccess((FieldAccess&) e);
+ case Expression::kIndex_Kind:
+ case Expression::kVariableReference_Kind:
+ this->writeVariableExpression(e);
break;
case Expression::kFloatLiteral_Kind:
this->writeFloatLiteral((FloatLiteral&) e);
@@ -586,9 +663,6 @@
case Expression::kFunctionCall_Kind:
this->writeFunctionCall((FunctionCall&) e);
break;
- case Expression::kIndex_Kind:
- this->writeIndexExpression((IndexExpression&) e);
- break;
case Expression::kIntLiteral_Kind:
this->writeIntLiteral((IntLiteral&) e);
break;
@@ -604,9 +678,6 @@
case Expression::kSwizzle_Kind:
this->writeSwizzle((Swizzle&) e);
break;
- case Expression::kVariableReference_Kind:
- this->writeVariableReference((VariableReference&) e);
- break;
case Expression::kTernary_Kind:
this->writeTernaryExpression((TernaryExpression&) e);
break;
@@ -620,7 +691,7 @@
public:
ByteCodeExternalValueLValue(ByteCodeGenerator* generator, ExternalValue& value, int index)
: INHERITED(*generator)
- , fCount(slot_count(value.type()))
+ , fCount(ByteCodeGenerator::SlotCount(value.type()))
, fIndex(index) {}
void load() override {
@@ -646,22 +717,26 @@
public:
ByteCodeSwizzleLValue(ByteCodeGenerator* generator, const Swizzle& swizzle)
: INHERITED(*generator)
- , fSwizzle(swizzle) {
- SkASSERT(fSwizzle.fBase->fKind == Expression::kVariableReference_Kind);
- }
+ , fSwizzle(swizzle) {}
void load() override {
fGenerator.writeSwizzle(fSwizzle);
}
void store() override {
- const Variable& var = ((VariableReference&)*fSwizzle.fBase).fVariable;
fGenerator.write(vector_instruction(ByteCodeInstruction::kDup,
fSwizzle.fComponents.size()));
- fGenerator.write(var.fStorage == Variable::kGlobal_Storage
- ? ByteCodeInstruction::kStoreSwizzleGlobal
- : ByteCodeInstruction::kStoreSwizzle);
- fGenerator.write8(fGenerator.getLocation(var));
+ Variable::Storage storage;
+ int location = fGenerator.getLocation(*fSwizzle.fBase, &storage);
+ bool isGlobal = storage == Variable::kGlobal_Storage;
+ if (location < 0) {
+ fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleIndirectGlobal
+ : ByteCodeInstruction::kStoreSwizzleIndirect);
+ } else {
+ fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreSwizzleGlobal
+ : ByteCodeInstruction::kStoreSwizzle);
+ fGenerator.write8(location);
+ }
fGenerator.write8(fSwizzle.fComponents.size());
for (int c : fSwizzle.fComponents) {
fGenerator.write8(c);
@@ -674,36 +749,47 @@
typedef LValue INHERITED;
};
-class ByteCodeVariableLValue : public ByteCodeGenerator::LValue {
+class ByteCodeExpressionLValue : public ByteCodeGenerator::LValue {
public:
- ByteCodeVariableLValue(ByteCodeGenerator* generator, const Variable& var)
+ ByteCodeExpressionLValue(ByteCodeGenerator* generator, const Expression& expr)
: INHERITED(*generator)
- , fCount(slot_count(var.fType))
- , fLocation(generator->getLocation(var))
- , fIsGlobal(var.fStorage == Variable::kGlobal_Storage) {
- }
+ , fExpression(expr) {}
void load() override {
- fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kLoadGlobal
- : ByteCodeInstruction::kLoad,
- fCount));
- fGenerator.write8(fLocation);
+ fGenerator.writeVariableExpression(fExpression);
}
void store() override {
- fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, fCount));
- fGenerator.write(vector_instruction(fIsGlobal ? ByteCodeInstruction::kStoreGlobal
- : ByteCodeInstruction::kStore,
- fCount));
- fGenerator.write8(fLocation);
+ int count = ByteCodeGenerator::SlotCount(fExpression.fType);
+ if (count > 4) {
+ fGenerator.write(ByteCodeInstruction::kDupN);
+ fGenerator.write8(count);
+ } else {
+ fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count));
+ }
+ Variable::Storage storage;
+ int location = fGenerator.getLocation(fExpression, &storage);
+ bool isGlobal = storage == Variable::kGlobal_Storage;
+ if (location < 0 || count > 4) {
+ if (location >= 0) {
+ fGenerator.write(ByteCodeInstruction::kPushImmediate);
+ fGenerator.write32(location);
+ }
+ fGenerator.write(isGlobal ? ByteCodeInstruction::kStoreExtendedGlobal
+ : ByteCodeInstruction::kStoreExtended);
+ fGenerator.write8(count);
+ } else {
+ fGenerator.write(vector_instruction(isGlobal ? ByteCodeInstruction::kStoreGlobal
+ : ByteCodeInstruction::kStore,
+ count));
+ fGenerator.write8(location);
+ }
}
private:
typedef LValue INHERITED;
- int fCount;
- int fLocation;
- bool fIsGlobal;
+ const Expression& fExpression;
};
std::unique_ptr<ByteCodeGenerator::LValue> ByteCodeGenerator::getLValue(const Expression& e) {
@@ -715,12 +801,10 @@
SkASSERT(index <= 255);
return std::unique_ptr<LValue>(new ByteCodeExternalValueLValue(this, *value, index));
}
+ case Expression::kFieldAccess_Kind:
case Expression::kIndex_Kind:
- // not yet implemented
- abort();
case Expression::kVariableReference_Kind:
- return std::unique_ptr<LValue>(new ByteCodeVariableLValue(this,
- ((VariableReference&) e).fVariable));
+ return std::unique_ptr<LValue>(new ByteCodeExpressionLValue(this, e));
case Expression::kSwizzle_Kind:
return std::unique_ptr<LValue>(new ByteCodeSwizzleLValue(this, (Swizzle&) e));
case Expression::kTernary_Kind:
@@ -790,7 +874,7 @@
this->setContinueTargets();
if (f.fNext) {
this->writeExpression(*f.fNext);
- this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType)));
+ this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType)));
}
this->write(ByteCodeInstruction::kBranch);
this->write16(start);
@@ -800,7 +884,7 @@
this->setContinueTargets();
if (f.fNext) {
this->writeExpression(*f.fNext);
- this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(f.fNext->fType)));
+ this->write(vector_instruction(ByteCodeInstruction::kPop, SlotCount(f.fNext->fType)));
}
this->write(ByteCodeInstruction::kBranch);
this->write16(start);
@@ -834,7 +918,7 @@
void ByteCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
this->writeExpression(*r.fExpression);
this->write(ByteCodeInstruction::kReturn);
- this->write8(r.fExpression->fType.columns() * r.fExpression->fType.rows());
+ this->write8(SlotCount(r.fExpression->fType));
}
void ByteCodeGenerator::writeSwitchStatement(const SwitchStatement& r) {
@@ -850,9 +934,16 @@
int location = getLocation(*decl.fVar);
if (decl.fValue) {
this->writeExpression(*decl.fValue);
- this->write(vector_instruction(ByteCodeInstruction::kStore,
- slot_count(decl.fValue->fType)));
- this->write8(location);
+ int count = SlotCount(decl.fValue->fType);
+ if (count > 4) {
+ this->write(ByteCodeInstruction::kPushImmediate);
+ this->write32(location);
+ this->write(ByteCodeInstruction::kStoreExtended);
+ this->write8(count);
+ } else {
+ this->write(vector_instruction(ByteCodeInstruction::kStore, count));
+ this->write8(location);
+ }
}
}
}
@@ -893,7 +984,13 @@
case Statement::kExpression_Kind: {
const Expression& expr = *((ExpressionStatement&) s).fExpression;
this->writeExpression(expr);
- this->write(vector_instruction(ByteCodeInstruction::kPop, slot_count(expr.fType)));
+ int count = SlotCount(expr.fType);
+ if (count > 4) {
+ this->write(ByteCodeInstruction::kPopN);
+ this->write8(count);
+ } else {
+ this->write(vector_instruction(ByteCodeInstruction::kPop, count));
+ }
break;
}
case Statement::kFor_Kind:
diff --git a/src/sksl/SkSLByteCodeGenerator.h b/src/sksl/SkSLByteCodeGenerator.h
index 3a2306c..4d16997 100644
--- a/src/sksl/SkSLByteCodeGenerator.h
+++ b/src/sksl/SkSLByteCodeGenerator.h
@@ -96,6 +96,8 @@
void writeTypedInstruction(const Type& type, ByteCodeInstruction s, ByteCodeInstruction u,
ByteCodeInstruction f, int count);
+ static int SlotCount(const Type& type);
+
private:
// reserves 16 bits in the output code, to be filled in later with an address once we determine
// it
@@ -171,11 +173,18 @@
*/
int getLocation(const Variable& var);
+ /**
+ * As above, but computes the (possibly dynamic) address of an expression involving indexing &
+ * field access. If the address is known, it's returned. If not, -1 is returned, and the
+ * location will be left on the top of the stack.
+ */
+ int getLocation(const Expression& expr, Variable::Storage* storage);
+
std::unique_ptr<ByteCodeFunction> writeFunction(const FunctionDefinition& f);
void writeVarDeclarations(const VarDeclarations& decl);
- void writeVariableReference(const VariableReference& ref);
+ void writeVariableExpression(const Expression& expr);
void writeExpression(const Expression& expr);
@@ -195,16 +204,12 @@
void writeExternalValue(const ExternalValueReference& r);
- void writeFieldAccess(const FieldAccess& f);
-
void writeSwizzle(const Swizzle& swizzle);
void writeBinaryExpression(const BinaryExpression& b);
void writeTernaryExpression(const TernaryExpression& t);
- void writeIndexExpression(const IndexExpression& expr);
-
void writeLogicalAnd(const BinaryExpression& b);
void writeLogicalOr(const BinaryExpression& o);
@@ -268,7 +273,7 @@
std::unordered_map<String, ByteCodeInstruction> fIntrinsics;
friend class DeferredLocation;
- friend class ByteCodeVariableLValue;
+ friend class ByteCodeExpressionLValue;
friend class ByteCodeSwizzleLValue;
typedef CodeGenerator INHERITED;
diff --git a/src/sksl/SkSLInterpreter.cpp b/src/sksl/SkSLInterpreter.cpp
index 13a62b6..c97ecae 100644
--- a/src/sksl/SkSLInterpreter.cpp
+++ b/src/sksl/SkSLInterpreter.cpp
@@ -8,6 +8,7 @@
#ifndef SKSL_STANDALONE
#include "src/core/SkRasterPipeline.h"
+#include "src/sksl/SkSLByteCodeGenerator.h"
#include "src/sksl/SkSLExternalValue.h"
#include "src/sksl/SkSLInterpreter.h"
#include "src/sksl/ir/SkSLBinaryExpression.h"
@@ -64,8 +65,7 @@
this->innerRun(f, stack, outReturn);
for (const Variable* p : f.fDeclaration.fParameters) {
- const int nvalues = p->fType.columns()
- * p->fType.rows();
+ const int nvalues = ByteCodeGenerator::SlotCount(p->fType);
if (p->fModifiers.fFlags & Modifiers::kOut_Flag) {
memcpy(args, stack, nvalues * sizeof(Value));
}
@@ -85,152 +85,181 @@
#define READ16() (ip += 2, unaligned_load<uint16_t>(ip - 2))
#define READ32() (ip += 4, unaligned_load<uint32_t>(ip - 4))
-#define VECTOR_DISASSEMBLE(op, text) \
+#define VECTOR_DISASSEMBLE(op, text) \
case ByteCodeInstruction::op: printf(text); break; \
case ByteCodeInstruction::op##2: printf(text "2"); break; \
case ByteCodeInstruction::op##3: printf(text "3"); break; \
case ByteCodeInstruction::op##4: printf(text "4"); break;
+static const uint8_t* disassemble_instruction(const uint8_t* ip) {
+ switch ((ByteCodeInstruction) READ16()) {
+ VECTOR_DISASSEMBLE(kAddF, "addf")
+ VECTOR_DISASSEMBLE(kAddI, "addi")
+ case ByteCodeInstruction::kAndB: printf("andb"); break;
+ case ByteCodeInstruction::kAndI: printf("andi"); break;
+ case ByteCodeInstruction::kBranch: printf("branch %d", READ16()); break;
+ case ByteCodeInstruction::kCall: printf("call %d", READ8()); break;
+ case ByteCodeInstruction::kCallExternal: {
+ int argumentCount = READ8();
+ int returnCount = READ8();
+ int externalValue = READ8();
+ printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue);
+ break;
+ }
+ VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
+ VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
+ VECTOR_DISASSEMBLE(kCompareFEQ, "comparefeq")
+ VECTOR_DISASSEMBLE(kCompareFNEQ, "comparefneq")
+ VECTOR_DISASSEMBLE(kCompareFGT, "comparefgt")
+ VECTOR_DISASSEMBLE(kCompareFGTEQ, "comparefgteq")
+ VECTOR_DISASSEMBLE(kCompareFLT, "compareflt")
+ VECTOR_DISASSEMBLE(kCompareFLTEQ, "compareflteq")
+ VECTOR_DISASSEMBLE(kCompareSGT, "comparesgt")
+ VECTOR_DISASSEMBLE(kCompareSGTEQ, "comparesgteq")
+ VECTOR_DISASSEMBLE(kCompareSLT, "compareslt")
+ VECTOR_DISASSEMBLE(kCompareSLTEQ, "compareslteq")
+ VECTOR_DISASSEMBLE(kCompareUGT, "compareugt")
+ VECTOR_DISASSEMBLE(kCompareUGTEQ, "compareugteq")
+ VECTOR_DISASSEMBLE(kCompareULT, "compareult")
+ VECTOR_DISASSEMBLE(kCompareULTEQ, "compareulteq")
+ case ByteCodeInstruction::kConditionalBranch:
+ printf("conditionalbranch %d", READ16());
+ break;
+ VECTOR_DISASSEMBLE(kConvertFtoI, "convertftoi")
+ VECTOR_DISASSEMBLE(kConvertStoF, "convertstof")
+ VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof")
+ VECTOR_DISASSEMBLE(kCos, "cos")
+ case ByteCodeInstruction::kDebugPrint: printf("debugprint"); break;
+ VECTOR_DISASSEMBLE(kDivideF, "dividef")
+ VECTOR_DISASSEMBLE(kDivideS, "divideS")
+ VECTOR_DISASSEMBLE(kDivideU, "divideu")
+ VECTOR_DISASSEMBLE(kDup, "dup")
+ case ByteCodeInstruction::kDupN: printf("dupN %d", READ8()); break;
+ case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
+ case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
+ case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
+ case ByteCodeInstruction::kLoad4: printf("load4 %d", READ8()); break;
+ case ByteCodeInstruction::kLoadGlobal: printf("loadglobal %d", READ8()); break;
+ case ByteCodeInstruction::kLoadGlobal2: printf("loadglobal2 %d", READ8()); break;
+ case ByteCodeInstruction::kLoadGlobal3: printf("loadglobal3 %d", READ8()); break;
+ case ByteCodeInstruction::kLoadGlobal4: printf("loadglobal4 %d", READ8()); break;
+ case ByteCodeInstruction::kLoadSwizzle: {
+ int target = READ8();
+ int count = READ8();
+ printf("loadswizzle %d %d", target, count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kLoadSwizzleGlobal: {
+ int target = READ8();
+ int count = READ8();
+ printf("loadswizzleglobal %d %d", target, count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break;
+ case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8());
+ break;
+ VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf")
+ VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
+ VECTOR_DISASSEMBLE(kNegateF, "negatef")
+ VECTOR_DISASSEMBLE(kNegateI, "negatei")
+ VECTOR_DISASSEMBLE(kNot, "not")
+ VECTOR_DISASSEMBLE(kOrB, "orb")
+ VECTOR_DISASSEMBLE(kOrI, "ori")
+ VECTOR_DISASSEMBLE(kPop, "pop")
+ case ByteCodeInstruction::kPopN: printf("popN %d", READ8()); break;
+ case ByteCodeInstruction::kPushImmediate: {
+ uint32_t v = READ32();
+ union { uint32_t u; float f; } pun = { v };
+ printf("pushimmediate %s", (to_string(v) + "(" + to_string(pun.f) + ")").c_str());
+ break;
+ }
+ case ByteCodeInstruction::kReadExternal: printf("readexternal %d", READ8()); break;
+ case ByteCodeInstruction::kReadExternal2: printf("readexternal2 %d", READ8()); break;
+ case ByteCodeInstruction::kReadExternal3: printf("readexternal3 %d", READ8()); break;
+ case ByteCodeInstruction::kReadExternal4: printf("readexternal4 %d", READ8()); break;
+ VECTOR_DISASSEMBLE(kRemainderF, "remainderf")
+ VECTOR_DISASSEMBLE(kRemainderS, "remainders")
+ VECTOR_DISASSEMBLE(kRemainderU, "remainderu")
+ case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break;
+ VECTOR_DISASSEMBLE(kSin, "sin")
+ VECTOR_DISASSEMBLE(kSqrt, "sqrt")
+ case ByteCodeInstruction::kStore: printf("store %d", READ8()); break;
+ case ByteCodeInstruction::kStore2: printf("store2 %d", READ8()); break;
+ case ByteCodeInstruction::kStore3: printf("store3 %d", READ8()); break;
+ case ByteCodeInstruction::kStore4: printf("store4 %d", READ8()); break;
+ case ByteCodeInstruction::kStoreGlobal: printf("storeglobal %d", READ8()); break;
+ case ByteCodeInstruction::kStoreGlobal2: printf("storeglobal2 %d", READ8()); break;
+ case ByteCodeInstruction::kStoreGlobal3: printf("storeglobal3 %d", READ8()); break;
+ case ByteCodeInstruction::kStoreGlobal4: printf("storeglobal4 %d", READ8()); break;
+ case ByteCodeInstruction::kStoreSwizzle: {
+ int target = READ8();
+ int count = READ8();
+ printf("storeswizzle %d %d", target, count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kStoreSwizzleGlobal: {
+ int target = READ8();
+ int count = READ8();
+ printf("storeswizzleglobal %d %d", target, count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kStoreSwizzleIndirect: {
+ int count = READ8();
+ printf("storeswizzleindirect %d", count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
+ int count = READ8();
+ printf("storeswizzleindirectglobal %d", count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break;
+ case ByteCodeInstruction::kStoreExtendedGlobal: printf("storeextendedglobal %d", READ8());
+ break;
+ VECTOR_DISASSEMBLE(kSubtractF, "subtractf")
+ VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
+ case ByteCodeInstruction::kSwizzle: {
+ printf("swizzle %d, ", READ8());
+ int count = READ8();
+ printf("%d", count);
+ for (int i = 0; i < count; ++i) {
+ printf(", %d", READ8());
+ }
+ break;
+ }
+ VECTOR_DISASSEMBLE(kTan, "tan")
+ case ByteCodeInstruction::kWriteExternal: printf("writeexternal %d", READ8()); break;
+ case ByteCodeInstruction::kWriteExternal2: printf("writeexternal2 %d", READ8()); break;
+ case ByteCodeInstruction::kWriteExternal3: printf("writeexternal3 %d", READ8()); break;
+ case ByteCodeInstruction::kWriteExternal4: printf("writeexternal4 %d", READ8()); break;
+ default: printf("unknown(%d)\n", *(ip - 1)); SkASSERT(false);
+ }
+ return ip;
+}
+
void Interpreter::disassemble(const ByteCodeFunction& f) {
const uint8_t* ip = f.fCode.data();
while (ip < f.fCode.data() + f.fCode.size()) {
printf("%d: ", (int) (ip - f.fCode.data()));
- switch ((ByteCodeInstruction) READ16()) {
- VECTOR_DISASSEMBLE(kAddF, "addf")
- VECTOR_DISASSEMBLE(kAddI, "addi")
- case ByteCodeInstruction::kAndB: printf("andb"); break;
- case ByteCodeInstruction::kAndI: printf("andi"); break;
- case ByteCodeInstruction::kBranch: printf("branch %d", READ16()); break;
- case ByteCodeInstruction::kCall: printf("call %d", READ8()); break;
- case ByteCodeInstruction::kCallExternal: {
- int argumentCount = READ8();
- int returnCount = READ8();
- int externalValue = READ8();
- printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue);
- break;
- }
- VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
- VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
- VECTOR_DISASSEMBLE(kCompareFEQ, "comparefeq")
- VECTOR_DISASSEMBLE(kCompareFNEQ, "comparefneq")
- VECTOR_DISASSEMBLE(kCompareFGT, "comparefgt")
- VECTOR_DISASSEMBLE(kCompareFGTEQ, "comparefgteq")
- VECTOR_DISASSEMBLE(kCompareFLT, "compareflt")
- VECTOR_DISASSEMBLE(kCompareFLTEQ, "compareflteq")
- VECTOR_DISASSEMBLE(kCompareSGT, "comparesgt")
- VECTOR_DISASSEMBLE(kCompareSGTEQ, "comparesgteq")
- VECTOR_DISASSEMBLE(kCompareSLT, "compareslt")
- VECTOR_DISASSEMBLE(kCompareSLTEQ, "compareslteq")
- VECTOR_DISASSEMBLE(kCompareUGT, "compareugt")
- VECTOR_DISASSEMBLE(kCompareUGTEQ, "compareugteq")
- VECTOR_DISASSEMBLE(kCompareULT, "compareult")
- VECTOR_DISASSEMBLE(kCompareULTEQ, "compareulteq")
- case ByteCodeInstruction::kConditionalBranch:
- printf("conditionalbranch %d", READ16());
- break;
- VECTOR_DISASSEMBLE(kConvertFtoI, "convertftoi")
- VECTOR_DISASSEMBLE(kConvertStoF, "convertstof")
- VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof")
- VECTOR_DISASSEMBLE(kCos, "cos")
- case ByteCodeInstruction::kDebugPrint: printf("debugprint"); break;
- VECTOR_DISASSEMBLE(kDivideF, "dividef")
- VECTOR_DISASSEMBLE(kDivideS, "divideS")
- VECTOR_DISASSEMBLE(kDivideU, "divideu")
- VECTOR_DISASSEMBLE(kDup, "dup")
- case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
- case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
- case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
- case ByteCodeInstruction::kLoad4: printf("load4 %d", READ8()); break;
- case ByteCodeInstruction::kLoadGlobal: printf("loadglobal %d", READ8()); break;
- case ByteCodeInstruction::kLoadGlobal2: printf("loadglobal2 %d", READ8()); break;
- case ByteCodeInstruction::kLoadGlobal3: printf("loadglobal3 %d", READ8()); break;
- case ByteCodeInstruction::kLoadGlobal4: printf("loadglobal4 %d", READ8()); break;
- case ByteCodeInstruction::kLoadSwizzle: {
- int target = READ8();
- int count = READ8();
- printf("loadswizzle %d %d", target, count);
- for (int i = 0; i < count; ++i) {
- printf(", %d", READ8());
- }
- break;
- }
- case ByteCodeInstruction::kLoadSwizzleGlobal: {
- int target = READ8();
- int count = READ8();
- printf("loadswizzleglobal %d %d", target, count);
- for (int i = 0; i < count; ++i) {
- printf(", %d", READ8());
- }
- break;
- }
- VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf")
- VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
- VECTOR_DISASSEMBLE(kNegateF, "negatef")
- VECTOR_DISASSEMBLE(kNegateI, "negatei")
- VECTOR_DISASSEMBLE(kNot, "not")
- VECTOR_DISASSEMBLE(kOrB, "orb")
- VECTOR_DISASSEMBLE(kOrI, "ori")
- VECTOR_DISASSEMBLE(kPop, "pop")
- case ByteCodeInstruction::kPushImmediate: {
- uint32_t v = READ32();
- union { uint32_t u; float f; } pun = { v };
- printf("pushimmediate %s", (to_string(v) + "(" + to_string(pun.f) + ")").c_str());
- break;
- }
- case ByteCodeInstruction::kReadExternal: printf("readexternal %d", READ8()); break;
- case ByteCodeInstruction::kReadExternal2: printf("readexternal2 %d", READ8()); break;
- case ByteCodeInstruction::kReadExternal3: printf("readexternal3 %d", READ8()); break;
- case ByteCodeInstruction::kReadExternal4: printf("readexternal4 %d", READ8()); break;
- VECTOR_DISASSEMBLE(kRemainderF, "remainderf")
- VECTOR_DISASSEMBLE(kRemainderS, "remainders")
- VECTOR_DISASSEMBLE(kRemainderU, "remainderu")
- case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break;
- VECTOR_DISASSEMBLE(kSin, "sin")
- VECTOR_DISASSEMBLE(kSqrt, "sqrt")
- case ByteCodeInstruction::kStore: printf("store %d", READ8()); break;
- case ByteCodeInstruction::kStore2: printf("store2 %d", READ8()); break;
- case ByteCodeInstruction::kStore3: printf("store3 %d", READ8()); break;
- case ByteCodeInstruction::kStore4: printf("store4 %d", READ8()); break;
- case ByteCodeInstruction::kStoreGlobal: printf("storeglobal %d", READ8()); break;
- case ByteCodeInstruction::kStoreGlobal2: printf("storeglobal2 %d", READ8()); break;
- case ByteCodeInstruction::kStoreGlobal3: printf("storeglobal3 %d", READ8()); break;
- case ByteCodeInstruction::kStoreGlobal4: printf("storeglobal4 %d", READ8()); break;
- case ByteCodeInstruction::kStoreSwizzle: {
- int target = READ8();
- int count = READ8();
- printf("storeswizzle %d %d", target, count);
- for (int i = 0; i < count; ++i) {
- printf(", %d", READ8());
- }
- break;
- }
- case ByteCodeInstruction::kStoreSwizzleGlobal: {
- int target = READ8();
- int count = READ8();
- printf("storeswizzleglobal %d %d", target, count);
- for (int i = 0; i < count; ++i) {
- printf(", %d", READ8());
- }
- break;
- }
- VECTOR_DISASSEMBLE(kSubtractF, "subtractf")
- VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
- case ByteCodeInstruction::kSwizzle: {
- printf("swizzle %d, ", READ8());
- int count = READ8();
- printf("%d", count);
- for (int i = 0; i < count; ++i) {
- printf(", %d", READ8());
- }
- break;
- }
- VECTOR_DISASSEMBLE(kTan, "tan")
- case ByteCodeInstruction::kWriteExternal: printf("writeexternal %d", READ8()); break;
- case ByteCodeInstruction::kWriteExternal2: printf("writeexternal2 %d", READ8()); break;
- case ByteCodeInstruction::kWriteExternal3: printf("writeexternal3 %d", READ8()); break;
- case ByteCodeInstruction::kWriteExternal4: printf("writeexternal4 %d", READ8()); break;
- default: printf("unknown(%d)\n", *(ip - 1)); SkASSERT(false);
- }
+ ip = disassemble_instruction(ip);
printf("\n");
}
}
@@ -304,7 +333,9 @@
for (;;) {
#ifdef TRACE
- printf("at %d\n", (int) (ip - code));
+ printf("at %3d ", (int) (ip - code));
+ disassemble_instruction(ip);
+ printf("\n");
#endif
ByteCodeInstruction inst = (ByteCodeInstruction) READ16();
switch (inst) {
@@ -404,6 +435,13 @@
case ByteCodeInstruction::kDup : PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
break;
+ case ByteCodeInstruction::kDupN: {
+ int count = READ8();
+ memcpy(sp + 1, sp - count + 1, count * sizeof(Value));
+ sp += count;
+ break;
+ }
+
case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3];
case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2];
case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1];
@@ -417,9 +455,27 @@
case ByteCodeInstruction::kLoadGlobal2: sp[2] = fGlobals[*ip + 1];
case ByteCodeInstruction::kLoadGlobal : sp[1] = fGlobals[*ip + 0];
++ip;
- sp += (int)inst - (int)ByteCodeInstruction::kLoadGlobal + 1;
+ sp += (int)inst -
+ (int)ByteCodeInstruction::kLoadGlobal + 1;
break;
+ case ByteCodeInstruction::kLoadExtended: {
+ int count = READ8();
+ int src = POP().fSigned;
+ memcpy(sp + 1, &stack[src], count * sizeof(Value));
+ sp += count;
+ break;
+ }
+
+ case ByteCodeInstruction::kLoadExtendedGlobal: {
+ int count = READ8();
+ int src = POP().fSigned;
+ SkASSERT(src + count <= (int) fGlobals.size());
+ memcpy(sp + 1, &fGlobals[src], count * sizeof(Value));
+ sp += count;
+ break;
+ }
+
case ByteCodeInstruction::kLoadSwizzle: {
int src = READ8();
int count = READ8();
@@ -466,6 +522,10 @@
case ByteCodeInstruction::kPop : POP();
break;
+ case ByteCodeInstruction::kPopN:
+ sp -= READ8();
+ break;
+
case ByteCodeInstruction::kPushImmediate:
PUSH(READ32());
break;
@@ -525,6 +585,22 @@
++ip;
break;
+ case ByteCodeInstruction::kStoreExtended: {
+ int count = READ8();
+ int target = POP().fSigned;
+ memcpy(&stack[target], sp - count + 1, count * sizeof(Value));
+ sp -= count;
+ break;
+ }
+ case ByteCodeInstruction::kStoreExtendedGlobal: {
+ int count = READ8();
+ int target = POP().fSigned;
+ SkASSERT(target + count <= (int) fGlobals.size());
+ memcpy(&fGlobals[target], sp - count + 1, count * sizeof(Value));
+ sp -= count;
+ break;
+ }
+
case ByteCodeInstruction::kStoreSwizzle: {
int target = READ8();
int count = READ8();
@@ -544,6 +620,24 @@
ip += count;
break;
}
+ case ByteCodeInstruction::kStoreSwizzleIndirect: {
+ int target = POP().fSigned;
+ int count = READ8();
+ for (int i = count - 1; i >= 0; --i) {
+ stack[target + *(ip + i)] = POP();
+ }
+ ip += count;
+ break;
+ }
+ case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: {
+ int target = POP().fSigned;
+ int count = READ8();
+ for (int i = count - 1; i >= 0; --i) {
+ fGlobals[target + *(ip + i)] = POP();
+ }
+ ip += count;
+ break;
+ }
VECTOR_BINARY_OP(kSubtractI, fSigned, -)
VECTOR_BINARY_OP(kSubtractF, fFloat, -)
diff --git a/tests/SkSLInterpreterTest.cpp b/tests/SkSLInterpreterTest.cpp
index 2bcd829..26db0bc 100644
--- a/tests/SkSLInterpreterTest.cpp
+++ b/tests/SkSLInterpreterTest.cpp
@@ -348,6 +348,144 @@
REPORTER_ASSERT(r, out == 5.0f);
}
+DEF_TEST(SkSLInterpreterCompound, r) {
+ struct RectAndColor { SkIRect fRect; SkColor4f fColor; };
+ struct ManyRects { int fNumRects; RectAndColor fRects[4]; };
+
+ const char* src =
+ // Some struct definitions
+ "struct Point { int x; int y; };\n"
+ "struct Rect { Point p0; Point p1; };\n"
+ "struct RectAndColor { Rect r; float4 color; };\n"
+
+ // Structs as globals, parameters, return values
+ "RectAndColor temp;\n"
+ "int rect_height(Rect r) { return r.p1.y - r.p0.y; }\n"
+ "RectAndColor make_blue_rect(int w, int h) {\n"
+ " temp.r.p0.x = temp.r.p0.y = 0;\n"
+ " temp.r.p1.x = w; temp.r.p1.y = h;\n"
+ " temp.color = float4(0, 1, 0, 1);\n"
+ " return temp;\n"
+ "}\n"
+
+ // Initialization and assignment of types larger than 4 slots
+ "RectAndColor init_big(RectAndColor r) { RectAndColor s = r; return s; }\n"
+ "RectAndColor copy_big(RectAndColor r) { RectAndColor s; s = r; return s; }\n"
+
+ // Same for arrays, including some non-constant indexing
+ "float tempFloats[8];\n"
+ "int median(int a[15]) { return a[7]; }\n"
+ "float[8] sums(float a[8]) {\n"
+ " float tempFloats[8];\n"
+ " tempFloats[0] = a[0];\n"
+ " for (int i = 1; i < 8; ++i) { tempFloats[i] = tempFloats[i - 1] + a[i]; }\n"
+ " return tempFloats;\n"
+ "}\n"
+
+ // Uniforms, array-of-structs, dynamic indices
+ "in uniform Rect gRects[4];\n"
+ "Rect get_rect(int i) { return gRects[i]; }\n"
+
+ // Kitchen sink (swizzles, inout, SoAoS)
+ "struct ManyRects { int numRects; RectAndColor rects[4]; };\n"
+ "void fill_rects(inout ManyRects mr) {\n"
+ " for (int i = 0; i < mr.numRects; ++i) {\n"
+ " mr.rects[i].r = gRects[i];\n"
+ " float b = mr.rects[i].r.p1.y;\n"
+ " mr.rects[i].color = float4(b, b, b, b);\n"
+ " }\n"
+ "}\n";
+
+ SkSL::Compiler compiler;
+ SkSL::Program::Settings settings;
+ std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+ SkSL::Program::kGeneric_Kind,
+ SkSL::String(src), settings);
+ REPORTER_ASSERT(r, program);
+
+ std::unique_ptr<SkSL::ByteCode> byteCode = compiler.toByteCode(*program);
+ REPORTER_ASSERT(r, !compiler.errorCount());
+
+ auto rect_height = byteCode->getFunction("rect_height"),
+ make_blue_rect = byteCode->getFunction("make_blue_rect"),
+ median = byteCode->getFunction("median"),
+ sums = byteCode->getFunction("sums"),
+ get_rect = byteCode->getFunction("get_rect"),
+ fill_rects = byteCode->getFunction("fill_rects");
+
+ SkIRect gRects[4] = { { 1,2,3,4 }, { 5,6,7,8 }, { 9,10,11,12 }, { 13,14,15,16 } };
+
+ SkSL::Interpreter interpreter(std::move(program), std::move(byteCode),
+ (SkSL::Interpreter::Value*)gRects);
+
+ {
+ SkIRect in = SkIRect::MakeXYWH(10, 10, 20, 30);
+ int out = 0;
+ interpreter.run(*rect_height,
+ (SkSL::Interpreter::Value*)&in,
+ (SkSL::Interpreter::Value*)&out);
+ REPORTER_ASSERT(r, out == 30);
+ }
+
+ {
+ int in[2] = { 15, 25 };
+ RectAndColor out;
+ interpreter.run(*make_blue_rect,
+ (SkSL::Interpreter::Value*)in,
+ (SkSL::Interpreter::Value*)&out);
+ REPORTER_ASSERT(r, out.fRect.width() == 15);
+ REPORTER_ASSERT(r, out.fRect.height() == 25);
+ SkColor4f blue = { 0.0f, 1.0f, 0.0f, 1.0f };
+ REPORTER_ASSERT(r, out.fColor == blue);
+ }
+
+ {
+ int in[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+ int out = 0;
+ interpreter.run(*median,
+ (SkSL::Interpreter::Value*)in,
+ (SkSL::Interpreter::Value*)&out);
+ REPORTER_ASSERT(r, out == 8);
+ }
+
+ {
+ float in[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+ float out[8] = { 0 };
+ interpreter.run(*sums,
+ (SkSL::Interpreter::Value*)in,
+ (SkSL::Interpreter::Value*)out);
+ for (int i = 0; i < 8; ++i) {
+ REPORTER_ASSERT(r, out[i] == static_cast<float>((i + 1) * (i + 2) / 2));
+ }
+ }
+
+ {
+ int in = 2;
+ SkIRect out = SkIRect::MakeEmpty();
+ interpreter.run(*get_rect,
+ (SkSL::Interpreter::Value*)&in,
+ (SkSL::Interpreter::Value*)&out);
+ REPORTER_ASSERT(r, out == gRects[2]);
+ }
+
+ {
+ ManyRects in;
+ memset(&in, 0, sizeof(in));
+ in.fNumRects = 2;
+ interpreter.run(*fill_rects,
+ (SkSL::Interpreter::Value*)&in,
+ nullptr);
+ ManyRects expected;
+ memset(&expected, 0, sizeof(expected));
+ expected.fNumRects = 2;
+ for (int i = 0; i < 2; ++i) {
+ expected.fRects[i].fRect = gRects[i];
+ float c = gRects[i].fBottom;
+ expected.fRects[i].fColor = { c, c, c, c };
+ }
+ REPORTER_ASSERT(r, memcmp(&in, &expected, sizeof(in)) == 0);
+ }
+}
DEF_TEST(SkSLInterpreterFunctions, r) {
const char* src =
diff --git a/tests/TypefaceTest.cpp b/tests/TypefaceTest.cpp
index b1c330b..e1dfff6 100644
--- a/tests/TypefaceTest.cpp
+++ b/tests/TypefaceTest.cpp
@@ -10,15 +10,20 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkStream.h"
#include "include/core/SkTypeface.h"
+#include "include/ports/SkTypeface_win.h"
#include "include/private/SkFixed.h"
#include "src/core/SkAdvancedTypefaceMetrics.h"
#include "src/core/SkFontDescriptor.h"
+#include "src/core/SkFontMgrPriv.h"
+#include "src/core/SkFontPriv.h"
#include "src/core/SkMakeUnique.h"
#include "src/core/SkTypefaceCache.h"
#include "src/sfnt/SkOTTable_OS_2.h"
#include "src/sfnt/SkSFNTHeader.h"
+#include "src/utils/SkUTF.h"
#include "tests/Test.h"
#include "tools/Resources.h"
+#include "tools/ToolUtils.h"
#include "tools/fonts/TestEmptyTypeface.h"
#include <memory>
@@ -323,3 +328,38 @@
}
+DEF_TEST(Typeface_glyph_to_char, reporter) {
+ SkFont font(ToolUtils::emoji_typeface(), 12);
+ SkASSERT(font.getTypeface());
+ char const * text = ToolUtils::emoji_sample_text();
+ size_t const textLen = strlen(text);
+ size_t const codepointCount = SkUTF::CountUTF8(text, textLen);
+ char const * const textEnd = text + textLen;
+ std::unique_ptr<SkUnichar[]> originalCodepoints(new SkUnichar[codepointCount]);
+ for (size_t i = 0; i < codepointCount; ++i) {
+ originalCodepoints[i] = SkUTF::NextUTF8(&text, textEnd);
+ }
+ std::unique_ptr<SkGlyphID[]> glyphs(new SkGlyphID[codepointCount]);
+ font.unicharsToGlyphs(originalCodepoints.get(), codepointCount, glyphs.get());
+
+ std::unique_ptr<SkUnichar[]> newCodepoints(new SkUnichar[codepointCount]);
+ SkFontPriv::GlyphsToUnichars(font, glyphs.get(), codepointCount, newCodepoints.get());
+
+ SkString familyName;
+ font.getTypeface()->getFamilyName(&familyName);
+ for (size_t i = 0; i < codepointCount; ++i) {
+#if defined(SK_BUILD_FOR_WIN)
+ // GDI does not support character to glyph mapping outside BMP.
+ if (gSkFontMgr_DefaultFactory == &SkFontMgr_New_GDI &&
+ 0xFFFF < originalCodepoints[i] && newCodepoints[i] == 0)
+ {
+ continue;
+ }
+#endif
+ // If two codepoints map to the same glyph then this assert is not valid.
+ // However, the emoji test font should never have multiple characters map to the same glyph.
+ REPORTER_ASSERT(reporter, originalCodepoints[i] == newCodepoints[i],
+ "name:%s i:%d original:%d new:%d glyph:%d", familyName.c_str(), i,
+ originalCodepoints[i], newCodepoints[i], glyphs[i]);
+ }
+}
diff --git a/tests/YUVTest.cpp b/tests/YUVTest.cpp
index 644450d..0180f07 100644
--- a/tests/YUVTest.cpp
+++ b/tests/YUVTest.cpp
@@ -124,3 +124,42 @@
// A PNG should fail.
codec_yuv(r, "images/arrow.png", nullptr);
}
+
+#include "include/effects/SkColorMatrix.h"
+#include "src/core/SkYUVMath.h"
+
+// Be sure that the two matrices are inverses of each other
+// (i.e. rgb2yuv and yuv2rgb
+DEF_TEST(YUVMath, reporter) {
+ const SkYUVColorSpace spaces[] = {
+ kJPEG_SkYUVColorSpace,
+ kRec601_SkYUVColorSpace,
+ kRec709_SkYUVColorSpace,
+ kIdentity_SkYUVColorSpace,
+ };
+
+ // Not sure what the theoretical precision we can hope for is, so pick a big value that
+ // passes (when I think we're correct).
+ const float tolerance = 1.0f/(1 << 18);
+
+ for (auto cs : spaces) {
+ float r2y[20], y2r[20];
+ SkColorMatrix_RGB2YUV(cs, r2y);
+ SkColorMatrix_YUV2RGB(cs, y2r);
+
+ SkColorMatrix r2ym, y2rm;
+ r2ym.setRowMajor(r2y);
+ y2rm.setRowMajor(y2r);
+ r2ym.postConcat(y2rm);
+
+ float tmp[20];
+ r2ym.getRowMajor(tmp);
+ for (int i = 0; i < 20; ++i) {
+ float expected = 0;
+ if (i % 6 == 0) { // diagonal
+ expected = 1;
+ }
+ REPORTER_ASSERT(reporter, SkScalarNearlyEqual(tmp[i], expected, tolerance));
+ }
+ }
+}