aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2018-05-21 12:54:39 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-21 18:21:08 +0000
commitbe3c1d22c7d3e18cee9f1697827392e16b436df2 (patch)
tree072c9c2e3a29a383b63d083f2483625a32b36401
parent477094250cd55a38d4d796ab6c50eb57bdba65e1 (diff)
Add perspective support to GrTextureOp.
Bug: skia: Change-Id: Idea4ffae37dc2c2f339af60a2b74ded476091758 Reviewed-on: https://skia-review.googlesource.com/127600 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-rw-r--r--gm/perspimages.cpp111
-rw-r--r--gn/gm.gni1
-rw-r--r--infra/bots/recipes/test.expected/Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Release-All-Android.json2
-rw-r--r--infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-ASAN.json4
-rw-r--r--infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN.json4
-rw-r--r--infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE.json4
-rw-r--r--infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_10-Coverage.json4
-rw-r--r--infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-TSAN.json4
-rw-r--r--infra/bots/recipes/test.expected/Test-Mac-Clang-MacMini7.1-CPU-AVX-x86_64-Release-All.json4
-rw-r--r--infra/bots/recipes/test.expected/failed_dm.json4
-rw-r--r--infra/bots/recipes/test.expected/trybot.json4
-rw-r--r--infra/bots/recipes/test.py3
-rw-r--r--src/gpu/GrQuad.cpp40
-rw-r--r--src/gpu/GrQuad.h34
-rw-r--r--src/gpu/GrRenderTargetContext.cpp13
-rw-r--r--src/gpu/GrRenderTargetContext.h8
-rw-r--r--src/gpu/SkGpuDevice_drawTexture.cpp31
-rw-r--r--src/gpu/ops/GrNonAAFillRectOp.cpp3
-rw-r--r--src/gpu/ops/GrTextureOp.cpp293
19 files changed, 445 insertions, 126 deletions
diff --git a/gm/perspimages.cpp b/gm/perspimages.cpp
new file mode 100644
index 0000000000..a4242cf6f2
--- /dev/null
+++ b/gm/perspimages.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "Resources.h"
+#include "SkGradientShader.h"
+#include "SkImage.h"
+#include "SkPath.h"
+#include "SkSurface.h"
+#include "sk_tool_utils.h"
+
+static sk_sp<SkImage> make_image1() { return GetResourceAsImage("images/mandrill_128.png"); }
+
+static sk_sp<SkImage> make_image2() {
+ return GetResourceAsImage("images/brickwork-texture.jpg")->makeSubset({0, 0, 128, 128});
+}
+
+namespace skiagm {
+
+class PerspImages : public GM {
+public:
+ PerspImages() = default;
+
+protected:
+ SkString onShortName() override { return SkString("persp_images"); }
+
+ SkISize onISize() override { return SkISize::Make(1150, 880); }
+
+ void onOnceBeforeDraw() override {
+ fImages.push_back(make_image1());
+ fImages.push_back(make_image2());
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ SkTDArray<SkMatrix> matrices;
+ matrices.push()->setAll(1.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f,
+ 0.f, 0.005f, 1.f);
+ matrices.push()->setAll(1.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f,
+ 0.007f, -0.005f, 1.f);
+ matrices[1].preSkew(0.2f, -0.1f);
+ matrices[1].preRotate(-65.f);
+ matrices[1].preScale(1.2f, .8f);
+ matrices[1].postTranslate(0.f, 60.f);
+ SkPaint paint;
+ int n = 0;
+ SkRect bounds = SkRect::MakeEmpty();
+ for (const auto& img : fImages) {
+ SkRect imgB = SkRect::MakeWH(img->width(), img->height());
+ for (const auto& m : matrices) {
+ SkRect temp;
+ m.mapRect(&temp, imgB);
+ bounds.join(temp);
+ }
+ }
+ canvas->translate(-bounds.fLeft + 10.f, -bounds.fTop + 10.f);
+ canvas->save();
+ for (auto subrect : {false, true}) {
+ for (const auto& m : matrices) {
+ for (auto aa : {false, true}) {
+ paint.setAntiAlias(aa);
+ for (auto filter : {kNone_SkFilterQuality, kLow_SkFilterQuality,
+ kMedium_SkFilterQuality, kHigh_SkFilterQuality}) {
+ for (const auto& img : fImages) {
+ paint.setFilterQuality(filter);
+ canvas->save();
+ canvas->concat(m);
+ if (subrect) {
+ SkRect src = {img->width() / 4.f, img->height() / 4.f,
+ 3.f * img->width() / 4.f, 3.f * img->height() / 4};
+ SkRect dst = {0, 0,
+ 3.f / 4.f * img->width(), 3.f / 4.f * img->height()};
+ canvas->drawImageRect(img, src, dst, &paint);
+ } else {
+ canvas->drawImage(img, 0, 0, &paint);
+ }
+ canvas->restore();
+ ++n;
+ if (n < 8) {
+ canvas->translate(bounds.width() + 10.f, 0);
+ } else {
+ canvas->restore();
+ canvas->translate(0, bounds.height() + 10.f);
+ canvas->save();
+ n = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ canvas->restore();
+ }
+
+private:
+ static constexpr int kNumImages = 4;
+ SkTArray<sk_sp<SkImage>> fImages;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM(return new PerspImages();)
+
+} // namespace skiagm
diff --git a/gn/gm.gni b/gn/gm.gni
index a02ff958a7..ee1081ea89 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -238,6 +238,7 @@ gm_sources = [
"$_gm/pathreverse.cpp",
"$_gm/pdf_never_embed.cpp",
"$_gm/perlinnoise.cpp",
+ "$_gm/perspimages.cpp",
"$_gm/perspshaders.cpp",
"$_gm/picture.cpp",
"$_gm/pictureimagefilter.cpp",
diff --git a/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Release-All-Android.json b/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Release-All-Android.json
index 2e929258c7..a25b46855f 100644
--- a/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Release-All-Android.json
+++ b/infra/bots/recipes/test.expected/Test-Android-Clang-Nexus7-CPU-Tegra3-arm-Release-All-Android.json
@@ -718,7 +718,7 @@
"--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-Nexus7-CPU-Tegra3-arm-Release-All-Android buildbucket_build_id 123454321 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 CPU cpu_or_gpu_value Tegra3 extra_config Android model Nexus7 os Android --uninterestingHashesFile /sdcard/revenge_of_the_skiabot/uninteresting_hashes.txt --writePath /sdcard/revenge_of_the_skiabot/dm_out --dont_write pdf --threads 2 --nogpu --config 8888 serialize-8888 tiles_rt-8888 pic-8888 --src tests gm image colorImage --blacklist _ test _ GrShape serialize-8888 gm _ bleed_image serialize-8888 gm _ c_gms serialize-8888 gm _ colortype serialize-8888 gm _ colortype_xfermodes serialize-8888 gm _ drawfilter serialize-8888 gm _ fontmgr_bounds_0.75_0 serialize-8888 gm _ fontmgr_bounds_1_-0.25 serialize-8888 gm _ fontmgr_bounds serialize-8888 gm _ fontmgr_match serialize-8888 gm _ fontmgr_iter serialize-8888 gm _ imagemasksubset serialize-8888 gm _ bitmapfilters serialize-8888 gm _ bitmapshaders serialize-8888 gm _ bleed serialize-8888 gm _ bleed_alpha_bmp serialize-8888 gm _ bleed_alpha_bmp_shader serialize-8888 gm _ convex_poly_clip serialize-8888 gm _ extractalpha serialize-8888 gm _ filterbitmap_checkerboard_32_32_g8 serialize-8888 gm _ filterbitmap_image_mandrill_64 serialize-8888 gm _ shadows serialize-8888 gm _ simpleaaclip_aaclip serialize-8888 gm _ composeshader_bitmap serialize-8888 gm _ scaled_tilemodes_npot serialize-8888 gm _ scaled_tilemodes serialize-8888 gm _ typefacerendering_pfaMac serialize-8888 gm _ parsedpaths serialize-8888 gm _ ImageGeneratorExternal_rect serialize-8888 gm _ ImageGeneratorExternal_shader serialize-8888 gm _ shadow_utils serialize-8888 gm _ all_bitmap_configs serialize-8888 gm _ makecolorspace serialize-8888 gm _ analytic_antialias_convex serialize-8888 gm _ bleed_alpha_image serialize-8888 gm _ bleed_alpha_image_shader serialize-8888 gm _ verylargebitmap serialize-8888 gm _ verylarge_picture_image pic-8888 gm _ drawfilter pic-8888 gm _ image-cacherator-from-picture serialize-8888 gm _ image-cacherator-from-picture pic-8888 gm _ image-cacherator-from-raster serialize-8888 gm _ image-cacherator-from-raster pic-8888 gm _ image-cacherator-from-ctable serialize-8888 gm _ image-cacherator-from-ctable pic-8888 gm _ gamut serialize-8888 gm _ gamut pic-8888 gm _ complexclip4_bw serialize-8888 gm _ complexclip4_bw pic-8888 gm _ complexclip4_aa serialize-8888 gm _ complexclip4_aa tiles_rt-8888 gm _ complexclip4_bw tiles_rt-8888 gm _ complexclip4_aa --nonativeFonts --verbose; echo $? >/data/local/tmp/rc",
+ "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-Nexus7-CPU-Tegra3-arm-Release-All-Android buildbucket_build_id 123454321 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 CPU cpu_or_gpu_value Tegra3 extra_config Android model Nexus7 os Android --uninterestingHashesFile /sdcard/revenge_of_the_skiabot/uninteresting_hashes.txt --writePath /sdcard/revenge_of_the_skiabot/dm_out --dont_write pdf --threads 2 --nogpu --config 8888 serialize-8888 tiles_rt-8888 pic-8888 --src tests gm image colorImage --blacklist _ test _ GrShape serialize-8888 gm _ bleed_image serialize-8888 gm _ c_gms serialize-8888 gm _ colortype serialize-8888 gm _ colortype_xfermodes serialize-8888 gm _ drawfilter serialize-8888 gm _ fontmgr_bounds_0.75_0 serialize-8888 gm _ fontmgr_bounds_1_-0.25 serialize-8888 gm _ fontmgr_bounds serialize-8888 gm _ fontmgr_match serialize-8888 gm _ fontmgr_iter serialize-8888 gm _ imagemasksubset serialize-8888 gm _ bitmapfilters serialize-8888 gm _ bitmapshaders serialize-8888 gm _ bleed serialize-8888 gm _ bleed_alpha_bmp serialize-8888 gm _ bleed_alpha_bmp_shader serialize-8888 gm _ convex_poly_clip serialize-8888 gm _ extractalpha serialize-8888 gm _ filterbitmap_checkerboard_32_32_g8 serialize-8888 gm _ filterbitmap_image_mandrill_64 serialize-8888 gm _ shadows serialize-8888 gm _ simpleaaclip_aaclip serialize-8888 gm _ composeshader_bitmap serialize-8888 gm _ scaled_tilemodes_npot serialize-8888 gm _ scaled_tilemodes serialize-8888 gm _ typefacerendering_pfaMac serialize-8888 gm _ parsedpaths serialize-8888 gm _ ImageGeneratorExternal_rect serialize-8888 gm _ ImageGeneratorExternal_shader serialize-8888 gm _ shadow_utils serialize-8888 gm _ persp_images serialize-8888 gm _ all_bitmap_configs serialize-8888 gm _ makecolorspace serialize-8888 gm _ analytic_antialias_convex serialize-8888 gm _ bleed_alpha_image serialize-8888 gm _ bleed_alpha_image_shader serialize-8888 gm _ verylargebitmap serialize-8888 gm _ verylarge_picture_image pic-8888 gm _ drawfilter pic-8888 gm _ image-cacherator-from-picture serialize-8888 gm _ image-cacherator-from-picture pic-8888 gm _ image-cacherator-from-raster serialize-8888 gm _ image-cacherator-from-raster pic-8888 gm _ image-cacherator-from-ctable serialize-8888 gm _ image-cacherator-from-ctable pic-8888 gm _ gamut serialize-8888 gm _ gamut pic-8888 gm _ complexclip4_bw serialize-8888 gm _ complexclip4_bw pic-8888 gm _ complexclip4_aa serialize-8888 gm _ complexclip4_aa tiles_rt-8888 gm _ complexclip4_bw tiles_rt-8888 gm _ complexclip4_aa --nonativeFonts --verbose; echo $? >/data/local/tmp/rc",
"[START_DIR]/tmp/dm.sh"
],
"env": {
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-ASAN.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-ASAN.json
index 3fdec82e4a..d16275ec5f 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-ASAN.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-ASAN.json
@@ -345,6 +345,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN.json
index 5fd36def78..1a167a3ab5 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-MSAN.json
@@ -339,6 +339,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE.json
index d2435d8681..208bca95e0 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-All-SK_USE_DISCARDABLE_SCALEDIMAGECACHE.json
@@ -421,6 +421,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_10-Coverage.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_10-Coverage.json
index a9dc7db844..030f09513e 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_10-Coverage.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Debug-shard_00_10-Coverage.json
@@ -344,6 +344,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-TSAN.json b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-TSAN.json
index a67e2f8e38..b038befb02 100644
--- a/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-TSAN.json
+++ b/infra/bots/recipes/test.expected/Test-Debian9-Clang-GCE-CPU-AVX2-x86_64-Release-All-TSAN.json
@@ -340,6 +340,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/Test-Mac-Clang-MacMini7.1-CPU-AVX-x86_64-Release-All.json b/infra/bots/recipes/test.expected/Test-Mac-Clang-MacMini7.1-CPU-AVX-x86_64-Release-All.json
index ed172772fb..3ad5b750ff 100644
--- a/infra/bots/recipes/test.expected/Test-Mac-Clang-MacMini7.1-CPU-AVX-x86_64-Release-All.json
+++ b/infra/bots/recipes/test.expected/Test-Mac-Clang-MacMini7.1-CPU-AVX-x86_64-Release-All.json
@@ -504,6 +504,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/failed_dm.json b/infra/bots/recipes/test.expected/failed_dm.json
index c858ac4080..de3b1787a2 100644
--- a/infra/bots/recipes/test.expected/failed_dm.json
+++ b/infra/bots/recipes/test.expected/failed_dm.json
@@ -417,6 +417,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.expected/trybot.json b/infra/bots/recipes/test.expected/trybot.json
index b6c92c6e58..ae2a8650b8 100644
--- a/infra/bots/recipes/test.expected/trybot.json
+++ b/infra/bots/recipes/test.expected/trybot.json
@@ -440,6 +440,10 @@
"serialize-8888",
"gm",
"_",
+ "persp_images",
+ "serialize-8888",
+ "gm",
+ "_",
"all_bitmap_configs",
"serialize-8888",
"gm",
diff --git a/infra/bots/recipes/test.py b/infra/bots/recipes/test.py
index 98eb8cff4a..715cc018dd 100644
--- a/infra/bots/recipes/test.py
+++ b/infra/bots/recipes/test.py
@@ -481,6 +481,9 @@ def dm_flags(api, bot):
# skia:6189
bad_serialize_gms.append('shadow_utils')
+ # skia:7938
+ bad_serialize_gms.append('persp_images')
+
# Not expected to round trip encoding/decoding.
bad_serialize_gms.append('all_bitmap_configs')
bad_serialize_gms.append('makecolorspace')
diff --git a/src/gpu/GrQuad.cpp b/src/gpu/GrQuad.cpp
index 724a827f21..93bd761970 100644
--- a/src/gpu/GrQuad.cpp
+++ b/src/gpu/GrQuad.cpp
@@ -43,3 +43,43 @@ GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
y.store(fY);
}
}
+
+GrPerspQuad::GrPerspQuad(const SkRect& rect, const SkMatrix& m) {
+ SkMatrix::TypeMask tm = m.getType();
+ if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
+ auto r = Sk4f::Load(&rect);
+ const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
+ if (tm <= SkMatrix::kTranslate_Mask) {
+ r += t;
+ } else {
+ const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
+ r = r * s + t;
+ }
+ SkNx_shuffle<0, 0, 2, 2>(r).store(fX);
+ SkNx_shuffle<1, 3, 1, 3>(r).store(fY);
+ fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
+ fIW[0] = fIW[1] = fIW[2] = fIW[3] = 1.f;
+ } else {
+ Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
+ Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
+ Sk4f sx(m.getScaleX());
+ Sk4f kx(m.getSkewX());
+ Sk4f tx(m.getTranslateX());
+ Sk4f ky(m.getSkewY());
+ Sk4f sy(m.getScaleY());
+ Sk4f ty(m.getTranslateY());
+ SkNx_fma(sx, rx, SkNx_fma(kx, ry, tx)).store(fX);
+ SkNx_fma(ky, rx, SkNx_fma(sy, ry, ty)).store(fY);
+ if (m.hasPerspective()) {
+ Sk4f w0(m.getPerspX());
+ Sk4f w1(m.getPerspY());
+ Sk4f w2(m.get(SkMatrix::kMPersp2));
+ auto w = SkNx_fma(w0, rx, SkNx_fma(w1, ry, w2));
+ w.store(fW);
+ w.invert().store(fIW);
+ } else {
+ fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
+ fIW[0] = fIW[1] = fIW[2] = fIW[3] = 1.f;
+ }
+ }
+}
diff --git a/src/gpu/GrQuad.h b/src/gpu/GrQuad.h
index 62f025d162..74e235646b 100644
--- a/src/gpu/GrQuad.h
+++ b/src/gpu/GrQuad.h
@@ -11,6 +11,7 @@
#include "SkMatrix.h"
#include "SkNx.h"
#include "SkPoint.h"
+#include "SkPoint3.h"
/**
* GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
@@ -53,4 +54,37 @@ private:
float fY[4];
};
+class GrPerspQuad {
+public:
+ GrPerspQuad() = default;
+
+ GrPerspQuad(const SkRect&, const SkMatrix&);
+
+ GrPerspQuad& operator=(const GrPerspQuad&) = default;
+
+ SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; }
+
+ SkRect bounds() {
+ auto x = this->x4f() * this->iw4f();
+ auto y = this->y4f() * this->iw4f();
+ return {x.min(), y.min(), x.max(), y.max()};
+ }
+
+ float x(int i) const { return fX[i]; }
+ float y(int i) const { return fY[i]; }
+ float w(int i) const { return fW[i]; }
+ float iw(int i) const { return fIW[i]; }
+
+ Sk4f x4f() const { return Sk4f::Load(fX); }
+ Sk4f y4f() const { return Sk4f::Load(fY); }
+ Sk4f w4f() const { return Sk4f::Load(fW); }
+ Sk4f iw4f() const { return Sk4f::Load(fIW); }
+
+private:
+ float fX[4];
+ float fY[4];
+ float fW[4];
+ float fIW[4]; // 1/w
+};
+
#endif
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index ded50490f4..86d1dde356 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -763,16 +763,15 @@ static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ct
return !SkScalarIsInt(x) || !SkScalarIsInt(y);
}
-void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
- GrSamplerState::Filter filter, GrColor color,
- const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
- const SkMatrix& viewMatrix,
- sk_sp<GrColorSpaceXform> colorSpaceXform) {
+void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
+ GrSamplerState::Filter filter, GrColor color,
+ const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
+ const SkMatrix& viewMatrix,
+ sk_sp<GrColorSpaceXform> colorSpaceXform) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
- GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureAffine", fContext);
- SkASSERT(!viewMatrix.hasPerspective());
+ GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
if (filter != GrSamplerState::Filter::kNearest && !must_filter(srcRect, dstRect, viewMatrix)) {
filter = GrSamplerState::Filter::kNearest;
}
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 8d677ae091..1a68444b13 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -146,11 +146,11 @@ public:
* Creates an op that draws a subrectangle of a texture. The passed color is modulated by the
* texture's color. 'srcRect' specifies the rectangle of the texture to draw. 'dstRect'
* specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to
- * device space. This asserts that the view matrix does not have perspective.
+ * device space.
*/
- void drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter,
- GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
- const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>);
+ void drawTexture(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter, GrColor,
+ const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
+ const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>);
/**
* Draw a roundrect using a paint.
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 16f8ee8f9f..70c89b5776 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -88,21 +88,20 @@ static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer,
/**
* Checks whether the paint, matrix, and constraint are compatible with using
- * GrRenderTargetContext::drawTextureAffine. It is more effecient than the GrTextureProducer
+ * GrRenderTargetContext::drawTexture. It is more efficient than the GrTextureProducer
* general case.
*/
-static bool can_use_draw_texture_affine(const SkPaint& paint, GrAA aa, const SkMatrix& ctm,
- SkCanvas::SrcRectConstraint constraint) {
+static bool can_use_draw_texture(const SkPaint& paint, GrAA aa, const SkMatrix& ctm,
+ SkCanvas::SrcRectConstraint constraint) {
return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
!paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality &&
- paint.getBlendMode() == SkBlendMode::kSrcOver && !ctm.hasPerspective() &&
+ paint.getBlendMode() == SkBlendMode::kSrcOver &&
SkCanvas::kFast_SrcRectConstraint == constraint);
}
-static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src,
- const SkRect* dst, GrAA aa, sk_sp<GrTextureProxy> proxy,
- SkColorSpace* colorSpace, const GrClip& clip,
- GrRenderTargetContext* rtc) {
+static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src,
+ const SkRect* dst, GrAA aa, sk_sp<GrTextureProxy> proxy,
+ SkColorSpace* colorSpace, const GrClip& clip, GrRenderTargetContext* rtc) {
SkASSERT(!(SkToBool(src) && !SkToBool(dst)));
SkRect srcRect = src ? *src : SkRect::MakeWH(proxy->width(), proxy->height());
SkRect dstRect = dst ? *dst : srcRect;
@@ -130,8 +129,8 @@ static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const
GrColor color = GrPixelConfigIsAlphaOnly(proxy->config())
? SkColorToPremulGrColor(paint.getColor())
: SkColorAlphaToGrColor(paint.getColor());
- rtc->drawTextureAffine(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, ctm,
- std::move(csxf));
+ rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, ctm,
+ std::move(csxf));
}
//////////////////////////////////////////////////////////////////////////////
@@ -142,9 +141,9 @@ void SkGpuDevice::drawPinnedTextureProxy(sk_sp<GrTextureProxy> proxy, uint32_t p
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix, const SkPaint& paint) {
GrAA aa = GrAA(paint.isAntiAlias());
- if (can_use_draw_texture_affine(paint, aa, this->ctm(), constraint)) {
- draw_texture_affine(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), colorSpace,
- this->clip(), fRenderTargetContext.get());
+ if (can_use_draw_texture(paint, aa, this->ctm(), constraint)) {
+ draw_texture(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), colorSpace,
+ this->clip(), fRenderTargetContext.get());
return;
}
GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID,
@@ -157,7 +156,7 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix, const SkPaint& paint) {
GrAA aa = GrAA(paint.isAntiAlias());
- if (can_use_draw_texture_affine(paint, aa, viewMatrix, constraint)) {
+ if (can_use_draw_texture(paint, aa, viewMatrix, constraint)) {
sk_sp<SkColorSpace> cs;
// We've done enough checks above to allow us to pass ClampNearest() and not check for
// scaling adjustments.
@@ -167,8 +166,8 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH
if (!proxy) {
return;
}
- draw_texture_affine(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), cs.get(),
- this->clip(), fRenderTargetContext.get());
+ draw_texture(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), cs.get(),
+ this->clip(), fRenderTargetContext.get());
return;
}
this->drawTextureProducer(maker, srcRect, dstRect, constraint, viewMatrix, paint);
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index 63868916ad..269f876ddc 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -72,8 +72,7 @@ static void tesselate(intptr_t vertices,
const GrQuad* localQuad) {
SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
- SkPointPriv::SetRectTriStrip(positions, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- vertexStride);
+ SkPointPriv::SetRectTriStrip(positions, rect, vertexStride);
if (viewMatrix) {
SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 91a6927266..5b7a30dedf 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -38,18 +38,24 @@ namespace {
*/
class TextureGeometryProcessor : public GrGeometryProcessor {
public:
- struct Vertex {
- SkPoint fPosition;
+ template <typename P> struct Vertex {
+ static constexpr GrAA kAA = GrAA::kNo;
+ static constexpr bool kIsMultiTexture = false;
+ using Position = P;
+ P fPosition;
SkPoint fTextureCoords;
GrColor fColor;
};
- struct AAVertex : public Vertex {
+ template <typename P> struct AAVertex : Vertex<P> {
+ static constexpr GrAA kAA = GrAA::kYes;
SkPoint3 fEdges[4];
};
- struct MultiTextureVertex : Vertex {
+ template <typename P> struct MultiTextureVertex : Vertex<P> {
+ static constexpr bool kIsMultiTexture = true;
int fTextureIdx;
};
- struct AAMultiTextureVertex : MultiTextureVertex {
+ template <typename P> struct AAMultiTextureVertex : MultiTextureVertex<P> {
+ static constexpr GrAA kAA = GrAA::kYes;
SkPoint3 fEdges[4];
};
@@ -68,15 +74,16 @@ public:
static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt,
sk_sp<GrColorSpaceXform> csxf, bool coverageAA,
- const GrSamplerState::Filter filters[],
+ bool perspective, const GrSamplerState::Filter filters[],
const GrShaderCaps& caps) {
// We use placement new to avoid always allocating space for kMaxTextures TextureSampler
// instances.
int samplerCnt = NumSamplersToUse(proxyCnt, caps);
size_t size = sizeof(TextureGeometryProcessor) + sizeof(TextureSampler) * (samplerCnt - 1);
void* mem = GrGeometryProcessor::operator new(size);
- return sk_sp<TextureGeometryProcessor>(new (mem) TextureGeometryProcessor(
- proxies, proxyCnt, samplerCnt, std::move(csxf), coverageAA, filters, caps));
+ return sk_sp<TextureGeometryProcessor>(
+ new (mem) TextureGeometryProcessor(proxies, proxyCnt, samplerCnt, std::move(csxf),
+ coverageAA, perspective, filters, caps));
}
~TextureGeometryProcessor() override {
@@ -90,7 +97,9 @@ public:
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get()));
- b->add32(static_cast<uint32_t>(this->usesCoverageEdgeAA()));
+ uint32_t x = this->usesCoverageEdgeAA() ? 0 : 1;
+ x |= kFloat3_GrVertexAttribType == fPositions.fType ? 0 : 2;
+ b->add32(x);
}
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override {
@@ -111,9 +120,12 @@ public:
const auto& textureGP = args.fGP.cast<TextureGeometryProcessor>();
fColorSpaceXformHelper.emitCode(
args.fUniformHandler, textureGP.fColorSpaceXform.get());
- args.fVaryingHandler->setNoPerspective();
+ if (kFloat2_GrVertexAttribType == textureGP.fPositions.fType) {
+ args.fVaryingHandler->setNoPerspective();
+ }
args.fVaryingHandler->emitAttributes(textureGP);
- this->writeOutputPosition(args.fVertBuilder, gpArgs, textureGP.fPositions.fName);
+ gpArgs->fPositionVar = textureGP.fPositions.asShaderVar();
+
this->emitTransforms(args.fVertBuilder,
args.fVaryingHandler,
args.fUniformHandler,
@@ -154,21 +166,38 @@ public:
args.fFragBuilder->codeAppend(";");
if (textureGP.usesCoverageEdgeAA()) {
const char* aaDistName = nullptr;
- // When interpolation is innacurate we perform the evaluation of the edge
+ bool mulByFragCoordW = false;
+ // When interpolation is inaccurate we perform the evaluation of the edge
// equations in the fragment shader rather than interpolating values computed
// in the vertex shader.
if (!args.fShaderCaps->interpolantsAreInaccurate()) {
GrGLSLVarying aaDistVarying(kFloat4_GrSLType,
GrGLSLVarying::Scope::kVertToFrag);
- args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
- args.fVertBuilder->codeAppendf(
- R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
- dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
- dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
- dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
- aaDistVarying.vsOut(), textureGP.fPositions.fName,
- textureGP.fPositions.fName, textureGP.fPositions.fName,
- textureGP.fPositions.fName);
+ if (kFloat3_GrVertexAttribType == textureGP.fPositions.fType) {
+ args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
+ // The distance from edge equation e to homogenous point p=sk_Position
+ // is e.x*p.x/p.wx + e.y*p.y/p.w + e.z. However, we want screen space
+ // interpolation of this distance. We can do this by multiplying the
+ // varying in the VS by p.w and then multiplying by sk_FragCoord.w in
+ // the FS. So we output e.x*p.x + e.y*p.y + e.z * p.w
+ args.fVertBuilder->codeAppendf(
+ R"(%s = float4(dot(aaEdge0, %s), dot(aaEdge1, %s),
+ dot(aaEdge2, %s), dot(aaEdge3, %s));)",
+ aaDistVarying.vsOut(), textureGP.fPositions.fName,
+ textureGP.fPositions.fName, textureGP.fPositions.fName,
+ textureGP.fPositions.fName);
+ mulByFragCoordW = true;
+ } else {
+ args.fVaryingHandler->addVarying("aaDists", &aaDistVarying);
+ args.fVertBuilder->codeAppendf(
+ R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z,
+ dot(aaEdge1.xy, %s.xy) + aaEdge1.z,
+ dot(aaEdge2.xy, %s.xy) + aaEdge2.z,
+ dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)",
+ aaDistVarying.vsOut(), textureGP.fPositions.fName,
+ textureGP.fPositions.fName, textureGP.fPositions.fName,
+ textureGP.fPositions.fName);
+ }
aaDistName = aaDistVarying.fsIn();
} else {
GrGLSLVarying aaEdgeVarying[4]{
@@ -199,6 +228,9 @@ public:
args.fFragBuilder->codeAppendf(
"float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));",
aaDistName, aaDistName, aaDistName, aaDistName);
+ if (mulByFragCoordW) {
+ args.fFragBuilder->codeAppend("mindist *= sk_FragCoord.w;");
+ }
args.fFragBuilder->codeAppendf("%s = float4(clamp(mindist, 0, 1));",
args.fOutputCoverage);
} else {
@@ -229,7 +261,7 @@ private:
}
TextureGeometryProcessor(sk_sp<GrTextureProxy> proxies[], int proxyCnt, int samplerCnt,
- sk_sp<GrColorSpaceXform> csxf, bool coverageAA,
+ sk_sp<GrColorSpaceXform> csxf, bool coverageAA, bool perspective,
const GrSamplerState::Filter filters[], const GrShaderCaps& caps)
: INHERITED(kTextureGeometryProcessor_ClassID), fColorSpaceXform(std::move(csxf)) {
SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt);
@@ -242,7 +274,11 @@ private:
this->addTextureSampler(&fSamplers[i]);
}
- fPositions = this->addVertexAttrib("position", kFloat2_GrVertexAttribType);
+ if (perspective) {
+ fPositions = this->addVertexAttrib("position", kFloat3_GrVertexAttribType);
+ } else {
+ fPositions = this->addVertexAttrib("position", kFloat2_GrVertexAttribType);
+ }
fTextureCoords = this->addVertexAttrib("textureCoords", kFloat2_GrVertexAttribType);
fColors = this->addVertexAttrib("color", kUByte4_norm_GrVertexAttribType);
@@ -322,27 +358,37 @@ static void compute_quad_edges_and_outset_vertices(Sk4f* x, Sk4f* y, Sk4f* a, Sk
namespace {
// This is a class soley so it can be partially specialized (functions cannot be).
-template<GrAA, typename Vertex> class VertexAAHandler;
+template <typename Vertex, GrAA AA = Vertex::kAA, typename Position = typename Vertex::Position>
+class VertexAAHandler;
-template<typename Vertex> class VertexAAHandler<GrAA::kNo, Vertex> {
+template<typename Vertex> class VertexAAHandler<Vertex, GrAA::kNo, SkPoint> {
public:
- static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad,
+ static void AssignPositionsAndTexCoords(Vertex* vertices, const GrPerspQuad& quad,
const SkRect& texRect) {
- vertices[0].fPosition = quad.point(0);
- vertices[0].fTextureCoords = {texRect.fLeft, texRect.fTop};
- vertices[1].fPosition = quad.point(1);
- vertices[1].fTextureCoords = {texRect.fLeft, texRect.fBottom};
- vertices[2].fPosition = quad.point(2);
- vertices[2].fTextureCoords = {texRect.fRight, texRect.fTop};
- vertices[3].fPosition = quad.point(3);
- vertices[3].fTextureCoords = {texRect.fRight, texRect.fBottom};
+ SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
+ SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(Vertex));
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].fPosition = {quad.x(i), quad.y(i)};
+ }
}
};
-template<typename Vertex> class VertexAAHandler<GrAA::kYes, Vertex> {
+template<typename Vertex> class VertexAAHandler<Vertex, GrAA::kNo, SkPoint3> {
public:
- static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad,
+ static void AssignPositionsAndTexCoords(Vertex* vertices, const GrPerspQuad& quad,
const SkRect& texRect) {
+ SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(Vertex));
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].fPosition = quad.point(i);
+ }
+ }
+};
+
+template<typename Vertex> class VertexAAHandler<Vertex, GrAA::kYes, SkPoint> {
+public:
+ static void AssignPositionsAndTexCoords(Vertex* vertices, const GrPerspQuad& quad,
+ const SkRect& texRect) {
+ SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
auto x = quad.x4f();
auto y = quad.y4f();
Sk4f a, b, c;
@@ -359,7 +405,7 @@ public:
}
private:
- static void AssignTexCoords(Vertex* vertices, const GrQuad& quad, const SkRect& tex) {
+ static void AssignTexCoords(Vertex* vertices, const GrPerspQuad& quad, const SkRect& tex) {
SkMatrix q = SkMatrix::MakeAll(quad.x(0), quad.x(1), quad.x(2),
quad.y(0), quad.y(1), quad.y(2),
1.f, 1.f, 1.f);
@@ -377,14 +423,73 @@ private:
}
};
-template <typename Vertex, bool IsMultiTex> struct TexIdAssigner;
+template<typename Vertex> class VertexAAHandler<Vertex, GrAA::kYes, SkPoint3> {
+public:
+ static void AssignPositionsAndTexCoords(Vertex* vertices, const GrPerspQuad& quad,
+ const SkRect& texRect) {
+ auto x = quad.x4f();
+ auto y = quad.y4f();
+ auto iw = quad.iw4f();
+ x *= iw;
+ y *= iw;
+
+ // Get an equation for w from device space coords.
+ SkMatrix P;
+ P.setAll(x[0], y[0], 1, x[1], y[1], 1, x[2], y[2], 1);
+ SkAssertResult(P.invert(&P));
+ SkPoint3 weq{quad.w(0), quad.w(1), quad.w(2)};
+ P.mapHomogeneousPoints(&weq, &weq, 1);
+
+ Sk4f a, b, c;
+ compute_quad_edges_and_outset_vertices(&x, &y, &a, &b, &c);
+
+ // Compute new w values for the output vertices;
+ auto w = Sk4f(weq.fX) * x + Sk4f(weq.fY) * y + Sk4f(weq.fZ);
+ x *= w;
+ y *= w;
+
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].fPosition = {x[i], y[i], w[i]};
+ for (int j = 0; j < 4; ++j) {
+ vertices[i].fEdges[j] = {a[j], b[j], c[j]};
+ }
+ }
+
+ AssignTexCoords(vertices, quad, texRect);
+ }
+
+private:
+ static void AssignTexCoords(Vertex* vertices, const GrPerspQuad& quad, const SkRect& tex) {
+ SkMatrix q = SkMatrix::MakeAll(quad.x(0), quad.x(1), quad.x(2),
+ quad.y(0), quad.y(1), quad.y(2),
+ quad.w(0), quad.w(1), quad.w(2));
+ SkMatrix qinv;
+ if (!q.invert(&qinv)) {
+ return;
+ }
+ SkMatrix t = SkMatrix::MakeAll(tex.fLeft, tex.fLeft, tex.fRight,
+ tex.fTop, tex.fBottom, tex.fTop,
+ 1.f, 1.f, 1.f);
+ SkMatrix map;
+ map.setConcat(t, qinv);
+ SkPoint3 tempTexCoords[4];
+ SkMatrixPriv::MapHomogeneousPointsWithStride(map, tempTexCoords, sizeof(SkPoint3),
+ &vertices[0].fPosition, sizeof(Vertex), 4);
+ for (int i = 0; i < 4; ++i) {
+ auto invW = 1.f / tempTexCoords[i].fZ;
+ vertices[i].fTextureCoords.fX = tempTexCoords[i].fX * invW;
+ vertices[i].fTextureCoords.fY = tempTexCoords[i].fY * invW;
+ }
+ }
+};
+
+template <typename Vertex, bool MT = Vertex::kIsMultiTexture> struct TexIdAssigner;
template <typename Vertex> struct TexIdAssigner<Vertex, true> {
static void Assign(Vertex* vertices, int textureIdx) {
- vertices[0].fTextureIdx = textureIdx;
- vertices[1].fTextureIdx = textureIdx;
- vertices[2].fTextureIdx = textureIdx;
- vertices[3].fTextureIdx = textureIdx;
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].fTextureIdx = textureIdx;
+ }
}
};
@@ -393,8 +498,8 @@ template <typename Vertex> struct TexIdAssigner<Vertex, false> {
};
} // anonymous namespace
-template <typename Vertex, bool IsMultiTex, GrAA AA>
-static void tessellate_quad(const GrQuad& devQuad, const SkRect& srcRect, GrColor color,
+template <typename Vertex>
+static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, GrColor color,
GrSurfaceOrigin origin, Vertex* vertices, SkScalar iw, SkScalar ih,
int textureIdx) {
SkRect texRect = {
@@ -407,12 +512,12 @@ static void tessellate_quad(const GrQuad& devQuad, const SkRect& srcRect, GrColo
texRect.fTop = 1.f - texRect.fTop;
texRect.fBottom = 1.f - texRect.fBottom;
}
- VertexAAHandler<AA, Vertex>::AssignPositionsAndTexCoords(vertices, devQuad, texRect);
+ VertexAAHandler<Vertex>::AssignPositionsAndTexCoords(vertices, devQuad, texRect);
vertices[0].fColor = color;
vertices[1].fColor = color;
vertices[2].fColor = color;
vertices[3].fColor = color;
- TexIdAssigner<Vertex, IsMultiTex>::Assign(vertices, textureIdx);
+ TexIdAssigner<Vertex>::Assign(vertices, textureIdx);
}
/**
* Op that implements GrTextureOp::Make. It draws textured quads. Each quad can modulate against a
@@ -524,8 +629,10 @@ __attribute__((no_sanitize("float-cast-overflow")))
draw.fSrcRect = srcRect;
draw.fTextureIdx = 0;
draw.fColor = color;
- draw.fQuad = GrQuad(dstRect, viewMatrix);
- SkRect bounds = draw.fQuad.bounds();
+ fPerspective = viewMatrix.hasPerspective();
+ SkRect bounds;
+ draw.fQuad = GrPerspQuad(dstRect, viewMatrix);
+ bounds = draw.fQuad.bounds();
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds);
@@ -543,9 +650,9 @@ __attribute__((no_sanitize("float-cast-overflow")))
}
bool coverageAA = GrAAType::kCoverage == this->aaType();
- sk_sp<GrGeometryProcessor> gp =
- TextureGeometryProcessor::Make(proxiesSPs, fProxyCnt, std::move(fColorSpaceXform),
- coverageAA, filters, *target->caps().shaderCaps());
+ sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
+ proxiesSPs, fProxyCnt, std::move(fColorSpaceXform), coverageAA, fPerspective,
+ filters, *target->caps().shaderCaps());
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
@@ -568,59 +675,52 @@ __attribute__((no_sanitize("float-cast-overflow")))
SkDebugf("Could not allocate vertices\n");
return;
}
+
+// Generic lambda in C++14?
+#define TESS_VERTS(Vertex) \
+ SkASSERT(gp->getVertexStride() == sizeof(Vertex)); \
+ auto vertices = static_cast<Vertex*>(vdata); \
+ for (const auto& draw : fDraws) { \
+ auto origin = proxies[draw.fTextureIdx]->origin(); \
+ tessellate_quad<Vertex>(draw.fQuad, draw.fSrcRect, draw.fColor, origin, vertices, \
+ iw[draw.fTextureIdx], ih[draw.fTextureIdx], draw.fTextureIdx); \
+ vertices += 4; \
+ }
+
+ float iw[kMaxTextures];
+ float ih[kMaxTextures];
+ for (int t = 0; t < fProxyCnt; ++t) {
+ const auto* texture = proxies[t]->priv().peekTexture();
+ iw[t] = 1.f / texture->width();
+ ih[t] = 1.f / texture->height();
+ }
+
if (1 == fProxyCnt) {
- GrSurfaceOrigin origin = proxies[0]->origin();
- GrTexture* texture = proxies[0]->priv().peekTexture();
- float iw = 1.f / texture->width();
- float ih = 1.f / texture->height();
if (coverageAA) {
- SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::AAVertex));
- auto vertices = static_cast<TextureGeometryProcessor::AAVertex*>(vdata);
- for (int i = 0; i < fDraws.count(); ++i) {
- tessellate_quad<TextureGeometryProcessor::AAVertex, false, GrAA::kYes>(
- fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
- vertices + 4 * i, iw, ih, 0);
+ if (fPerspective) {
+ TESS_VERTS(TextureGeometryProcessor::AAVertex<SkPoint3>)
+ } else {
+ TESS_VERTS(TextureGeometryProcessor::AAVertex<SkPoint>)
}
} else {
- SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::Vertex));
- auto vertices = static_cast<TextureGeometryProcessor::Vertex*>(vdata);
- for (int i = 0; i < fDraws.count(); ++i) {
- tessellate_quad<TextureGeometryProcessor::Vertex, false, GrAA::kNo>(
- fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
- vertices + 4 * i, iw, ih, 0);
+ if (fPerspective) {
+ TESS_VERTS(TextureGeometryProcessor::Vertex<SkPoint3>)
+ } else {
+ TESS_VERTS(TextureGeometryProcessor::Vertex<SkPoint>)
}
}
} else {
- GrTexture* textures[kMaxTextures];
- float iw[kMaxTextures];
- float ih[kMaxTextures];
- for (int t = 0; t < fProxyCnt; ++t) {
- textures[t] = proxies[t]->priv().peekTexture();
- iw[t] = 1.f / textures[t]->width();
- ih[t] = 1.f / textures[t]->height();
- }
if (coverageAA) {
- SkASSERT(gp->getVertexStride() ==
- sizeof(TextureGeometryProcessor::AAMultiTextureVertex));
- auto vertices = static_cast<TextureGeometryProcessor::AAMultiTextureVertex*>(vdata);
- for (int i = 0; i < fDraws.count(); ++i) {
- auto tidx = fDraws[i].fTextureIdx;
- GrSurfaceOrigin origin = proxies[tidx]->origin();
- tessellate_quad<TextureGeometryProcessor::AAMultiTextureVertex, true,
- GrAA::kYes>(fDraws[i].fQuad, fDraws[i].fSrcRect,
- fDraws[i].fColor, origin, vertices + 4 * i,
- iw[tidx], ih[tidx], tidx);
+ if (fPerspective) {
+ TESS_VERTS(TextureGeometryProcessor::AAMultiTextureVertex<SkPoint3>)
+ } else {
+ TESS_VERTS(TextureGeometryProcessor::AAMultiTextureVertex<SkPoint>)
}
} else {
- SkASSERT(gp->getVertexStride() ==
- sizeof(TextureGeometryProcessor::MultiTextureVertex));
- auto vertices = static_cast<TextureGeometryProcessor::MultiTextureVertex*>(vdata);
- for (int i = 0; i < fDraws.count(); ++i) {
- auto tidx = fDraws[i].fTextureIdx;
- GrSurfaceOrigin origin = proxies[tidx]->origin();
- tessellate_quad<TextureGeometryProcessor::MultiTextureVertex, true, GrAA::kNo>(
- fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin,
- vertices + 4 * i, iw[tidx], ih[tidx], tidx);
+ if (fPerspective) {
+ TESS_VERTS(TextureGeometryProcessor::MultiTextureVertex<SkPoint3>)
+ } else {
+ TESS_VERTS(TextureGeometryProcessor::MultiTextureVertex<SkPoint>)
}
}
}
@@ -704,6 +804,7 @@ __attribute__((no_sanitize("float-cast-overflow")))
}
this->joinBounds(*that);
fMaxApproxDstPixelArea = SkTMax(that->fMaxApproxDstPixelArea, fMaxApproxDstPixelArea);
+ fPerspective |= that->fPerspective;
return true;
}
@@ -779,7 +880,7 @@ __attribute__((no_sanitize("float-cast-overflow")))
struct Draw {
SkRect fSrcRect;
int fTextureIdx;
- GrQuad fQuad;
+ GrPerspQuad fQuad;
GrColor fColor;
};
SkSTArray<1, Draw, true> fDraws;
@@ -795,6 +896,7 @@ __attribute__((no_sanitize("float-cast-overflow")))
GrSamplerState::Filter fFilter0;
uint8_t fProxyCnt;
unsigned fAAType : 2;
+ unsigned fPerspective : 1;
// Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
unsigned fFinalized : 1;
unsigned fAllowSRGBInputs : 1;
@@ -813,7 +915,6 @@ std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filt
GrColor color, const SkRect& srcRect, const SkRect& dstRect,
GrAAType aaType, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> csxf, bool allowSRGBInputs) {
- SkASSERT(!viewMatrix.hasPerspective());
return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, aaType, viewMatrix,
std::move(csxf), allowSRGBInputs);
}