aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Jim Van Verth <jvanverth@google.com>2018-01-25 16:26:25 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-01-26 13:54:54 +0000
commitfc4f768e5aaf8efdd112f38295a35de83a0f9a55 (patch)
tree64571d9e826dd917299fd4973111732dd76ddcb1
parentfc807c885b3cce6252cc1d057098d96f8e14eadc (diff)
Use int when possible to calculate atlas indices in shaders.
On certain iOS devices half has a mantissa of only 10 bits, which is not enough to perform the floating point trickery to get the lower bits out of the "texture coordinates". Instead we use int if available, and float if not available. Also re-enables multitexturing for iOS and adds a sample which stresses the issue, and a version of fontcache that tests multitexturing. Bug: skia:7285 Change-Id: Ia541b6a418c1860c941071750ceb26459eb846ea Reviewed-on: https://skia-review.googlesource.com/99800 Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
-rw-r--r--gm/fontcache.cpp41
-rw-r--r--gn/samples.gni1
-rw-r--r--samplecode/SampleFlutterAnimate.cpp115
-rw-r--r--src/gpu/GrContext.cpp20
-rw-r--r--src/gpu/effects/GrAtlasedShaderHelpers.h28
-rw-r--r--src/gpu/effects/GrBitmapTextGeoProc.cpp3
-rw-r--r--src/gpu/effects/GrDistanceFieldGeoProc.cpp9
-rw-r--r--src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp40
8 files changed, 223 insertions, 34 deletions
diff --git a/gm/fontcache.cpp b/gm/fontcache.cpp
index ce919e9df5..f7a1313fb9 100644
--- a/gm/fontcache.cpp
+++ b/gm/fontcache.cpp
@@ -5,6 +5,13 @@
* found in the LICENSE file.
*/
+// GM to stress the GPU font cache
+// It's not necessary to run this with CPU configs
+
+#include "gm.h"
+
+#if SK_SUPPORT_GPU
+
#include "GrContext.h"
#include "GrContextOptions.h"
#include "SkCanvas.h"
@@ -14,8 +21,6 @@
#include "gm.h"
#include "sk_tool_utils.h"
-// GM to stress the GPU font cache
-
static SkScalar draw_string(SkCanvas* canvas, const SkString& text, SkScalar x,
SkScalar y, const SkPaint& paint) {
canvas->drawString(text, x, y, paint);
@@ -24,16 +29,23 @@ static SkScalar draw_string(SkCanvas* canvas, const SkString& text, SkScalar x,
class FontCacheGM : public skiagm::GM {
public:
- FontCacheGM() { this->setBGColor(SK_ColorLTGRAY); }
+ FontCacheGM(GrContextOptions::Enable allowMultipleTextures)
+ : fAllowMultipleTextures(allowMultipleTextures) {
+ this->setBGColor(SK_ColorLTGRAY);
+ }
void modifyGrContextOptions(GrContextOptions* options) override {
options->fGlyphCacheTextureMaximumBytes = 0;
- options->fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo;
+ options->fAllowMultipleGlyphCacheTextures = fAllowMultipleTextures;
}
protected:
SkString onShortName() override {
- return SkString("fontcache");
+ SkString name("fontcache");
+ if (GrContextOptions::Enable::kYes == fAllowMultipleTextures) {
+ name.append("-mt");
+ }
+ return name;
}
SkISize onISize() override { return SkISize::Make(kSize, kSize); }
@@ -49,9 +61,15 @@ protected:
}
void onDraw(SkCanvas* canvas) override {
+ GrRenderTargetContext* renderTargetContext =
+ canvas->internal_private_accessTopLayerRenderTargetContext();
+ if (!renderTargetContext) {
+ skiagm::GM::DrawGpuOnlyMessage(canvas);
+ return;
+ }
+
canvas->clear(SK_ColorLTGRAY);
this->drawText(canvas);
-#if SK_SUPPORT_GPU
// Debugging tool for GPU.
static const bool kShowAtlas = false;
if (kShowAtlas) {
@@ -60,7 +78,6 @@ protected:
canvas->drawImage(img, 0, 0);
}
}
-#endif
}
private:
@@ -83,6 +100,10 @@ private:
SkScalar subpixelY = 0;
bool offsetX = true;
+ if (GrContextOptions::Enable::kYes == fAllowMultipleTextures) {
+ canvas->scale(10, 10);
+ }
+
do {
for (auto s : kSizes) {
auto size = 2 * s;
@@ -109,6 +130,7 @@ private:
static constexpr SkScalar kSize = 1280;
+ GrContextOptions::Enable fAllowMultipleTextures;
sk_sp<SkTypeface> fTypefaces[6];
typedef GM INHERITED;
};
@@ -117,4 +139,7 @@ constexpr SkScalar FontCacheGM::kSize;
//////////////////////////////////////////////////////////////////////////////
-DEF_GM(return new FontCacheGM;)
+DEF_GM(return new FontCacheGM(GrContextOptions::Enable::kNo))
+DEF_GM(return new FontCacheGM(GrContextOptions::Enable::kYes))
+
+#endif
diff --git a/gn/samples.gni b/gn/samples.gni
index 3ee15aed85..48c580c2a3 100644
--- a/gn/samples.gni
+++ b/gn/samples.gni
@@ -47,6 +47,7 @@ samples_sources = [
"$_samplecode/SampleFilter2.cpp",
"$_samplecode/SampleFilterFuzz.cpp",
"$_samplecode/SampleFilterQuality.cpp",
+ "$_samplecode/SampleFlutterAnimate.cpp",
"$_samplecode/SampleFontScalerTest.cpp",
"$_samplecode/SampleFuzz.cpp",
"$_samplecode/SampleGradients.cpp",
diff --git a/samplecode/SampleFlutterAnimate.cpp b/samplecode/SampleFlutterAnimate.cpp
new file mode 100644
index 0000000000..813572934e
--- /dev/null
+++ b/samplecode/SampleFlutterAnimate.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 "SampleCode.h"
+#include "SkAnimTimer.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkUtils.h"
+#include "SkColorPriv.h"
+#include "SkColorFilter.h"
+#include "SkImage.h"
+#include "SkRandom.h"
+#include "SkTime.h"
+#include "SkTypeface.h"
+#include "Timer.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#endif
+
+// Create an animation of a bunch of letters that rotate in place. This is intended to stress
+// the glyph atlas and test that we don't see corruption or bad slowdowns.
+class FlutterAnimateView : public SampleView {
+public:
+ FlutterAnimateView() : fCurrTime(0), fResetTime(0) {}
+
+protected:
+ void onOnceBeforeDraw() override {
+ fTypeface = SkTypeface::MakeFromFile("/skimages/samplefont.ttf");
+ initChars();
+ }
+
+ // overrides from SkEventSink
+ bool onQuery(SkEvent* evt) override {
+ if (SampleCode::TitleQ(*evt)) {
+ SampleCode::TitleR(evt, "FlutterAnimate");
+ return true;
+ }
+
+ return this->INHERITED::onQuery(evt);
+ }
+
+ void onDrawContent(SkCanvas* canvas) override {
+ SkPaint paint;
+ paint.setTypeface(fTypeface);
+ paint.setAntiAlias(true);
+ paint.setFilterQuality(kMedium_SkFilterQuality);
+ paint.setTextSize(50);
+
+ // rough center of each glyph
+ static constexpr auto kMidX = 35;
+ static constexpr auto kMidY = 50;
+
+ canvas->clear(SK_ColorWHITE);
+ for (int i = 0; i < kNumChars; ++i) {
+ canvas->save();
+ double rot = SkScalarInterp(fChars[i].fStartRotation, fChars[i].fEndRotation,
+ fCurrTime/kDuration);
+ canvas->translate(fChars[i].fPosition.fX + kMidX, fChars[i].fPosition.fY - kMidY);
+ canvas->rotate(SkRadiansToDegrees(rot));
+ canvas->translate(-35,+50);
+ canvas->drawString(fChars[i].fChar, 0, 0, paint);
+ canvas->restore();
+ }
+ }
+
+ bool onAnimate(const SkAnimTimer& timer) override {
+ fCurrTime = timer.secs() - fResetTime;
+ if (fCurrTime > kDuration) {
+ this->initChars();
+ fResetTime = timer.secs();
+ fCurrTime = 0;
+ }
+
+ return true;
+ }
+
+private:
+ void initChars() {
+ for (int i = 0; i < kNumChars; ++i) {
+ char c = fRand.nextULessThan(26) + 65;
+ fChars[i].fChar[0] = c;
+ fChars[i].fChar[1] = '\0';
+ fChars[i].fPosition = SkPoint::Make(fRand.nextF()*748 + 10, fRand.nextF()*1004 + 10);
+ fChars[i].fStartRotation = fRand.nextF();
+ fChars[i].fEndRotation = fRand.nextF() * 20 - 10;
+ }
+ }
+
+ static constexpr double kDuration = 5.0;
+ double fCurrTime;
+ double fResetTime;
+ SkRandom fRand;
+
+ struct AnimatedChar {
+ char fChar[2];
+ SkPoint fPosition;
+ SkScalar fStartRotation;
+ SkScalar fEndRotation;
+ };
+ sk_sp<SkTypeface> fTypeface;
+ static constexpr int kNumChars = 40;
+ AnimatedChar fChars[kNumChars];
+
+ typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new FlutterAnimateView; }
+static SkViewRegister reg(MyFactory);
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index f6c66db223..d1060235f9 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -277,20 +277,12 @@ bool GrContext::init(const GrContextOptions& options) {
new GrDrawingManager(this, prcOptions, atlasTextContextOptions, &fSingleOwner));
GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
- switch (options.fAllowMultipleGlyphCacheTextures) {
- case GrContextOptions::Enable::kDefault:
-#ifdef SK_BUILD_FOR_IOS
- allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
-#else
- allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
-#endif
- break;
- case GrContextOptions::Enable::kNo:
- allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
- break;
- case GrContextOptions::Enable::kYes:
- allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
- break;
+ if (GrContextOptions::Enable::kNo == options.fAllowMultipleGlyphCacheTextures ||
+ // multitexturing supported only if range can represent the index + texcoords fully
+ !(fCaps->shaderCaps()->floatIs32Bits() || fCaps->shaderCaps()->integerSupport())) {
+ allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo;
+ } else {
+ allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes;
}
fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes,
allowMultitexturing);
diff --git a/src/gpu/effects/GrAtlasedShaderHelpers.h b/src/gpu/effects/GrAtlasedShaderHelpers.h
index 99bbcc0606..8c09291d6a 100644
--- a/src/gpu/effects/GrAtlasedShaderHelpers.h
+++ b/src/gpu/effects/GrAtlasedShaderHelpers.h
@@ -8,6 +8,7 @@
#ifndef GrAtlasedShaderHelpers_DEFINED
#define GrAtlasedShaderHelpers_DEFINED
+#include "GrShaderCaps.h"
#include "glsl/GrGLSLPrimitiveProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLVarying.h"
@@ -22,22 +23,33 @@ static void append_index_uv_varyings(GrGLSLPrimitiveProcessor::EmitArgs& args,
// This extracts the texture index and texel coordinates from the same variable
// Packing structure: texel coordinates are multiplied by 2 (or shifted left 1)
// texture index is stored as lower bits of both x and y
- args.fVertBuilder->codeAppendf("half2 indexTexCoords = half2(%s.x, %s.y);",
- inTexCoordsName, inTexCoordsName);
- args.fVertBuilder->codeAppend("half2 intCoords = floor(0.5*indexTexCoords);");
- args.fVertBuilder->codeAppend("half2 diff = indexTexCoords - 2.0*intCoords;");
- args.fVertBuilder->codeAppend("half texIdx = 2.0*diff.x + diff.y;");
+ if (args.fShaderCaps->integerSupport()) {
+ args.fVertBuilder->codeAppendf("int2 signedCoords = int2(%s.x, %s.y);",
+ inTexCoordsName, inTexCoordsName);
+ args.fVertBuilder->codeAppend("int texIdx = 2*(signedCoords.x & 0x1) + (signedCoords.y & 0x1);");
+ args.fVertBuilder->codeAppend("float2 unormTexCoords = float2(signedCoords.x/2, signedCoords.y/2);");
+ } else {
+ args.fVertBuilder->codeAppendf("float2 indexTexCoords = float2(%s.x, %s.y);",
+ inTexCoordsName, inTexCoordsName);
+ args.fVertBuilder->codeAppend("float2 unormTexCoords = floor(0.5*indexTexCoords);");
+ args.fVertBuilder->codeAppend("float2 diff = indexTexCoords - 2.0*unormTexCoords;");
+ args.fVertBuilder->codeAppend("float texIdx = 2.0*diff.x + diff.y;");
+ }
// Multiply by 1/atlasSize to get normalized texture coordinates
args.fVaryingHandler->addVarying("TextureCoords", uv);
- args.fVertBuilder->codeAppendf("%s = intCoords * %s;", uv->vsOut(), atlasSizeInvName);
+ args.fVertBuilder->codeAppendf("%s = unormTexCoords * %s;", uv->vsOut(), atlasSizeInvName);
- args.fVaryingHandler->addVarying("TexIndex", texIdx);
+ if (args.fShaderCaps->integerSupport()) {
+ args.fVaryingHandler->addFlatVarying("TexIndex", texIdx);
+ } else {
+ args.fVaryingHandler->addVarying("TexIndex", texIdx);
+ }
args.fVertBuilder->codeAppendf("%s = texIdx;", texIdx->vsOut());
if (st) {
args.fVaryingHandler->addVarying("IntTextureCoords", st);
- args.fVertBuilder->codeAppendf("%s = intCoords;", st->vsOut());
+ args.fVertBuilder->codeAppendf("%s = unormTexCoords;", st->vsOut());
}
}
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index ae1340badc..a9ebdca89f 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -38,7 +38,8 @@ public:
&atlasSizeInvName);
GrGLSLVarying uv(kFloat2_GrSLType);
- GrGLSLVarying texIdx(kHalf_GrSLType);
+ GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
+ GrGLSLVarying texIdx(texIdxType);
append_index_uv_varyings(args, btgp.inTextureCoords()->fName, atlasSizeInvName,
&uv, &texIdx, nullptr);
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index d8944fa9d0..8a1a4de2d1 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -66,7 +66,8 @@ public:
// add varyings
GrGLSLVarying uv(kFloat2_GrSLType);
- GrGLSLVarying texIdx(kHalf_GrSLType);
+ GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
+ GrGLSLVarying texIdx(texIdxType);
GrGLSLVarying st(kFloat2_GrSLType);
append_index_uv_varyings(args, dfTexEffect.inTextureCoords()->fName, atlasSizeInvName,
&uv, &texIdx, &st);
@@ -325,7 +326,8 @@ public:
&atlasSizeInvName);
GrGLSLVarying uv(kFloat2_GrSLType);
- GrGLSLVarying texIdx(kHalf_GrSLType);
+ GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
+ GrGLSLVarying texIdx(texIdxType);
GrGLSLVarying st(kFloat2_GrSLType);
append_index_uv_varyings(args, dfPathEffect.inTextureCoords()->fName, atlasSizeInvName, &uv,
&texIdx, &st);
@@ -608,7 +610,8 @@ public:
// set up varyings
GrGLSLVarying uv(kFloat2_GrSLType);
- GrGLSLVarying texIdx(kHalf_GrSLType);
+ GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
+ GrGLSLVarying texIdx(texIdxType);
GrGLSLVarying st(kFloat2_GrSLType);
append_index_uv_varyings(args, dfTexEffect.inTextureCoords()->fName, atlasSizeInvName,
&uv, &texIdx, &st);
diff --git a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
index 1ae2c79fd4..384596ddb6 100644
--- a/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
+++ b/src/gpu/text/GrAtlasTextBlobVertexRegenerator.cpp
@@ -38,6 +38,11 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
bool useDistanceFields, SkScalar transX, SkScalar transY,
GrColor color) {
uint16_t u0, v0, u1, v1;
+#ifdef DISPLAY_PAGE_INDEX
+ // Enable this to visualize the page from which each glyph is being drawn.
+ // Green Red Magenta Cyan -> 0 1 2 3; Black -> error
+ SkColor hackColor;
+#endif
if (regenTexCoords) {
SkASSERT(glyph);
int width = glyph->fBounds.width();
@@ -67,6 +72,25 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
u1 |= uBit;
v1 <<= 1;
v1 |= vBit;
+#ifdef DISPLAY_PAGE_INDEX
+ switch (pageIndex) {
+ case 0:
+ hackColor = SK_ColorGREEN;
+ break;
+ case 1:
+ hackColor = SK_ColorRED;
+ break;
+ case 2:
+ hackColor = SK_ColorMAGENTA;
+ break;
+ case 3:
+ hackColor = SK_ColorCYAN;
+ break;
+ default:
+ hackColor = SK_ColorBLACK;
+ break;
+ }
+#endif
}
// This is a bit wonky, but sometimes we have LCD text, in which case we won't have color
@@ -90,6 +114,10 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
textureCoords[0] = u0;
textureCoords[1] = v0;
+#ifdef DISPLAY_PAGE_INDEX
+ SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
+ *vcolor = hackColor;
+#endif
}
vertex += vertexStride;
@@ -109,6 +137,10 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
textureCoords[0] = u0;
textureCoords[1] = v1;
+#ifdef DISPLAY_PAGE_INDEX
+ SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
+ *vcolor = hackColor;
+#endif
}
vertex += vertexStride;
@@ -128,6 +160,10 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
textureCoords[0] = u1;
textureCoords[1] = v0;
+#ifdef DISPLAY_PAGE_INDEX
+ SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
+ *vcolor = hackColor;
+#endif
}
vertex += vertexStride;
@@ -147,6 +183,10 @@ inline void regen_vertices(char* vertex, const GrGlyph* glyph, size_t vertexStri
uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset);
textureCoords[0] = u1;
textureCoords[1] = v1;
+#ifdef DISPLAY_PAGE_INDEX
+ SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + colorOffset);
+ *vcolor = hackColor;
+#endif
}
}