aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrContext.cpp9
-rw-r--r--src/gpu/GrContextPriv.h5
-rw-r--r--src/gpu/GrContextThreadSafeProxyPriv.h1
-rw-r--r--src/gpu/GrDDLContext.cpp2
-rw-r--r--src/gpu/GrDirectContext.cpp6
-rw-r--r--src/gpu/GrProcessor.h1
-rw-r--r--src/gpu/SkGr.cpp86
-rw-r--r--src/gpu/SkGr.h2
-rw-r--r--src/gpu/effects/GrDitherEffect.cpp75
-rw-r--r--src/gpu/effects/GrDitherEffect.fp85
-rw-r--r--src/gpu/effects/GrDitherEffect.h67
-rw-r--r--src/gpu/effects/GrRectBlurEffect.cpp34
-rw-r--r--src/gpu/effects/GrSkSLFP.cpp268
-rw-r--r--src/gpu/effects/GrSkSLFP.h147
-rw-r--r--src/gpu/glsl/GrGLSLShaderBuilder.h2
15 files changed, 537 insertions, 253 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index caed7298ae..8380f0d711 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -37,7 +37,9 @@
#include "SkTaskGroup.h"
#include "SkUnPreMultiplyPriv.h"
#include "effects/GrConfigConversionEffect.h"
+#include "effects/GrSkSLFP.h"
#include "text/GrTextBlobCache.h"
+#include <unordered_map>
#define ASSERT_OWNED_PROXY(P) \
SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
@@ -160,7 +162,6 @@ GrContext::~GrContext() {
if (fDrawingManager) {
fDrawingManager->cleanup();
}
-
fTextureStripAtlasManager = nullptr;
delete fResourceProvider;
delete fResourceCache;
@@ -172,11 +173,13 @@ GrContext::~GrContext() {
GrContextThreadSafeProxy::GrContextThreadSafeProxy(sk_sp<const GrCaps> caps, uint32_t uniqueID,
GrBackend backend,
- const GrContextOptions& options)
+ const GrContextOptions& options,
+ sk_sp<GrSkSLFPFactoryCache> cache)
: fCaps(std::move(caps))
, fContextUniqueID(uniqueID)
, fBackend(backend)
- , fOptions(options) {}
+ , fOptions(options)
+ , fFPFactoryCache(std::move(cache)) {}
GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default;
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index 4f392f88b3..1b90dafa37 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -16,6 +16,7 @@ class GrBackendRenderTarget;
class GrOpMemoryPool;
class GrOnFlushCallbackObject;
class GrSemaphore;
+class GrSkSLFPFactory;
class GrSurfaceProxy;
class GrTextureContext;
@@ -279,6 +280,10 @@ public:
GrContextOptions::PersistentCache* getPersistentCache() { return fContext->fPersistentCache; }
+ sk_sp<GrSkSLFPFactoryCache> getFPFactoryCache() {
+ return fContext->fFPFactoryCache;
+ }
+
/** This is only useful for debug purposes */
SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fContext->fSingleOwner; } )
diff --git a/src/gpu/GrContextThreadSafeProxyPriv.h b/src/gpu/GrContextThreadSafeProxyPriv.h
index 8e299c8180..b3a4eab021 100644
--- a/src/gpu/GrContextThreadSafeProxyPriv.h
+++ b/src/gpu/GrContextThreadSafeProxyPriv.h
@@ -23,6 +23,7 @@ public:
sk_sp<const GrCaps> refCaps() const { return fProxy->fCaps; }
uint32_t contextUniqueID() const { return fProxy->fContextUniqueID; }
GrBackend backend() const { return fProxy->fBackend; }
+ sk_sp<GrSkSLFPFactoryCache> fpFactoryCache() const { return fProxy->fFPFactoryCache; }
private:
explicit GrContextThreadSafeProxyPriv(GrContextThreadSafeProxy* proxy) : fProxy(proxy) {}
diff --git a/src/gpu/GrDDLContext.cpp b/src/gpu/GrDDLContext.cpp
index 1ae640c3e3..eb5ed29e6b 100644
--- a/src/gpu/GrDDLContext.cpp
+++ b/src/gpu/GrDDLContext.cpp
@@ -19,6 +19,8 @@ public:
GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)
: INHERITED(proxy->priv().backend(), proxy->priv().contextUniqueID()) {
fCaps = proxy->priv().refCaps();
+ fFPFactoryCache = proxy->priv().fpFactoryCache();
+ SkASSERT(fFPFactoryCache);
fThreadSafeProxy = std::move(proxy);
}
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index 3e4b8ef5fa..c87078b98b 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -10,6 +10,7 @@
#include "GrContextPriv.h"
#include "GrGpu.h"
+#include "effects/GrSkSLFP.h"
#include "gl/GrGLGpu.h"
#include "mock/GrMockGpu.h"
#include "text/GrGlyphCache.h"
@@ -58,9 +59,10 @@ protected:
bool init(const GrContextOptions& options) override {
SkASSERT(fCaps); // should've been set in ctor
SkASSERT(!fThreadSafeProxy);
-
+ SkASSERT(!fFPFactoryCache);
+ fFPFactoryCache.reset(new GrSkSLFPFactoryCache());
fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(),
- fBackend, options));
+ fBackend, options, fFPFactoryCache));
if (!INHERITED::initCommon(options)) {
return false;
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 586f6d25b9..beac0e5c5a 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -131,6 +131,7 @@ public:
kGrRRectBlurEffect_ClassID,
kGrRRectShadowGeoProc_ClassID,
kGrSimpleTextureEffect_ClassID,
+ kGrSkSLFP_ClassID,
kGrSpecularLightingEffect_ClassID,
kGrSRGBEffect_ClassID,
kGrSweepGradient_ClassID,
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 5baf0d4017..9082fc4222 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -37,9 +37,49 @@
#include "SkTraceEvent.h"
#include "effects/GrBicubicEffect.h"
#include "effects/GrConstColorProcessor.h"
-#include "effects/GrDitherEffect.h"
#include "effects/GrPorterDuffXferProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"
+#include "effects/GrSkSLFP.h"
+
+const char* SKSL_DITHER_SRC = R"(
+// This controls the range of values added to color channels
+layout(key) in int rangeType;
+
+void main(int x, int y, inout half4 color) {
+ half value;
+ half range;
+ @switch (rangeType) {
+ case 0:
+ range = 1.0 / 255.0;
+ break;
+ case 1:
+ range = 1.0 / 63.0;
+ break;
+ default:
+ // Experimentally this looks better than the expected value of 1/15.
+ range = 1.0 / 15.0;
+ break;
+ }
+ @if (sk_Caps.integerSupport) {
+ // This ordered-dither code is lifted from the cpu backend.
+ uint x = uint(x);
+ uint y = uint(y);
+ uint m = (y & 1) << 5 | (x & 1) << 4 |
+ (y & 2) << 2 | (x & 2) << 1 |
+ (y & 4) >> 1 | (x & 4) >> 2;
+ value = half(m) * 1.0 / 64.0 - 63.0 / 128.0;
+ } else {
+ // Simulate the integer effect used above using step/mod. For speed, simulates a 4x4
+ // dither pattern rather than an 8x8 one.
+ half4 modValues = mod(float4(x, y, x, y), half4(2.0, 2.0, 4.0, 4.0));
+ half4 stepValues = step(modValues, half4(1.0, 1.0, 2.0, 2.0));
+ value = dot(stepValues, half4(8.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0)) - 15.0 / 32.0;
+ }
+ // For each color channel, add the random offset to the channel value and then clamp
+ // between 0 and alpha to keep the color premultiplied.
+ color = half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);
+}
+)";
GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) {
GrSurfaceDesc desc;
@@ -284,6 +324,39 @@ static inline bool blend_requires_shader(const SkBlendMode mode) {
return SkBlendMode::kDst != mode;
}
+#ifndef SK_IGNORE_GPU_DITHER
+static inline int32_t dither_range_type_for_config(GrPixelConfig dstConfig) {
+ switch (dstConfig) {
+ case kGray_8_GrPixelConfig:
+ case kGray_8_as_Lum_GrPixelConfig:
+ case kGray_8_as_Red_GrPixelConfig:
+ case kRGBA_8888_GrPixelConfig:
+ case kRGB_888_GrPixelConfig:
+ case kBGRA_8888_GrPixelConfig:
+ return 0;
+ case kRGB_565_GrPixelConfig:
+ return 1;
+ case kRGBA_4444_GrPixelConfig:
+ return 2;
+ case kUnknown_GrPixelConfig:
+ case kSRGBA_8888_GrPixelConfig:
+ case kSBGRA_8888_GrPixelConfig:
+ case kRGBA_1010102_GrPixelConfig:
+ case kAlpha_half_GrPixelConfig:
+ case kAlpha_half_as_Red_GrPixelConfig:
+ case kRGBA_float_GrPixelConfig:
+ case kRG_float_GrPixelConfig:
+ case kRGBA_half_GrPixelConfig:
+ case kAlpha_8_GrPixelConfig:
+ case kAlpha_8_as_Alpha_GrPixelConfig:
+ case kAlpha_8_as_Red_GrPixelConfig:
+ return -1;
+ }
+ SkASSERT(false);
+ return 0;
+}
+#endif
+
static inline bool skpaint_to_grpaint_impl(GrContext* context,
const GrColorSpaceInfo& colorSpaceInfo,
const SkPaint& skPaint,
@@ -411,9 +484,14 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context,
SkColorType ct = SkColorType::kRGB_565_SkColorType;
GrPixelConfigToColorType(colorSpaceInfo.config(), &ct);
if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0) {
- auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config());
- if (ditherFP) {
- grPaint->addColorFragmentProcessor(std::move(ditherFP));
+ int32_t ditherRange = dither_range_type_for_config(colorSpaceInfo.config());
+ if (ditherRange >= 0) {
+ static int ditherIndex = GrSkSLFP::NewIndex();
+ auto ditherFP = GrSkSLFP::Make(context, ditherIndex, "Dither", SKSL_DITHER_SRC,
+ &ditherRange, sizeof(ditherRange));
+ if (ditherFP) {
+ grPaint->addColorFragmentProcessor(std::move(ditherFP));
+ }
}
}
#endif
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index ec9f30a3bf..394b2f2156 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -38,6 +38,8 @@ class SkPixelRef;
class SkPixmap;
struct SkIRect;
+extern const char* SKSL_DITHER_SRC;
+
////////////////////////////////////////////////////////////////////////////////
// Color type conversions
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
deleted file mode 100644
index 17c8776524..0000000000
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrDitherEffect.fp; do not modify.
- **************************************************************************************************/
-#include "GrDitherEffect.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramBuilder.h"
-#include "GrTexture.h"
-#include "SkSLCPP.h"
-#include "SkSLUtil.h"
-class GrGLSLDitherEffect : public GrGLSLFragmentProcessor {
-public:
- GrGLSLDitherEffect() {}
- void emitCode(EmitArgs& args) override {
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- const GrDitherEffect& _outer = args.fFp.cast<GrDitherEffect>();
- (void)_outer;
- auto rangeType = _outer.rangeType();
- (void)rangeType;
- fragBuilder->codeAppendf(
- "half value;\nhalf range;\n@switch (%d) {\n case 0:\n range = "
- "0.0039215686274509803;\n break;\n case 1:\n range = "
- "0.015873015873015872;\n break;\n default:\n range = "
- "0.066666666666666666;\n break;\n}\n@if (sk_Caps.integerSupport) {\n "
- "uint x = uint(sk_FragCoord.x);\n uint y = uint(sk_FragCoord.y);\n uint m = "
- "(((((y & 1) << 5 | (x & 1) << 4) | (y & 2) << 2) | (x & 2) << 1) | (y & 4) >> 1) "
- "| (x & 4) >> 2;\n value = float(float(half(m)) / 64.0) - 0.4",
- _outer.rangeType());
- fragBuilder->codeAppendf(
- "921875;\n} else {\n half4 modValues = half4(mod(sk_FragCoord.xyxy, "
- "float4(half4(2.0, 2.0, 4.0, 4.0))));\n half4 stepValues = "
- "half4(step(float4(modValues), float4(half4(1.0, 1.0, 2.0, 2.0))));\n value = "
- "float(dot(stepValues, half4(0.5, 0.25, 0.125, 0.0625))) - 0.46875;\n}\n%s = "
- "half4(clamp(float3(%s.xyz + value * range), 0.0, float(%s.w)), %s.w);\n",
- args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)",
- args.fInputColor ? args.fInputColor : "half4(1)",
- args.fInputColor ? args.fInputColor : "half4(1)");
- }
-
-private:
- void onSetData(const GrGLSLProgramDataManager& pdman,
- const GrFragmentProcessor& _proc) override {}
-};
-GrGLSLFragmentProcessor* GrDitherEffect::onCreateGLSLInstance() const {
- return new GrGLSLDitherEffect();
-}
-void GrDitherEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- b->add32((int32_t)fRangeType);
-}
-bool GrDitherEffect::onIsEqual(const GrFragmentProcessor& other) const {
- const GrDitherEffect& that = other.cast<GrDitherEffect>();
- (void)that;
- if (fRangeType != that.fRangeType) return false;
- return true;
-}
-GrDitherEffect::GrDitherEffect(const GrDitherEffect& src)
- : INHERITED(kGrDitherEffect_ClassID, src.optimizationFlags()), fRangeType(src.fRangeType) {}
-std::unique_ptr<GrFragmentProcessor> GrDitherEffect::clone() const {
- return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(*this));
-}
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDitherEffect);
-#if GR_TEST_UTILS
-std::unique_ptr<GrFragmentProcessor> GrDitherEffect::TestCreate(GrProcessorTestData* testData) {
- float range = testData->fRandom->nextRangeF(0.001f, 0.05f);
- return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(range));
-}
-#endif
diff --git a/src/gpu/effects/GrDitherEffect.fp b/src/gpu/effects/GrDitherEffect.fp
deleted file mode 100644
index ed6c0e6b70..0000000000
--- a/src/gpu/effects/GrDitherEffect.fp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// This controls the range of values added to color channels
-layout(key) in int rangeType;
-
-@make {
- static std::unique_ptr<GrFragmentProcessor> Make(GrPixelConfig dstConfig) {
- int rangeType;
- switch (dstConfig) {
- case kGray_8_GrPixelConfig:
- case kGray_8_as_Lum_GrPixelConfig:
- case kGray_8_as_Red_GrPixelConfig:
- case kRGBA_8888_GrPixelConfig:
- case kRGB_888_GrPixelConfig:
- case kBGRA_8888_GrPixelConfig:
- rangeType = 0;
- break;
- case kRGB_565_GrPixelConfig:
- rangeType = 1;
- break;
- case kRGBA_4444_GrPixelConfig:
- rangeType = 2;
- break;
- case kUnknown_GrPixelConfig:
- case kSRGBA_8888_GrPixelConfig:
- case kSBGRA_8888_GrPixelConfig:
- case kRGBA_1010102_GrPixelConfig:
- case kAlpha_half_GrPixelConfig:
- case kAlpha_half_as_Red_GrPixelConfig:
- case kRGBA_float_GrPixelConfig:
- case kRG_float_GrPixelConfig:
- case kRGBA_half_GrPixelConfig:
- case kAlpha_8_GrPixelConfig:
- case kAlpha_8_as_Alpha_GrPixelConfig:
- case kAlpha_8_as_Red_GrPixelConfig:
- return nullptr;
- }
- return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(rangeType));
- }
-}
-
-void main() {
- half value;
- half range;
- @switch (rangeType) {
- case 0:
- range = 1.0 / 255.0;
- break;
- case 1:
- range = 1.0 / 63.0;
- break;
- default:
- // Experimentally this looks better than the expected value of 1/15.
- range = 1.0 / 15.0;
- break;
- }
- @if (sk_Caps.integerSupport) {
- // This ordered-dither code is lifted from the cpu backend.
- uint x = uint(sk_FragCoord.x);
- uint y = uint(sk_FragCoord.y);
- uint m = (y & 1) << 5 | (x & 1) << 4 |
- (y & 2) << 2 | (x & 2) << 1 |
- (y & 4) >> 1 | (x & 4) >> 2;
- value = half(m) * 1.0 / 64.0 - 63.0 / 128.0;
- } else {
- // Simulate the integer effect used above using step/mod. For speed, simulates a 4x4
- // dither pattern rather than an 8x8 one.
- half4 modValues = mod(sk_FragCoord.xyxy, half4(2.0, 2.0, 4.0, 4.0));
- half4 stepValues = step(modValues, half4(1.0, 1.0, 2.0, 2.0));
- value = dot(stepValues, half4(8.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0)) - 15.0 / 32.0;
- }
- // For each color channel, add the random offset to the channel value and then clamp
- // between 0 and alpha to keep the color premultiplied.
- sk_OutColor = half4(clamp(sk_InColor.rgb + value * range, 0, sk_InColor.a), sk_InColor.a);
-}
-
-@test(testData) {
- float range = testData->fRandom->nextRangeF(0.001f, 0.05f);
- return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(range));
-}
diff --git a/src/gpu/effects/GrDitherEffect.h b/src/gpu/effects/GrDitherEffect.h
deleted file mode 100644
index 70adc45e6a..0000000000
--- a/src/gpu/effects/GrDitherEffect.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-/**************************************************************************************************
- *** This file was autogenerated from GrDitherEffect.fp; do not modify.
- **************************************************************************************************/
-#ifndef GrDitherEffect_DEFINED
-#define GrDitherEffect_DEFINED
-#include "SkTypes.h"
-#include "GrFragmentProcessor.h"
-#include "GrCoordTransform.h"
-class GrDitherEffect : public GrFragmentProcessor {
-public:
- int rangeType() const { return fRangeType; }
-
- static std::unique_ptr<GrFragmentProcessor> Make(GrPixelConfig dstConfig) {
- int rangeType;
- switch (dstConfig) {
- case kGray_8_GrPixelConfig:
- case kGray_8_as_Lum_GrPixelConfig:
- case kGray_8_as_Red_GrPixelConfig:
- case kRGBA_8888_GrPixelConfig:
- case kRGB_888_GrPixelConfig:
- case kBGRA_8888_GrPixelConfig:
- rangeType = 0;
- break;
- case kRGB_565_GrPixelConfig:
- rangeType = 1;
- break;
- case kRGBA_4444_GrPixelConfig:
- rangeType = 2;
- break;
- case kUnknown_GrPixelConfig:
- case kSRGBA_8888_GrPixelConfig:
- case kSBGRA_8888_GrPixelConfig:
- case kRGBA_1010102_GrPixelConfig:
- case kAlpha_half_GrPixelConfig:
- case kAlpha_half_as_Red_GrPixelConfig:
- case kRGBA_float_GrPixelConfig:
- case kRG_float_GrPixelConfig:
- case kRGBA_half_GrPixelConfig:
- case kAlpha_8_GrPixelConfig:
- case kAlpha_8_as_Alpha_GrPixelConfig:
- case kAlpha_8_as_Red_GrPixelConfig:
- return nullptr;
- }
- return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(rangeType));
- }
- GrDitherEffect(const GrDitherEffect& src);
- std::unique_ptr<GrFragmentProcessor> clone() const override;
- const char* name() const override { return "DitherEffect"; }
-
-private:
- GrDitherEffect(int rangeType)
- : INHERITED(kGrDitherEffect_ClassID, kNone_OptimizationFlags), fRangeType(rangeType) {}
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
- void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
- bool onIsEqual(const GrFragmentProcessor&) const override;
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST
- int fRangeType;
- typedef GrFragmentProcessor INHERITED;
-};
-#endif
diff --git a/src/gpu/effects/GrRectBlurEffect.cpp b/src/gpu/effects/GrRectBlurEffect.cpp
index 9ade87cbe1..0e99bc05b7 100644
--- a/src/gpu/effects/GrRectBlurEffect.cpp
+++ b/src/gpu/effects/GrRectBlurEffect.cpp
@@ -46,13 +46,13 @@ public:
fProfileSizeVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
kDefault_GrSLPrecision, "profileSize");
fragBuilder->codeAppendf(
- "bool highPrecision = %s;\n@if (highPrecision) {\n float2 translatedPos = "
- "sk_FragCoord.xy - %s.xy;\n float width = %s.z - %s.x;\n float height = %s.w "
- "- %s.y;\n float2 smallDims = float2(width - float(%s), height - float(%s));\n "
- " float center = 2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0;\n float2 wh "
- "= smallDims - float2(center, center);\n half hcoord = "
- "half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n half "
- "hlookup = texture(%s, float2(float(hcoord), 0.5)).%s.w",
+ "/* key */ bool highPrecision = %s;\n@if (highPrecision) {\n float2 "
+ "translatedPos = sk_FragCoord.xy - %s.xy;\n float width = %s.z - %s.x;\n "
+ "float height = %s.w - %s.y;\n float2 smallDims = float2(width - float(%s), "
+ "height - float(%s));\n float center = 2.0 * floor(float(float(%s / 2.0) + "
+ "0.25)) - 1.0;\n float2 wh = smallDims - float2(center, center);\n half "
+ "hcoord = half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n "
+ " half hlookup = texture(%s, float2(float(hcoord), ",
(highPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(fRectVar),
args.fUniformHandler->getUniformCStr(fRectVar),
args.fUniformHandler->getUniformCStr(fRectVar),
@@ -62,16 +62,16 @@ public:
args.fUniformHandler->getUniformCStr(fProfileSizeVar),
args.fUniformHandler->getUniformCStr(fProfileSizeVar),
args.fUniformHandler->getUniformCStr(fProfileSizeVar),
- fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
- fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str());
+ fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str());
fragBuilder->codeAppendf(
- ";\n half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) / "
- "float(%s));\n half vlookup = texture(%s, float2(float(vcoord), 0.5)).%s.w;\n "
- " %s = (%s * hlookup) * vlookup;\n} else {\n half2 translatedPos = "
- "half2(sk_FragCoord.xy - %s.xy);\n half width = half(%s.z - %s.x);\n half "
- "height = half(%s.w - %s.y);\n half2 smallDims = half2(width - %s, height - "
- "%s);\n half center = half(2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0);\n "
- " half2 wh = smallDims - half2(float2(floa",
+ "0.5)).%s.w;\n half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * "
+ "wh.y) / float(%s));\n half vlookup = texture(%s, float2(float(vcoord), "
+ "0.5)).%s.w;\n %s = (%s * hlookup) * vlookup;\n} else {\n half2 "
+ "translatedPos = half2(sk_FragCoord.xy - %s.xy);\n half width = half(%s.z - "
+ "%s.x);\n half height = half(%s.w - %s.y);\n half2 smallDims = half2(width - "
+ "%s, height - %s);\n half center = half(2.0 * floor(float(float(%s / 2.0) + "
+ "0.25)) - 1.0);\n half2 wh = smallDims - half2(f",
+ fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
args.fUniformHandler->getUniformCStr(fProfileSizeVar),
fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(),
fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(),
@@ -85,7 +85,7 @@ public:
args.fUniformHandler->getUniformCStr(fProfileSizeVar),
args.fUniformHandler->getUniformCStr(fProfileSizeVar));
fragBuilder->codeAppendf(
- "t(center), float(center)));\n half hcoord = "
+ "loat2(float(center), float(center)));\n half hcoord = "
"half((abs(float(float(translatedPos.x) - 0.5 * float(width))) - 0.5 * "
"float(wh.x)) / float(%s));\n half hlookup = texture(%s, float2(float(hcoord), "
"0.5)).%s.w;\n half vcoord = half((abs(float(float(translatedPos.y) - 0.5 * "
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
new file mode 100644
index 0000000000..bc84c833d7
--- /dev/null
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -0,0 +1,268 @@
+/*
+ * 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 "GrSkSLFP.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramBuilder.h"
+#include "GrContext.h"
+#include "GrContextPriv.h"
+#include "GrTexture.h"
+#include "SkSLUtil.h"
+
+GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl)
+ : fName(name) {
+ SkSL::Program::Settings settings;
+ settings.fCaps = shaderCaps;
+ fBaseProgram = fCompiler.convertProgram(SkSL::Program::kPipelineStage_Kind,
+ SkSL::String(sksl),
+ settings);
+ if (fCompiler.errorCount()) {
+ SkDebugf("%s\n", fCompiler.errorText().c_str());
+ }
+ SkASSERT(fBaseProgram);
+ SkASSERT(!fCompiler.errorCount());
+ for (const auto& e : *fBaseProgram) {
+ if (e.fKind == SkSL::ProgramElement::kVar_Kind) {
+ SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e;
+ for (const auto& varStatement : v.fVars) {
+ const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar;
+ if (var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
+ fInputVars.push_back(&var);
+ }
+ if (var.fModifiers.fLayout.fKey) {
+ fKeyVars.push_back(&var);
+ }
+ }
+ }
+ }
+}
+
+const SkSL::Program* GrSkSLFPFactory::getSpecialization(const SkSL::String& key, const void* inputs,
+ size_t inputSize) {
+ const auto& found = fSpecializations.find(key);
+ if (found != fSpecializations.end()) {
+ return found->second.get();
+ }
+
+ std::unordered_map<SkSL::String, SkSL::Program::Settings::Value> inputMap;
+ size_t offset = 0;
+ for (const auto& v : fInputVars) {
+ SkSL::String name(v->fName);
+ if (&v->fType == fCompiler.context().fInt_Type.get()) {
+ offset = SkAlign4(offset);
+ int32_t v = *(int32_t*) (((uint8_t*) inputs) + offset);
+ inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(v)));
+ offset += sizeof(int32_t);
+ }
+ }
+ SkASSERT(offset == inputSize);
+
+ std::unique_ptr<SkSL::Program> specialized = fCompiler.specialize(*fBaseProgram, inputMap);
+ SkAssertResult(fCompiler.optimize(*specialized));
+ const SkSL::Program* result = specialized.get();
+ fSpecializations.insert(std::make_pair(key, std::move(specialized)));
+ return result;
+}
+
+class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
+public:
+ GrGLSLSkSLFP(SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs)
+ : fGLSL(glsl)
+ , fFormatArgs(formatArgs) {}
+
+ void emitCode(EmitArgs& args) override {
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ int substringStartIndex = 0;
+ int formatArgIndex = 0;
+ for (size_t i = 0; i < fGLSL.length(); ++i) {
+ char c = fGLSL[i];
+ if (c == '%') {
+ fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
+ i - substringStartIndex);
+ ++i;
+ c = fGLSL[i];
+ switch (c) {
+ case 's':
+ switch (fFormatArgs[formatArgIndex++]) {
+ case SkSL::Compiler::FormatArg::kInput:
+ fragBuilder->codeAppend(args.fInputColor ? args.fInputColor
+ : "half4(1)");
+ break;
+ case SkSL::Compiler::FormatArg::kOutput:
+ fragBuilder->codeAppend(args.fOutputColor);
+ break;
+ }
+ break;
+ default:
+ fragBuilder->codeAppendf("%c", c);
+ }
+ substringStartIndex = i + 1;
+ }
+ }
+ fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex,
+ fGLSL.length() - substringStartIndex);
+ }
+
+ // nearly-finished GLSL; still contains printf-style "%s" format tokens
+ const SkSL::String fGLSL;
+ std::vector<SkSL::Compiler::FormatArg> fFormatArgs;
+};
+
+std::unique_ptr<GrFragmentProcessor> GrSkSLFP::Make(GrContext* context, int index, const char* name,
+ const char* sksl, const void* inputs,
+ size_t inputSize) {
+ return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP(
+ context->contextPriv().getFPFactoryCache(),
+ context->contextPriv().caps()->shaderCaps(),
+ index, name, sksl, inputs, inputSize));
+}
+
+
+GrSkSLFP::GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps,
+ int index, const char* name, const char* sksl, const void* inputs,
+ size_t inputSize)
+ : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
+ , fFactoryCache(factoryCache)
+ , fShaderCaps(sk_ref_sp(shaderCaps))
+ , fIndex(index)
+ , fName(name)
+ , fSkSL(sksl)
+ , fInputs(new int8_t[inputSize])
+ , fInputSize(inputSize) {
+ memcpy(fInputs.get(), inputs, inputSize);
+}
+
+GrSkSLFP::GrSkSLFP(const GrSkSLFP& other)
+ : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags)
+ , fFactoryCache(other.fFactoryCache)
+ , fShaderCaps(other.fShaderCaps)
+ , fFactory(other.fFactory)
+ , fIndex(other.fIndex)
+ , fName(other.fName)
+ , fSkSL(other.fSkSL)
+ , fInputs(new int8_t[other.fInputSize])
+ , fInputSize(other.fInputSize) {
+ memcpy(fInputs.get(), other.fInputs.get(), fInputSize);
+}
+
+const char* GrSkSLFP::name() const {
+ return fName;
+}
+
+void GrSkSLFP::createFactory() const {
+ if (!fFactory) {
+ fFactory = fFactoryCache->get(fIndex);
+ if (!fFactory) {
+ fFactory = sk_sp<GrSkSLFPFactory>(new GrSkSLFPFactory(fName, fShaderCaps.get(), fSkSL));
+ fFactoryCache->set(fIndex, fFactory);
+ }
+ }
+}
+
+GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
+ this->createFactory();
+ const SkSL::Program* specialized = fFactory->getSpecialization(fKey, fInputs.get(), fInputSize);
+ SkSL::String glsl;
+ std::vector<SkSL::Compiler::FormatArg> formatArgs;
+ if (!fFactory->fCompiler.toPipelineStage(*specialized, &glsl, &formatArgs)) {
+ printf("%s\n", fFactory->fCompiler.errorText().c_str());
+ abort();
+ }
+ return new GrGLSLSkSLFP(glsl, formatArgs);
+}
+
+void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ this->createFactory();
+ size_t offset = 0;
+ char* inputs = (char*) fInputs.get();
+ for (const auto& v : fFactory->fInputVars) {
+ if (&v->fType == fFactory->fCompiler.context().fInt_Type.get()) {
+ offset = SkAlign4(offset);
+ if (v->fModifiers.fLayout.fKey) {
+ fKey += inputs[offset + 0];
+ fKey += inputs[offset + 1];
+ fKey += inputs[offset + 2];
+ fKey += inputs[offset + 3];
+ b->add32(*(int32_t*) (inputs + offset));
+ }
+ offset += sizeof(int32_t);
+ }
+ else {
+ // unsupported input var type
+ SkASSERT(false);
+ }
+ }
+ SkASSERT(offset == fInputSize);
+}
+
+bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const {
+ const GrSkSLFP& sk = other.cast<GrSkSLFP>();
+ SkASSERT(fIndex != sk.fIndex || fInputSize == sk.fInputSize);
+ return fIndex == sk.fIndex &&
+ !memcmp(fInputs.get(), sk.fInputs.get(), fInputSize);
+}
+
+std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const {
+ return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP(*this));
+}
+
+// We have to do a bit of manual refcounting in the cache methods below. Ideally, we could just
+// define fFactories to contain sk_sp<GrSkSLFPFactory> rather than GrSkSLFPFactory*, but that would
+// require GrContext to include GrSkSLFP, which creates much bigger headaches than a few manual
+// refcounts.
+
+sk_sp<GrSkSLFPFactory> GrSkSLFPFactoryCache::get(int index) {
+ if (index >= (int) fFactories.size()) {
+ return nullptr;
+ }
+ GrSkSLFPFactory* result = fFactories[index];
+ result->ref();
+ return sk_sp<GrSkSLFPFactory>(result);
+}
+
+void GrSkSLFPFactoryCache::set(int index, sk_sp<GrSkSLFPFactory> factory) {
+ while (index >= (int) fFactories.size()) {
+ fFactories.emplace_back();
+ }
+ factory->ref();
+ SkASSERT(!fFactories[index]);
+ fFactories[index] = factory.get();
+}
+
+GrSkSLFPFactoryCache::~GrSkSLFPFactoryCache() {
+ for (GrSkSLFPFactory* factory : fFactories) {
+ if (factory) {
+ factory->unref();
+ }
+ }
+}
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP);
+
+#if GR_TEST_UTILS
+
+#include "SkGr.h"
+
+using Value = SkSL::Program::Settings::Value;
+
+std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) {
+ int type = d->fRandom->nextULessThan(1);
+ switch (type) {
+ case 0: {
+ static int ditherIndex = NewIndex();
+ int rangeType = d->fRandom->nextULessThan(3);
+ return GrSkSLFP::Make(d->context(), ditherIndex, "Dither", SKSL_DITHER_SRC, &rangeType,
+ sizeof(rangeType));
+ }
+ }
+ SK_ABORT("unreachable");
+ return nullptr;
+}
+
+#endif
diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h
new file mode 100644
index 0000000000..428e0892e0
--- /dev/null
+++ b/src/gpu/effects/GrSkSLFP.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrSkSLFP_DEFINED
+#define GrSkSLFP_DEFINED
+
+#include "GrCaps.h"
+#include "GrFragmentProcessor.h"
+#include "GrCoordTransform.h"
+#include "GrShaderCaps.h"
+#include "SkSLCompiler.h"
+#include "SkSLPipelineStageCodeGenerator.h"
+#include "SkRefCnt.h"
+#include "../private/GrSkSLFPFactoryCache.h"
+
+class GrContext;
+class GrSkSLFPFactory;
+
+class GrSkSLFP : public GrFragmentProcessor {
+public:
+ /**
+ * Returns a new unique identifier. Each different SkSL fragment processor should call
+ * NewIndex once, statically, and use this index for all calls to Make.
+ */
+ static int NewIndex() {
+ static int index = 0;
+ return sk_atomic_inc(&index);
+ }
+
+ /**
+ * Creates a new fragment processor from an SkSL source string and a struct of inputs to the
+ * program. The input struct's type is derived from the 'in' variables in the SkSL source, so
+ * e.g. the shader:
+ *
+ * in bool dither;
+ * in float x;
+ * in float y;
+ * ....
+ *
+ * would expect a pointer to a struct set up like:
+ *
+ * struct {
+ * bool dither;
+ * float x;
+ * float y;
+ * };
+ *
+ * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
+ * based on the inputs, internally the process is divided into two steps: we first parse and
+ * semantically analyze the SkSL into an internal representation, and then "specialize" this
+ * internal representation based on the inputs. The unspecialized internal representation of
+ * the program is cached, so further specializations of the same code are much faster than the
+ * first call.
+ *
+ * This caching is based on the 'index' parameter, which should be derived by statically calling
+ * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
+ * associated with it.
+ */
+ static std::unique_ptr<GrFragmentProcessor> Make(
+ GrContext* context,
+ int index,
+ const char* name,
+ const char* sksl,
+ const void* inputs,
+ size_t inputSize);
+
+ const char* name() const override;
+
+ std::unique_ptr<GrFragmentProcessor> clone() const override;
+
+private:
+ GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex,
+ const char* name, const char* sksl, const void* inputs, size_t inputSize);
+
+ GrSkSLFP(const GrSkSLFP& other);
+
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+
+ void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
+
+ bool onIsEqual(const GrFragmentProcessor&) const override;
+
+ void createFactory() const;
+
+ sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
+
+ const sk_sp<GrShaderCaps> fShaderCaps;
+
+ mutable sk_sp<GrSkSLFPFactory> fFactory;
+
+ int fIndex;
+
+ const char* fName;
+
+ const char* fSkSL;
+
+ const std::unique_ptr<int8_t[]> fInputs;
+
+ size_t fInputSize;
+
+ mutable SkSL::String fKey;
+
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST
+
+ typedef GrFragmentProcessor INHERITED;
+
+ friend class GrSkSLFPFactory;
+};
+
+/**
+ * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
+ * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
+ * string, then use that to create the actual GrFragmentProcessor.
+ */
+class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
+public:
+ /**
+ * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
+ * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
+ * the produced shaders to differ), so it is important to reuse the same factory instance for
+ * the same shader in order to avoid repeatedly re-parsing the SkSL.
+ */
+ GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl);
+
+ const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
+ size_t inputSize);
+
+ const char* fName;
+
+ SkSL::Compiler fCompiler;
+
+ std::shared_ptr<SkSL::Program> fBaseProgram;
+
+ std::vector<const SkSL::Variable*> fInputVars;
+
+ std::vector<const SkSL::Variable*> fKeyVars;
+
+ std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
+
+ friend class GrSkSLFP;
+};
+
+#endif
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index 538300d95a..f61174f2d7 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -102,6 +102,8 @@ public:
void codeAppend(const char* str) { this->code().append(str); }
+ void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
+
void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
va_list args;
va_start(args, format);