Remove generic GrFragmentProcessor texture sampling.
Instead GrTextureEffect is a special effect known by
program builders, pipeline states, etc.
Change-Id: I4436d7a10a1c3174fe1f02f136363a1c117f92fb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301357
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index c16014c..1f89155 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -21,14 +21,6 @@
if (this->classID() != that.classID()) {
return false;
}
- if (this->numTextureSamplers() != that.numTextureSamplers()) {
- return false;
- }
- for (int i = 0; i < this->numTextureSamplers(); ++i) {
- if (this->textureSampler(i) != that.textureSampler(i)) {
- return false;
- }
- }
if (this->usesVaryingCoordsDirectly() != that.usesVaryingCoordsDirectly()) {
return false;
}
@@ -46,11 +38,35 @@
return true;
}
-void GrFragmentProcessor::visitProxies(const GrOp::VisitProxyFunc& func) {
- for (auto [sampler, fp] : FPTextureSamplerRange(*this)) {
- bool mipped = (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter());
- func(sampler.view().proxy(), GrMipMapped(mipped));
+void GrFragmentProcessor::visitProxies(const GrOp::VisitProxyFunc& func) const {
+ this->visitTextureEffects([&func](const GrTextureEffect& te) {
+ bool mipped = (GrSamplerState::Filter::kMipMap == te.samplerState().filter());
+ func(te.view().proxy(), GrMipMapped(mipped));
+ });
+}
+
+void GrFragmentProcessor::visitTextureEffects(
+ const std::function<void(const GrTextureEffect&)>& func) const {
+ if (auto* te = this->asTextureEffect()) {
+ func(*te);
}
+ for (auto& child : fChildProcessors) {
+ child->visitTextureEffects(func);
+ }
+}
+
+GrTextureEffect* GrFragmentProcessor::asTextureEffect() {
+ if (this->classID() == kGrTextureEffect_ClassID) {
+ return static_cast<GrTextureEffect*>(this);
+ }
+ return nullptr;
+}
+
+const GrTextureEffect* GrFragmentProcessor::asTextureEffect() const {
+ if (this->classID() == kGrTextureEffect_ClassID) {
+ return static_cast<const GrTextureEffect*>(this);
+ }
+ return nullptr;
}
GrGLSLFragmentProcessor* GrFragmentProcessor::createGLSLInstance() const {
@@ -62,11 +78,6 @@
return glFragProc;
}
-const GrFragmentProcessor::TextureSampler& GrFragmentProcessor::textureSampler(int i) const {
- SkASSERT(i >= 0 && i < fTextureSamplerCnt);
- return this->onTextureSampler(i);
-}
-
void GrFragmentProcessor::addAndPushFlagToChildren(PrivateFlags flag) {
// This propagates down, so if we've already marked it, all our children should have it too
if (!(fFlags & flag)) {
@@ -84,19 +95,13 @@
#ifdef SK_DEBUG
bool GrFragmentProcessor::isInstantiated() const {
- for (int i = 0; i < fTextureSamplerCnt; ++i) {
- if (!this->textureSampler(i).isInstantiated()) {
- return false;
+ bool result = true;
+ this->visitTextureEffects([&result](const GrTextureEffect& te) {
+ if (!te.texture()) {
+ result = false;
}
- }
-
- for (int i = 0; i < this->numChildProcessors(); ++i) {
- if (!this->childProcessor(i).isInstantiated()) {
- return false;
- }
- }
-
- return true;
+ });
+ return result;
}
#endif
@@ -449,41 +454,8 @@
}
}
-GrFragmentProcessor::CIter::CIter(const GrProcessorSet& set) {
- for (int i = set.numCoverageFragmentProcessors() - 1; i >= 0; --i) {
- fFPStack.push_back(set.coverageFragmentProcessor(i));
- }
- for (int i = set.numColorFragmentProcessors() - 1; i >= 0; --i) {
- fFPStack.push_back(set.colorFragmentProcessor(i));
- }
-}
-
GrFragmentProcessor::CIter::CIter(const GrPipeline& pipeline) {
for (int i = pipeline.numFragmentProcessors() - 1; i >= 0; --i) {
fFPStack.push_back(&pipeline.getFragmentProcessor(i));
}
}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-GrFragmentProcessor::TextureSampler::TextureSampler(GrSurfaceProxyView view,
- GrSamplerState samplerState)
- : fView(std::move(view)), fSamplerState(samplerState) {
- GrSurfaceProxy* proxy = this->proxy();
- fSamplerState.setFilterMode(
- std::min(samplerState.filter(),
- GrTextureProxy::HighestFilterMode(proxy->backendFormat().textureType())));
-}
-
-#if GR_TEST_UTILS
-void GrFragmentProcessor::TextureSampler::set(GrSurfaceProxyView view,
- GrSamplerState samplerState) {
- SkASSERT(view.proxy()->asTextureProxy());
- fView = std::move(view);
- fSamplerState = samplerState;
-
- fSamplerState.setFilterMode(
- std::min(samplerState.filter(),
- GrTextureProxy::HighestFilterMode(this->proxy()->backendFormat().textureType())));
-}
-#endif
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 7ea426d..fe634b3 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -20,14 +20,13 @@
class GrProcessorKeyBuilder;
class GrShaderCaps;
class GrSwizzle;
+class GrTextureEffect;
/** Provides custom fragment shader code. Fragment processors receive an input color (half4) and
produce an output color. They may reference textures and uniforms.
*/
class GrFragmentProcessor : public GrProcessor {
public:
- class TextureSampler;
-
/**
* In many instances (e.g. SkShader::asFragmentProcessor() implementations) it is desirable to
* only consider the input color's alpha. However, there is a competing desire to have reusable
@@ -115,9 +114,6 @@
}
}
- int numTextureSamplers() const { return fTextureSamplerCnt; }
- const TextureSampler& textureSampler(int i) const;
-
int numVaryingCoordsUsed() const { return this->usesVaryingCoordsDirectly() ? 1 : 0; }
int numChildProcessors() const { return fChildProcessors.count(); }
@@ -231,7 +227,12 @@
*/
bool isEqual(const GrFragmentProcessor& that) const;
- void visitProxies(const GrOp::VisitProxyFunc& func);
+ void visitProxies(const GrOp::VisitProxyFunc& func) const;
+
+ void visitTextureEffects(const std::function<void(const GrTextureEffect&)>&) const;
+
+ GrTextureEffect* asTextureEffect();
+ const GrTextureEffect* asTextureEffect() const;
// A pre-order traversal iterator over a hierarchy of FPs. It can also iterate over all the FP
// hierarchies rooted in a GrPaint, GrProcessorSet, or GrPipeline. For these collections it
@@ -251,18 +252,13 @@
// Used to implement a range-for loop using CIter. Src is one of GrFragmentProcessor,
// GrPaint, GrProcessorSet, or GrPipeline. Type aliases for these defined below.
// Example usage:
- // for (const auto& fp : GrFragmentProcessor::PaintRange(paint)) {
+ // for (const auto& fp : GrFragmentProcessor::PaintCRange(paint)) {
// if (fp.usesLocalCoords()) {
// ...
// }
// }
template <typename Src> class CIterRange;
- // Like CIterRange but non const and only constructable from GrFragmentProcessor. This could
- // support GrPaint as it owns non-const FPs but no need for it as of now.
- // for (auto& fp0 : GrFragmentProcessor::IterRange(fp)) {
- // ...
- // }
- class IterRange;
+
// We would use template deduction guides for Iter/CIter but for:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79501
@@ -271,56 +267,8 @@
using FPCRange = CIterRange<GrFragmentProcessor>;
using PaintCRange = CIterRange<GrPaint>;
- // Implementation details for iterators that walk an array of Items owned by a set of FPs.
- using CountFn = int (GrFragmentProcessor::*)() const;
- // Defined GetFn to be a member function that returns an Item by index. The function itself is
- // const if Item is a const type and non-const if Item is non-const.
- template <typename Item, bool IsConst = std::is_const<Item>::value> struct GetT;
- template <typename Item> struct GetT<Item, false> {
- using GetFn = Item& (GrFragmentProcessor::*)(int);
- };
- template <typename Item> struct GetT<Item, true> {
- using GetFn = const Item& (GrFragmentProcessor::*)(int) const;
- };
- template <typename Item> using GetFn = typename GetT<Item>::GetFn;
- // This is an iterator over the Items owned by a (collection of) FP. CountFn is a FP member that
- // gets the number of Items owned by each FP and GetFn is a member that gets them by index.
- template <typename Item, CountFn Count, GetFn<Item> Get> class FPItemIter;
-
- // Loops over all the TextureSamplers owned by GrFragmentProcessors. The possible sources for
- // the iteration are the same as those for Iter and the FPs are walked in the same order as
- // Iter. This provides access to the texture sampler and the FP that owns it. Example usage:
- // for (GrFragmentProcessor::TextureSamplerIter iter(pipeline); iter; ++iter) {
- // // TextureSamplerIter is const GrFragmentProcessor::TextureSampler& and
- // // owningFP is const GrFragmentProcessor&.
- // auto [sampler, owningFP] = *iter;
- // ...
- // }
- // See the ranges below to make this simpler a la range-for loops.
- using TextureSamplerIter = FPItemIter<const TextureSampler,
- &GrFragmentProcessor::numTextureSamplers,
- &GrFragmentProcessor::textureSampler>;
-
- // Implementation detail for using TextureSamplerIter in range-for loops.
- template <typename Src, typename ItemIter> class FPItemRange;
-
- // These allow iteration over texture samplers for various FP sources via range-for loops.
- // An example usage for looping over the texture samplers in a pipeline:
- // for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(pipeline)) {
- // ...
- // }
- // Only the combinations of FP sources and iterable things have been defined but it is easy
- // to add more as they become useful. Maybe someday we'll have template argument deduction
- // with guides for type aliases and the sources can be removed from the type aliases:
- // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1021r5.html
- using PipelineTextureSamplerRange = FPItemRange<const GrPipeline, TextureSamplerIter>;
- using FPTextureSamplerRange = FPItemRange<const GrFragmentProcessor, TextureSamplerIter>;
- using ProcessorSetTextureSamplerRange = FPItemRange<const GrProcessorSet, TextureSamplerIter>;
-
// Sentinel type for range-for using Iter.
class EndIter {};
- // Sentinel type for range-for using FPItemIter.
- class FPItemEndIter {};
protected:
enum OptimizationFlags : uint32_t {
@@ -414,28 +362,12 @@
*/
void cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src);
- void setTextureSamplerCnt(int cnt) {
- SkASSERT(cnt >= 0);
- fTextureSamplerCnt = cnt;
- }
-
// FP implementations must call this function if their matching GrGLSLFragmentProcessor's
// emitCode() function uses the EmitArgs::fSampleCoord variable in generated SkSL.
void setUsesSampleCoordsDirectly() {
fFlags |= kUsesSampleCoordsDirectly_Flag;
}
- /**
- * Helper for implementing onTextureSampler(). E.g.:
- * return IthTexureSampler(i, fMyFirstSampler, fMySecondSampler, fMyThirdSampler);
- */
- template <typename... Args>
- static const TextureSampler& IthTextureSampler(int i, const TextureSampler& samp0,
- const Args&... samps) {
- return (0 == i) ? samp0 : IthTextureSampler(i - 1, samps...);
- }
- inline static const TextureSampler& IthTextureSampler(int i);
-
private:
// Implementation details of Iter and CIter.
template <typename> class IterBase;
@@ -459,8 +391,6 @@
*/
virtual bool onIsEqual(const GrFragmentProcessor&) const = 0;
- virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
-
enum PrivateFlags {
kFirstPrivateFlag = kAll_OptimizationFlags + 1,
@@ -476,75 +406,16 @@
};
void addAndPushFlagToChildren(PrivateFlags flag);
- uint32_t fFlags = 0;
-
- int fTextureSamplerCnt = 0;
-
SkSTArray<1, std::unique_ptr<GrFragmentProcessor>, true> fChildProcessors;
const GrFragmentProcessor* fParent = nullptr;
+ uint32_t fFlags = 0;
SkSL::SampleUsage fUsage;
typedef GrProcessor INHERITED;
};
-/**
- * Used to represent a texture that is required by a GrFragmentProcessor. It holds a GrTextureProxy
- * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to
- * account for texture origin.
- */
-class GrFragmentProcessor::TextureSampler {
-public:
- TextureSampler() = default;
-
- /**
- * This copy constructor is used by GrFragmentProcessor::clone() implementations.
- */
- explicit TextureSampler(const TextureSampler&) = default;
-
- TextureSampler(GrSurfaceProxyView, GrSamplerState = {});
-
- TextureSampler(TextureSampler&&) = default;
- TextureSampler& operator=(TextureSampler&&) = default;
- TextureSampler& operator=(const TextureSampler&) = delete;
-
- bool operator==(const TextureSampler& that) const {
- return fView == that.fView && fSamplerState == that.fSamplerState;
- }
-
- bool operator!=(const TextureSampler& other) const { return !(*this == other); }
-
- SkDEBUGCODE(bool isInstantiated() const { return this->proxy()->isInstantiated(); })
-
- // 'peekTexture' should only ever be called after a successful 'instantiate' call
- GrTexture* peekTexture() const {
- SkASSERT(this->proxy()->isInstantiated());
- return this->proxy()->peekTexture();
- }
-
- const GrSurfaceProxyView& view() const { return fView; }
- GrSamplerState samplerState() const { return fSamplerState; }
-
- bool isInitialized() const { return SkToBool(this->proxy()); }
-
- GrSurfaceProxy* proxy() const { return fView.proxy(); }
-
-#if GR_TEST_UTILS
- void set(GrSurfaceProxyView, GrSamplerState);
-#endif
-
-private:
- GrSurfaceProxyView fView;
- GrSamplerState fSamplerState;
-};
-
//////////////////////////////////////////////////////////////////////////////
-const GrFragmentProcessor::TextureSampler& GrFragmentProcessor::IthTextureSampler(int i) {
- SK_ABORT("Illegal texture sampler index");
- static const TextureSampler kBogus;
- return kBogus;
-}
-
GR_MAKE_BITFIELD_OPS(GrFragmentProcessor::OptimizationFlags)
//////////////////////////////////////////////////////////////////////////////
@@ -597,7 +468,6 @@
public:
explicit CIter(const GrFragmentProcessor& fp) : IterBase(fp) {}
explicit CIter(const GrPaint&);
- explicit CIter(const GrProcessorSet&);
explicit CIter(const GrPipeline&);
CIter& operator++() {
this->increment();
@@ -617,60 +487,6 @@
const Src& fT;
};
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
-class GrFragmentProcessor::FPItemIter {
-public:
- template <typename Src> explicit FPItemIter(Src& s);
-
- std::pair<Item&, const GrFragmentProcessor&> operator*() const {
- return {(*fFPIter.*Get)(fIndex), *fFPIter};
- }
- FPItemIter& operator++();
- operator bool() const { return fFPIter; }
- bool operator!=(const FPItemEndIter&) { return (bool)*this; }
-
- FPItemIter(const FPItemIter&) = delete;
- FPItemIter& operator=(const FPItemIter&) = delete;
-
-private:
- typename std::conditional<std::is_const<Item>::value, CIter, Iter>::type fFPIter;
- int fIndex;
-};
-
-template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
-template <typename Src>
-GrFragmentProcessor::FPItemIter<Item, Count, Get>::FPItemIter(Src& s) : fFPIter(s), fIndex(-1) {
- if (fFPIter) {
- ++*this;
- }
-}
-
-template <typename Item, GrFragmentProcessor::CountFn Count, GrFragmentProcessor::GetFn<Item> Get>
-GrFragmentProcessor::FPItemIter<Item, Count, Get>&
-GrFragmentProcessor::FPItemIter<Item, Count, Get>::operator++() {
- ++fIndex;
- if (fIndex < ((*fFPIter).*Count)()) {
- return *this;
- }
- fIndex = 0;
- do {} while (++fFPIter && !((*fFPIter).*Count)());
- return *this;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename Src, typename ItemIter> class GrFragmentProcessor::FPItemRange {
-public:
- FPItemRange(Src& src) : fSrc(src) {}
- ItemIter begin() const { return ItemIter(fSrc); }
- FPItemEndIter end() const { return FPItemEndIter(); }
-
-private:
- Src& fSrc;
-};
-
/**
* Some fragment-processor creation methods have preconditions that might not be satisfied by the
* calling code. Those methods can return a `GrFPResult` from their factory methods. If creation
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 58c8f0c..95cc8a7 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -108,11 +108,17 @@
b->add32(blendKey);
}
+void GrPipeline::visitTextureEffects(
+ const std::function<void(const GrTextureEffect&)>& func) const {
+ for (auto& fp : fFragmentProcessors) {
+ fp->visitTextureEffects(func);
+ }
+}
+
void GrPipeline::visitProxies(const GrOp::VisitProxyFunc& func) const {
// This iteration includes any clip coverage FPs
- for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(*this)) {
- bool mipped = (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter());
- func(sampler.view().proxy(), GrMipMapped(mipped));
+ for (auto& fp : fFragmentProcessors) {
+ fp->visitProxies(func);
}
if (fDstProxyView.asTextureProxy()) {
func(fDstProxyView.asTextureProxy(), GrMipMapped::kNo);
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index a59adde..11eb8b0 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -113,6 +113,8 @@
}
int numFragmentProcessors() const { return fFragmentProcessors.count(); }
+ void visitTextureEffects(const std::function<void(const GrTextureEffect&)>&) const;
+
const GrXferProcessor& getXferProcessor() const {
if (fXferProcessor) {
return *fXferProcessor.get();
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index 48fb9af..b8f077d 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -253,8 +253,7 @@
}
void GrProcessorSet::visitProxies(const GrOp::VisitProxyFunc& func) const {
- for (auto [sampler, fp] : GrFragmentProcessor::ProcessorSetTextureSamplerRange(*this)) {
- bool mipped = (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter());
- func(sampler.view().proxy(), GrMipMapped(mipped));
+ for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) {
+ fFragmentProcessors[i]->visitProxies(func);
}
}
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 2a9f1ae..3383fcf 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -56,24 +56,6 @@
return SkToU32(samplerTypeKey | swizzleKey << kSamplerOrImageTypeKeyBits);
}
-static void add_fp_sampler_keys(GrProcessorKeyBuilder* b, const GrFragmentProcessor& fp,
- const GrCaps& caps) {
- int numTextureSamplers = fp.numTextureSamplers();
- if (!numTextureSamplers) {
- return;
- }
- for (int i = 0; i < numTextureSamplers; ++i) {
- const GrFragmentProcessor::TextureSampler& sampler = fp.textureSampler(i);
- const GrBackendFormat& backendFormat = sampler.view().proxy()->backendFormat();
-
- uint32_t samplerKey = sampler_key(backendFormat.textureType(), sampler.view().swizzle(),
- caps);
- b->add32(samplerKey);
-
- caps.addExtraSamplerKey(b, sampler.samplerState(), backendFormat);
- }
-}
-
static void add_pp_sampler_keys(GrProcessorKeyBuilder* b, const GrPrimitiveProcessor& pp,
const GrCaps& caps) {
int numTextureSamplers = pp.numTextureSamplers();
@@ -113,7 +95,12 @@
return false;
}
- add_fp_sampler_keys(b, fp, caps);
+ fp.visitTextureEffects([&](const GrTextureEffect& te) {
+ const GrBackendFormat& backendFormat = te.view().proxy()->backendFormat();
+ uint32_t samplerKey = sampler_key(backendFormat.textureType(), te.view().swizzle(), caps);
+ b->add32(samplerKey);
+ caps.addExtraSamplerKey(b, te.samplerState(), backendFormat);
+ });
uint32_t* key = b->add32n(2);
key[0] = (classID << 16) | SkToU32(processorKeySize);
diff --git a/src/gpu/GrProgramInfo.cpp b/src/gpu/GrProgramInfo.cpp
index 43b307a..34e6459 100644
--- a/src/gpu/GrProgramInfo.cpp
+++ b/src/gpu/GrProgramInfo.cpp
@@ -31,25 +31,26 @@
}
void GrProgramInfo::checkAllInstantiated() const {
- for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(this->pipeline())) {
- SkASSERT(sampler.proxy()->isInstantiated());
- }
+ this->pipeline().visitProxies([](GrSurfaceProxy* proxy, GrMipMapped) {
+ SkASSERT(proxy->isInstantiated());
+ return true;
+ });
}
void GrProgramInfo::checkMSAAAndMIPSAreResolved() const {
- for (auto [sampler, fp] : GrFragmentProcessor::PipelineTextureSamplerRange(this->pipeline())) {
- GrTexture* tex = sampler.peekTexture();
+ this->pipeline().visitTextureEffects([](const GrTextureEffect& te) {
+ GrTexture* tex = te.texture();
SkASSERT(tex);
// Ensure mipmaps were all resolved ahead of time by the DAG.
- if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter() &&
+ if (GrSamplerState::Filter::kMipMap == te.samplerState().filter() &&
(tex->width() != 1 || tex->height() != 1)) {
- // There are some cases where we might be given a non-mipmapped texture with a mipmap
- // filter. See skbug.com/7094.
+ // There are some cases where we might be given a non-mipmapped texture with a
+ // mipmap filter. See skbug.com/7094.
SkASSERT(tex->texturePriv().mipMapped() != GrMipMapped::kYes ||
!tex->texturePriv().mipMapsAreDirty());
}
- }
+ });
}
#endif
diff --git a/src/gpu/d3d/GrD3DOpsRenderPass.cpp b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
index baac3d2..84ee42a 100644
--- a/src/gpu/d3d/GrD3DOpsRenderPass.cpp
+++ b/src/gpu/d3d/GrD3DOpsRenderPass.cpp
@@ -213,10 +213,11 @@
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
update_resource_state(primProcTextures[i]->peekTexture(), fRenderTarget, fGpu);
}
- GrFragmentProcessor::PipelineTextureSamplerRange textureSamplerRange(pipeline);
- for (auto [sampler, fp] : textureSamplerRange) {
- update_resource_state(sampler.peekTexture(), fRenderTarget, fGpu);
- }
+
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ update_resource_state(te.texture(), fRenderTarget, fGpu);
+ });
+
if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
update_resource_state(dstTexture, fRenderTarget, fGpu);
}
diff --git a/src/gpu/d3d/GrD3DPipelineState.cpp b/src/gpu/d3d/GrD3DPipelineState.cpp
index c91990a..5f8a73a 100644
--- a/src/gpu/d3d/GrD3DPipelineState.cpp
+++ b/src/gpu/d3d/GrD3DPipelineState.cpp
@@ -110,20 +110,15 @@
rangeSizes[currTextureBinding++] = 1;
}
- for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
- for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
- for (int s = 0; s < fp.numTextureSamplers(); ++s) {
- const auto& sampler = fp.textureSampler(s);
- auto texture = static_cast<GrD3DTexture*>(sampler.peekTexture());
- shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
- samplers[currTextureBinding] =
- gpu->resourceProvider().findOrCreateCompatibleSampler(
- sampler.samplerState());
- gpu->currentCommandList()->addSampledTextureRef(texture);
- rangeSizes[currTextureBinding++] = 1;
- }
- }
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ GrSamplerState samplerState = te.samplerState();
+ auto* texture = static_cast<GrD3DTexture*>(te.texture());
+ shaderResourceViews[currTextureBinding] = texture->shaderResourceView();
+ samplers[currTextureBinding] =
+ gpu->resourceProvider().findOrCreateCompatibleSampler(samplerState);
+ gpu->currentCommandList()->addSampledTextureRef(texture);
+ rangeSizes[currTextureBinding++] = 1;
+ });
if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
auto texture = static_cast<GrD3DTexture*>(dstTexture);
diff --git a/src/gpu/dawn/GrDawnProgramBuilder.cpp b/src/gpu/dawn/GrDawnProgramBuilder.cpp
index 7d388ca..9680897 100644
--- a/src/gpu/dawn/GrDawnProgramBuilder.cpp
+++ b/src/gpu/dawn/GrDawnProgramBuilder.cpp
@@ -567,15 +567,9 @@
}
}
- for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
- for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
- for (int s = 0; s < fp.numTextureSamplers(); ++s) {
- const auto& sampler = fp.textureSampler(s);
- set_texture(gpu, sampler.samplerState(), sampler.peekTexture(), &bindings,
- &binding);
- }
- }
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ set_texture(gpu, te.samplerState(), te.texture(), &bindings, &binding);
+ });
SkIPoint offset;
if (GrTexture* dstTexture = pipeline.peekDstTexture(&offset)) {
diff --git a/src/gpu/effects/GrTextureEffect.cpp b/src/gpu/effects/GrTextureEffect.cpp
index fe7792a..07591d5 100644
--- a/src/gpu/effects/GrTextureEffect.cpp
+++ b/src/gpu/effects/GrTextureEffect.cpp
@@ -11,8 +11,6 @@
#include "src/gpu/GrTexture.h"
#include "src/gpu/GrTexturePriv.h"
#include "src/gpu/effects/GrMatrixEffect.h"
-#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
@@ -308,442 +306,427 @@
return m == ShaderMode::kClampToBorderNearest || m == ShaderMode::kClampToBorderFilter;
}
-GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const {
- class Impl : public GrGLSLFragmentProcessor {
- UniformHandle fSubsetUni;
- UniformHandle fClampUni;
- UniformHandle fNormUni;
- UniformHandle fBorderUni;
+void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
+ using ShaderMode = GrTextureEffect::ShaderMode;
- public:
- void emitCode(EmitArgs& args) override {
- auto& te = args.fFp.cast<GrTextureEffect>();
- auto* fb = args.fFragBuilder;
+ auto& te = args.fFp.cast<GrTextureEffect>();
+ auto* fb = args.fFragBuilder;
- if (te.fShaderModes[0] == ShaderMode::kNone &&
- te.fShaderModes[1] == ShaderMode::kNone) {
- fb->codeAppendf("%s = ", args.fOutputColor);
- if (te.fLazyProxyNormalization) {
- const char* norm = nullptr;
- fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag,
- kFloat4_GrSLType, "norm", &norm);
- fb->appendTextureLookupAndBlend(args.fInputColor, SkBlendMode::kModulate,
- args.fTexSamplers[0],
- SkStringPrintf("%s * %s.zw", args.fSampleCoord,
- norm).c_str());
- } else {
- fb->appendTextureLookupAndBlend(args.fInputColor, SkBlendMode::kModulate,
- args.fTexSamplers[0], args.fSampleCoord);
- }
- fb->codeAppendf(";");
+ if (te.fShaderModes[0] == ShaderMode::kNone &&
+ te.fShaderModes[1] == ShaderMode::kNone) {
+ fb->codeAppendf("%s = ", args.fOutputColor);
+ if (te.fLazyProxyNormalization) {
+ const char* norm = nullptr;
+ fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag,
+ kFloat4_GrSLType, "norm", &norm);
+ SkString coordString = SkStringPrintf("%s * %s.zw", args.fSampleCoord, norm);
+ fb->appendTextureLookupAndBlend(args.fInputColor,
+ SkBlendMode::kModulate,
+ fSamplerHandle,
+ coordString.c_str());
+ } else {
+ fb->appendTextureLookupAndBlend(args.fInputColor, SkBlendMode::kModulate,
+ fSamplerHandle, args.fSampleCoord);
+ }
+ fb->codeAppendf(";");
+ } else {
+ // Tripping this assert means we have a normalized fully lazy proxy with a
+ // non-default ShaderMode. There's nothing fundamentally wrong with doing that, but
+ // it hasn't been tested and this code path probably won't handle normalization
+ // properly in that case.
+ SkASSERT(!te.fLazyProxyNormalization);
+ // Here is the basic flow of the various ShaderModes are implemented in a series of
+ // steps. Not all the steps apply to all the modes. We try to emit only the steps
+ // that are necessary for the given x/y shader modes.
+ //
+ // 0) Start with interpolated coordinates (unnormalize if doing anything
+ // complicated).
+ // 1) Map the coordinates into the subset range [Repeat and MirrorRepeat], or pass
+ // through output of 0).
+ // 2) Clamp the coordinates to a 0.5 inset of the subset rect [Clamp, Repeat, and
+ // MirrorRepeat always or ClampToBorder only when filtering] or pass through
+ // output of 1). The clamp rect collapses to a line or point it if the subset
+ // rect is less than one pixel wide/tall.
+ // 3) Look up texture with output of 2) [All]
+ // 3) Use the difference between 1) and 2) to apply filtering at edge [Repeat or
+ // ClampToBorder]. In the Repeat case this requires extra texture lookups on the
+ // other side of the subset (up to 3 more reads). Or if ClampToBorder and not
+ // filtering do a hard less than/greater than test with the subset rect.
+
+ // Convert possible projective texture coordinates into non-homogeneous half2.
+ fb->codeAppendf("float2 inCoord = %s;", args.fSampleCoord);
+
+ const auto& m = te.fShaderModes;
+ GrTextureType textureType = te.view().proxy()->backendFormat().textureType();
+ bool normCoords = textureType != GrTextureType::kRectangle;
+
+ const char* borderName = nullptr;
+ if (te.hasClampToBorderShaderMode()) {
+ fBorderUni = args.fUniformHandler->addUniform(
+ &te, kFragment_GrShaderFlag, kHalf4_GrSLType, "border", &borderName);
+ }
+ auto modeUsesSubset = [](ShaderMode m) {
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return false;
+ case ShaderMode::kRepeatNearest: return true;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return true;
+ case ShaderMode::kClampToBorderNearest: return true;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
+ };
+
+ auto modeUsesClamp = [](ShaderMode m) {
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return true;
+ case ShaderMode::kRepeatNearest: return true;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return true;
+ case ShaderMode::kClampToBorderNearest: return false;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
+ };
+
+ // To keep things a little simpler, when we have filtering logic in the shader we
+ // operate on unnormalized texture coordinates. We will add a uniform that stores
+ // {w, h, 1/w, 1/h} in a float4 below.
+ auto modeRequiresUnormCoords = [](ShaderMode m) {
+ switch (m) {
+ case ShaderMode::kNone: return false;
+ case ShaderMode::kClamp: return false;
+ case ShaderMode::kRepeatNearest: return false;
+ case ShaderMode::kRepeatBilerp: return true;
+ case ShaderMode::kRepeatMipMap: return true;
+ case ShaderMode::kMirrorRepeat: return false;
+ case ShaderMode::kClampToBorderNearest: return true;
+ case ShaderMode::kClampToBorderFilter: return true;
+ }
+ SkUNREACHABLE;
+ };
+
+ bool useSubset[2] = {modeUsesSubset(m[0]), modeUsesSubset(m[1])};
+ bool useClamp [2] = {modeUsesClamp (m[0]), modeUsesClamp (m[1])};
+
+ const char* subsetName = nullptr;
+ if (useSubset[0] || useSubset[1]) {
+ fSubsetUni = args.fUniformHandler->addUniform(
+ &te, kFragment_GrShaderFlag, kFloat4_GrSLType, "subset", &subsetName);
+ }
+
+ const char* clampName = nullptr;
+ if (useClamp[0] || useClamp[1]) {
+ fClampUni = args.fUniformHandler->addUniform(
+ &te, kFragment_GrShaderFlag, kFloat4_GrSLType, "clamp", &clampName);
+ }
+
+ const char* norm = nullptr;
+ if (normCoords && (modeRequiresUnormCoords(m[0]) ||
+ modeRequiresUnormCoords(m[1]))) {
+ // TODO: Detect support for textureSize() or polyfill textureSize() in SkSL and
+ // always use?
+ fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag,
+ kFloat4_GrSLType, "norm", &norm);
+ // TODO: Remove the normalization from the CoordTransform to skip unnormalizing
+ // step here.
+ fb->codeAppendf("inCoord *= %s.xy;", norm);
+ }
+
+ // Generates a string to read at a coordinate, normalizing coords if necessary.
+ auto read = [&](const char* coord) {
+ SkString result;
+ SkString normCoord;
+ if (norm) {
+ normCoord.printf("(%s) * %s.zw", coord, norm);
} else {
- // Tripping this assert means we have a normalized fully lazy proxy with a
- // non-default ShaderMode. There's nothing fundamentally wrong with doing that, but
- // it hasn't been tested and this code path probably won't handle normalization
- // properly in that case.
- SkASSERT(!te.fLazyProxyNormalization);
- // Here is the basic flow of the various ShaderModes are implemented in a series of
- // steps. Not all the steps apply to all the modes. We try to emit only the steps
- // that are necessary for the given x/y shader modes.
- //
- // 0) Start with interpolated coordinates (unnormalize if doing anything
- // complicated).
- // 1) Map the coordinates into the subset range [Repeat and MirrorRepeat], or pass
- // through output of 0).
- // 2) Clamp the coordinates to a 0.5 inset of the subset rect [Clamp, Repeat, and
- // MirrorRepeat always or ClampToBorder only when filtering] or pass through
- // output of 1). The clamp rect collapses to a line or point it if the subset
- // rect is less than one pixel wide/tall.
- // 3) Look up texture with output of 2) [All]
- // 3) Use the difference between 1) and 2) to apply filtering at edge [Repeat or
- // ClampToBorder]. In the Repeat case this requires extra texture lookups on the
- // other side of the subset (up to 3 more reads). Or if ClampToBorder and not
- // filtering do a hard less than/greater than test with the subset rect.
+ normCoord = coord;
+ }
+ fb->appendTextureLookup(&result, fSamplerHandle, normCoord.c_str());
+ return result;
+ };
- // Convert possible projective texture coordinates into non-homogeneous half2.
- fb->codeAppendf("float2 inCoord = %s;", args.fSampleCoord);
-
- const auto& m = te.fShaderModes;
- GrTextureType textureType = te.fSampler.proxy()->backendFormat().textureType();
- bool normCoords = textureType != GrTextureType::kRectangle;
-
- const char* borderName = nullptr;
- if (te.hasClampToBorderShaderMode()) {
- fBorderUni = args.fUniformHandler->addUniform(
- &te, kFragment_GrShaderFlag, kHalf4_GrSLType, "border", &borderName);
- }
- auto modeUsesSubset = [](ShaderMode m) {
- switch (m) {
- case ShaderMode::kNone: return false;
- case ShaderMode::kClamp: return false;
- case ShaderMode::kRepeatNearest: return true;
- case ShaderMode::kRepeatBilerp: return true;
- case ShaderMode::kRepeatMipMap: return true;
- case ShaderMode::kMirrorRepeat: return true;
- case ShaderMode::kClampToBorderNearest: return true;
- case ShaderMode::kClampToBorderFilter: return true;
- }
- SkUNREACHABLE;
- };
-
- auto modeUsesClamp = [](ShaderMode m) {
- switch (m) {
- case ShaderMode::kNone: return false;
- case ShaderMode::kClamp: return true;
- case ShaderMode::kRepeatNearest: return true;
- case ShaderMode::kRepeatBilerp: return true;
- case ShaderMode::kRepeatMipMap: return true;
- case ShaderMode::kMirrorRepeat: return true;
- case ShaderMode::kClampToBorderNearest: return false;
- case ShaderMode::kClampToBorderFilter: return true;
- }
- SkUNREACHABLE;
- };
-
- // To keep things a little simpler, when we have filtering logic in the shader we
- // operate on unnormalized texture coordinates. We will add a uniform that stores
- // {w, h, 1/w, 1/h} in a float4 below.
- auto modeRequiresUnormCoords = [](ShaderMode m) {
- switch (m) {
- case ShaderMode::kNone: return false;
- case ShaderMode::kClamp: return false;
- case ShaderMode::kRepeatNearest: return false;
- case ShaderMode::kRepeatBilerp: return true;
- case ShaderMode::kRepeatMipMap: return true;
- case ShaderMode::kMirrorRepeat: return false;
- case ShaderMode::kClampToBorderNearest: return true;
- case ShaderMode::kClampToBorderFilter: return true;
- }
- SkUNREACHABLE;
- };
-
- bool useSubset[2] = {modeUsesSubset(m[0]), modeUsesSubset(m[1])};
- bool useClamp [2] = {modeUsesClamp (m[0]), modeUsesClamp (m[1])};
-
- const char* subsetName = nullptr;
- if (useSubset[0] || useSubset[1]) {
- fSubsetUni = args.fUniformHandler->addUniform(
- &te, kFragment_GrShaderFlag, kFloat4_GrSLType, "subset", &subsetName);
- }
-
- const char* clampName = nullptr;
- if (useClamp[0] || useClamp[1]) {
- fClampUni = args.fUniformHandler->addUniform(
- &te, kFragment_GrShaderFlag, kFloat4_GrSLType, "clamp", &clampName);
- }
-
- const char* norm = nullptr;
- if (normCoords && (modeRequiresUnormCoords(m[0]) ||
- modeRequiresUnormCoords(m[1]))) {
- // TODO: Detect support for textureSize() or polyfill textureSize() in SkSL and
- // always use?
- fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag,
- kFloat4_GrSLType, "norm", &norm);
- // TODO: Remove the normalization from the CoordTransform to skip unnormalizing
- // step here.
- fb->codeAppendf("inCoord *= %s.xy;", norm);
- }
-
- // Generates a string to read at a coordinate, normalizing coords if necessary.
- auto read = [&](const char* coord) {
- SkString result;
- SkString normCoord;
- if (norm) {
- normCoord.printf("(%s) * %s.zw", coord, norm);
- } else {
- normCoord = coord;
- }
- fb->appendTextureLookup(&result, args.fTexSamplers[0], normCoord.c_str());
- return result;
- };
-
- // Implements coord wrapping for kRepeat and kMirrorRepeat
- auto subsetCoord = [&](ShaderMode mode,
- const char* coordSwizzle,
- const char* subsetStartSwizzle,
- const char* subsetStopSwizzle,
- const char* extraCoord,
- const char* coordWeight) {
- switch (mode) {
- // These modes either don't use the subset rect or don't need to map the
- // coords to be within the subset.
- case ShaderMode::kNone:
- case ShaderMode::kClampToBorderNearest:
- case ShaderMode::kClampToBorderFilter:
- case ShaderMode::kClamp:
- fb->codeAppendf("subsetCoord.%s = inCoord.%s;", coordSwizzle,
- coordSwizzle);
- break;
- case ShaderMode::kRepeatNearest:
- case ShaderMode::kRepeatBilerp:
- fb->codeAppendf(
- "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + "
- "%s.%s;",
- coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle,
- subsetName, subsetStopSwizzle, subsetName, subsetStartSwizzle,
+ // Implements coord wrapping for kRepeat and kMirrorRepeat
+ auto subsetCoord = [&](ShaderMode mode,
+ const char* coordSwizzle,
+ const char* subsetStartSwizzle,
+ const char* subsetStopSwizzle,
+ const char* extraCoord,
+ const char* coordWeight) {
+ switch (mode) {
+ // These modes either don't use the subset rect or don't need to map the
+ // coords to be within the subset.
+ case ShaderMode::kNone:
+ case ShaderMode::kClampToBorderNearest:
+ case ShaderMode::kClampToBorderFilter:
+ case ShaderMode::kClamp:
+ fb->codeAppendf("subsetCoord.%s = inCoord.%s;", coordSwizzle, coordSwizzle);
+ break;
+ case ShaderMode::kRepeatNearest:
+ case ShaderMode::kRepeatBilerp:
+ fb->codeAppendf(
+ "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + "
+ "%s.%s;",
+ coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle, subsetName,
+ subsetStopSwizzle, subsetName, subsetStartSwizzle, subsetName,
+ subsetStartSwizzle);
+ break;
+ case ShaderMode::kRepeatMipMap:
+ // The approach here is to generate two sets of texture coords that
+ // are both "moving" at the same speed (if not direction) as
+ // inCoords. We accomplish that by using two out of phase mirror
+ // repeat coords. We will always sample using both coords but the
+ // read from the upward sloping one is selected using a weight
+ // that transitions from one set to the other near the reflection
+ // point. Like the coords, the weight is a saw-tooth function,
+ // phase-shifted, vertically translated, and then clamped to 0..1.
+ // TODO: Skip this and use textureGrad() when available.
+ SkASSERT(extraCoord);
+ SkASSERT(coordWeight);
+ fb->codeAppend("{");
+ fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
subsetName, subsetStartSwizzle);
- break;
- case ShaderMode::kRepeatMipMap:
- // The approach here is to generate two sets of texture coords that
- // are both "moving" at the same speed (if not direction) as
- // inCoords. We accomplish that by using two out of phase mirror
- // repeat coords. We will always sample using both coords but the
- // read from the upward sloping one is selected using a weight
- // that transitions from one set to the other near the reflection
- // point. Like the coords, the weight is a saw-tooth function,
- // phase-shifted, vertically translated, and then clamped to 0..1.
- // TODO: Skip this and use textureGrad() when available.
- SkASSERT(extraCoord);
- SkASSERT(coordWeight);
- fb->codeAppend("{");
- fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName,
- subsetStopSwizzle, subsetName, subsetStartSwizzle);
- fb->codeAppendf("float w2 = 2 * w;");
- fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle,
- subsetName, subsetStartSwizzle);
- fb->codeAppend("float m = mod(d, w2);");
- fb->codeAppend("float o = mix(m, w2 - m, step(w, m));");
- fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName,
- subsetStartSwizzle);
- fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName,
- subsetStartSwizzle);
- // coordWeight is used as the third param of mix() to blend between a
- // sample taken using subsetCoord and a sample at extraCoord.
- fb->codeAppend("float hw = w/2;");
- fb->codeAppend("float n = mod(d - hw, w2);");
- fb->codeAppendf(
- "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + "
- "0.5));",
- coordWeight);
- fb->codeAppend("}");
- break;
- case ShaderMode::kMirrorRepeat:
- fb->codeAppend("{");
- fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName,
- subsetStopSwizzle, subsetName, subsetStartSwizzle);
- fb->codeAppendf("float w2 = 2 * w;");
- fb->codeAppendf("float m = mod(inCoord.%s - %s.%s, w2);", coordSwizzle,
- subsetName, subsetStartSwizzle);
- fb->codeAppendf("subsetCoord.%s = mix(m, w2 - m, step(w, m)) + %s.%s;",
- coordSwizzle, subsetName, subsetStartSwizzle);
- fb->codeAppend("}");
- break;
- }
- };
-
- auto clampCoord = [&](bool clamp,
- const char* coordSwizzle,
- const char* clampStartSwizzle,
- const char* clampStopSwizzle) {
- if (clamp) {
- fb->codeAppendf("clampedCoord.%s = clamp(subsetCoord.%s, %s.%s, %s.%s);",
- coordSwizzle, coordSwizzle, clampName, clampStartSwizzle,
- clampName, clampStopSwizzle);
- } else {
- fb->codeAppendf("clampedCoord.%s = subsetCoord.%s;", coordSwizzle,
- coordSwizzle);
- }
- };
-
- // Insert vars for extra coords and blending weights for kRepeatMipMap.
- const char* extraRepeatCoordX = nullptr;
- const char* repeatCoordWeightX = nullptr;
- const char* extraRepeatCoordY = nullptr;
- const char* repeatCoordWeightY = nullptr;
- if (m[0] == ShaderMode::kRepeatMipMap) {
- fb->codeAppend("float extraRepeatCoordX; half repeatCoordWeightX;");
- extraRepeatCoordX = "extraRepeatCoordX";
- repeatCoordWeightX = "repeatCoordWeightX";
- }
- if (m[1] == ShaderMode::kRepeatMipMap) {
- fb->codeAppend("float extraRepeatCoordY; half repeatCoordWeightY;");
- extraRepeatCoordY = "extraRepeatCoordY";
- repeatCoordWeightY = "repeatCoordWeightY";
- }
-
- // Apply subset rect and clamp rect to coords.
- fb->codeAppend("float2 subsetCoord;");
- subsetCoord(te.fShaderModes[0], "x", "x", "z", extraRepeatCoordX,
- repeatCoordWeightX);
- subsetCoord(te.fShaderModes[1], "y", "y", "w", extraRepeatCoordY,
- repeatCoordWeightY);
- fb->codeAppend("float2 clampedCoord;");
- clampCoord(useClamp[0], "x", "x", "z");
- clampCoord(useClamp[1], "y", "y", "w");
-
- // Additional clamping for the extra coords for kRepeatMipMap.
- if (m[0] == ShaderMode::kRepeatMipMap) {
- fb->codeAppendf("extraRepeatCoordX = clamp(extraRepeatCoordX, %s.x, %s.z);",
- clampName, clampName);
- }
- if (m[1] == ShaderMode::kRepeatMipMap) {
- fb->codeAppendf("extraRepeatCoordY = clamp(extraRepeatCoordY, %s.y, %s.w);",
- clampName, clampName);
- }
-
- // Do the 2 or 4 texture reads for kRepeatMipMap and then apply the weight(s)
- // to blend between them. If neither direction is kRepeatMipMap do a single
- // read at clampedCoord.
- if (m[0] == ShaderMode::kRepeatMipMap && m[1] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf("float w2 = 2 * w;");
+ fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle, subsetName,
+ subsetStartSwizzle);
+ fb->codeAppend("float m = mod(d, w2);");
+ fb->codeAppend("float o = mix(m, w2 - m, step(w, m));");
+ fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName,
+ subsetStartSwizzle);
+ fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName,
+ subsetStartSwizzle);
+ // coordWeight is used as the third param of mix() to blend between a
+ // sample taken using subsetCoord and a sample at extraCoord.
+ fb->codeAppend("float hw = w/2;");
+ fb->codeAppend("float n = mod(d - hw, w2);");
fb->codeAppendf(
- "half4 textureColor ="
- " mix(mix(%s, %s, repeatCoordWeightX),"
- " mix(%s, %s, repeatCoordWeightX),"
- " repeatCoordWeightY);",
+ "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + "
+ "0.5));",
+ coordWeight);
+ fb->codeAppend("}");
+ break;
+ case ShaderMode::kMirrorRepeat:
+ fb->codeAppend("{");
+ fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle,
+ subsetName, subsetStartSwizzle);
+ fb->codeAppendf("float w2 = 2 * w;");
+ fb->codeAppendf("float m = mod(inCoord.%s - %s.%s, w2);", coordSwizzle,
+ subsetName, subsetStartSwizzle);
+ fb->codeAppendf("subsetCoord.%s = mix(m, w2 - m, step(w, m)) + %s.%s;",
+ coordSwizzle, subsetName, subsetStartSwizzle);
+ fb->codeAppend("}");
+ break;
+ }
+ };
+
+ auto clampCoord = [&](bool clamp,
+ const char* coordSwizzle,
+ const char* clampStartSwizzle,
+ const char* clampStopSwizzle) {
+ if (clamp) {
+ fb->codeAppendf("clampedCoord.%s = clamp(subsetCoord.%s, %s.%s, %s.%s);",
+ coordSwizzle, coordSwizzle, clampName, clampStartSwizzle, clampName,
+ clampStopSwizzle);
+ } else {
+ fb->codeAppendf("clampedCoord.%s = subsetCoord.%s;", coordSwizzle, coordSwizzle);
+ }
+ };
+
+ // Insert vars for extra coords and blending weights for kRepeatMipMap.
+ const char* extraRepeatCoordX = nullptr;
+ const char* repeatCoordWeightX = nullptr;
+ const char* extraRepeatCoordY = nullptr;
+ const char* repeatCoordWeightY = nullptr;
+ if (m[0] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppend("float extraRepeatCoordX; half repeatCoordWeightX;");
+ extraRepeatCoordX = "extraRepeatCoordX";
+ repeatCoordWeightX = "repeatCoordWeightX";
+ }
+ if (m[1] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppend("float extraRepeatCoordY; half repeatCoordWeightY;");
+ extraRepeatCoordY = "extraRepeatCoordY";
+ repeatCoordWeightY = "repeatCoordWeightY";
+ }
+
+ // Apply subset rect and clamp rect to coords.
+ fb->codeAppend("float2 subsetCoord;");
+ subsetCoord(te.fShaderModes[0], "x", "x", "z", extraRepeatCoordX, repeatCoordWeightX);
+ subsetCoord(te.fShaderModes[1], "y", "y", "w", extraRepeatCoordY, repeatCoordWeightY);
+ fb->codeAppend("float2 clampedCoord;");
+ clampCoord(useClamp[0], "x", "x", "z");
+ clampCoord(useClamp[1], "y", "y", "w");
+
+ // Additional clamping for the extra coords for kRepeatMipMap.
+ if (m[0] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf("extraRepeatCoordX = clamp(extraRepeatCoordX, %s.x, %s.z);", clampName,
+ clampName);
+ }
+ if (m[1] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf("extraRepeatCoordY = clamp(extraRepeatCoordY, %s.y, %s.w);", clampName,
+ clampName);
+ }
+
+ // Do the 2 or 4 texture reads for kRepeatMipMap and then apply the weight(s)
+ // to blend between them. If neither direction is kRepeatMipMap do a single
+ // read at clampedCoord.
+ if (m[0] == ShaderMode::kRepeatMipMap && m[1] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf(
+ "half4 textureColor ="
+ " mix(mix(%s, %s, repeatCoordWeightX),"
+ " mix(%s, %s, repeatCoordWeightX),"
+ " repeatCoordWeightY);",
+ read("clampedCoord").c_str(),
+ read("float2(extraRepeatCoordX, clampedCoord.y)").c_str(),
+ read("float2(clampedCoord.x, extraRepeatCoordY)").c_str(),
+ read("float2(extraRepeatCoordX, extraRepeatCoordY)").c_str());
+
+ } else if (m[0] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
read("clampedCoord").c_str(),
- read("float2(extraRepeatCoordX, clampedCoord.y)").c_str(),
- read("float2(clampedCoord.x, extraRepeatCoordY)").c_str(),
- read("float2(extraRepeatCoordX, extraRepeatCoordY)").c_str());
-
- } else if (m[0] == ShaderMode::kRepeatMipMap) {
- fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
- read("clampedCoord").c_str(),
- read("float2(extraRepeatCoordX, clampedCoord.y)").c_str());
- } else if (m[1] == ShaderMode::kRepeatMipMap) {
- fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
- read("clampedCoord").c_str(),
- read("float2(clampedCoord.x, extraRepeatCoordY)").c_str());
- } else {
- fb->codeAppendf("half4 textureColor = %s;", read("clampedCoord").c_str());
- }
-
- // Strings for extra texture reads used only in kRepeatBilerp
- SkString repeatBilerpReadX;
- SkString repeatBilerpReadY;
-
- // Calculate the amount the coord moved for clamping. This will be used
- // to implement shader-based filtering for kClampToBorder and kRepeat.
-
- if (m[0] == ShaderMode::kRepeatBilerp || m[0] == ShaderMode::kClampToBorderFilter) {
- fb->codeAppend("half errX = half(subsetCoord.x - clampedCoord.x);");
- fb->codeAppendf("float repeatCoordX = errX > 0 ? %s.x : %s.z;", clampName,
- clampName);
- repeatBilerpReadX = read("float2(repeatCoordX, clampedCoord.y)");
- }
- if (m[1] == ShaderMode::kRepeatBilerp || m[1] == ShaderMode::kClampToBorderFilter) {
- fb->codeAppend("half errY = half(subsetCoord.y - clampedCoord.y);");
- fb->codeAppendf("float repeatCoordY = errY > 0 ? %s.y : %s.w;", clampName,
- clampName);
- repeatBilerpReadY = read("float2(clampedCoord.x, repeatCoordY)");
- }
-
- // Add logic for kRepeatBilerp. Do 1 or 3 more texture reads depending
- // on whether both modes are kRepeat and whether we're near a single subset edge
- // or a corner. Then blend the multiple reads using the err values calculated
- // above.
- const char* ifStr = "if";
- if (m[0] == ShaderMode::kRepeatBilerp && m[1] == ShaderMode::kRepeatBilerp) {
- auto repeatBilerpReadXY = read("float2(repeatCoordX, repeatCoordY)");
- fb->codeAppendf(
- "if (errX != 0 && errY != 0) {"
- " errX = abs(errX);"
- " textureColor = mix(mix(textureColor, %s, errX),"
- " mix(%s, %s, errX),"
- " abs(errY));"
- "}",
- repeatBilerpReadX.c_str(), repeatBilerpReadY.c_str(),
- repeatBilerpReadXY.c_str());
- ifStr = "else if";
- }
- if (m[0] == ShaderMode::kRepeatBilerp) {
- fb->codeAppendf(
- "%s (errX != 0) {"
- " textureColor = mix(textureColor, %s, abs(errX));"
- "}",
- ifStr, repeatBilerpReadX.c_str());
- }
- if (m[1] == ShaderMode::kRepeatBilerp) {
- fb->codeAppendf(
- "%s (errY != 0) {"
- " textureColor = mix(textureColor, %s, abs(errY));"
- "}",
- ifStr, repeatBilerpReadY.c_str());
- }
-
- // Do soft edge shader filtering against border color for kClampToBorderFilter using
- // the err values calculated above.
- if (m[0] == ShaderMode::kClampToBorderFilter) {
- fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errX), 1));",
- borderName);
- }
- if (m[1] == ShaderMode::kClampToBorderFilter) {
- fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errY), 1));",
- borderName);
- }
-
- // Do hard-edge shader transition to border color for kClampToBorderNearest at the
- // subset boundaries. Snap the input coordinates to nearest neighbor (with an
- // epsilon) before comparing to the subset rect to avoid GPU interpolation errors
- if (m[0] == ShaderMode::kClampToBorderNearest) {
- fb->codeAppendf(
- "float snappedX = floor(inCoord.x + 0.001) + 0.5;"
- "if (snappedX < %s.x || snappedX > %s.z) {"
- " textureColor = %s;"
- "}",
- subsetName, subsetName, borderName);
- }
- if (m[1] == ShaderMode::kClampToBorderNearest) {
- fb->codeAppendf(
- "float snappedY = floor(inCoord.y + 0.001) + 0.5;"
- "if (snappedY < %s.y || snappedY > %s.w) {"
- " textureColor = %s;"
- "}",
- subsetName, subsetName, borderName);
- }
- fb->codeAppendf("%s = %s * textureColor;", args.fOutputColor, args.fInputColor);
- }
+ read("float2(extraRepeatCoordX, clampedCoord.y)").c_str());
+ } else if (m[1] == ShaderMode::kRepeatMipMap) {
+ fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
+ read("clampedCoord").c_str(),
+ read("float2(clampedCoord.x, extraRepeatCoordY)").c_str());
+ } else {
+ fb->codeAppendf("half4 textureColor = %s;", read("clampedCoord").c_str());
}
- protected:
- void onSetData(const GrGLSLProgramDataManager& pdm,
- const GrFragmentProcessor& fp) override {
- const auto& te = fp.cast<GrTextureEffect>();
+ // Strings for extra texture reads used only in kRepeatBilerp
+ SkString repeatBilerpReadX;
+ SkString repeatBilerpReadY;
- const float w = te.fSampler.peekTexture()->width();
- const float h = te.fSampler.peekTexture()->height();
- const auto& s = te.fSubset;
- const auto& c = te.fClamp;
+ // Calculate the amount the coord moved for clamping. This will be used
+ // to implement shader-based filtering for kClampToBorder and kRepeat.
- auto type = te.fSampler.peekTexture()->texturePriv().textureType();
-
- float norm[4] = {w, h, 1.f/w, 1.f/h};
-
- if (fNormUni.isValid()) {
- pdm.set4fv(fNormUni, 1, norm);
- SkASSERT(type != GrTextureType::kRectangle);
- }
-
- auto pushRect = [&](float rect[4], UniformHandle uni) {
- if (te.fSampler.view().origin() == kBottomLeft_GrSurfaceOrigin) {
- rect[1] = h - rect[1];
- rect[3] = h - rect[3];
- std::swap(rect[1], rect[3]);
- }
- if (!fNormUni.isValid() && type != GrTextureType::kRectangle) {
- rect[0] *= norm[2];
- rect[2] *= norm[2];
- rect[1] *= norm[3];
- rect[3] *= norm[3];
- }
- pdm.set4fv(uni, 1, rect);
- };
-
- if (fSubsetUni.isValid()) {
- float subset[] = {s.fLeft, s.fTop, s.fRight, s.fBottom};
- pushRect(subset, fSubsetUni);
- }
- if (fClampUni.isValid()) {
- float subset[] = {c.fLeft, c.fTop, c.fRight, c.fBottom};
- pushRect(subset, fClampUni);
- }
- if (fBorderUni.isValid()) {
- pdm.set4fv(fBorderUni, 1, te.fBorder);
- }
+ if (m[0] == ShaderMode::kRepeatBilerp || m[0] == ShaderMode::kClampToBorderFilter) {
+ fb->codeAppend("half errX = half(subsetCoord.x - clampedCoord.x);");
+ fb->codeAppendf("float repeatCoordX = errX > 0 ? %s.x : %s.z;", clampName, clampName);
+ repeatBilerpReadX = read("float2(repeatCoordX, clampedCoord.y)");
}
- };
- return new Impl;
+ if (m[1] == ShaderMode::kRepeatBilerp || m[1] == ShaderMode::kClampToBorderFilter) {
+ fb->codeAppend("half errY = half(subsetCoord.y - clampedCoord.y);");
+ fb->codeAppendf("float repeatCoordY = errY > 0 ? %s.y : %s.w;", clampName, clampName);
+ repeatBilerpReadY = read("float2(clampedCoord.x, repeatCoordY)");
+ }
+
+ // Add logic for kRepeatBilerp. Do 1 or 3 more texture reads depending
+ // on whether both modes are kRepeat and whether we're near a single subset edge
+ // or a corner. Then blend the multiple reads using the err values calculated
+ // above.
+ const char* ifStr = "if";
+ if (m[0] == ShaderMode::kRepeatBilerp && m[1] == ShaderMode::kRepeatBilerp) {
+ auto repeatBilerpReadXY = read("float2(repeatCoordX, repeatCoordY)");
+ fb->codeAppendf(
+ "if (errX != 0 && errY != 0) {"
+ " errX = abs(errX);"
+ " textureColor = mix(mix(textureColor, %s, errX),"
+ " mix(%s, %s, errX),"
+ " abs(errY));"
+ "}",
+ repeatBilerpReadX.c_str(), repeatBilerpReadY.c_str(),
+ repeatBilerpReadXY.c_str());
+ ifStr = "else if";
+ }
+ if (m[0] == ShaderMode::kRepeatBilerp) {
+ fb->codeAppendf(
+ "%s (errX != 0) {"
+ " textureColor = mix(textureColor, %s, abs(errX));"
+ "}",
+ ifStr, repeatBilerpReadX.c_str());
+ }
+ if (m[1] == ShaderMode::kRepeatBilerp) {
+ fb->codeAppendf(
+ "%s (errY != 0) {"
+ " textureColor = mix(textureColor, %s, abs(errY));"
+ "}",
+ ifStr, repeatBilerpReadY.c_str());
+ }
+
+ // Do soft edge shader filtering against border color for kClampToBorderFilter using
+ // the err values calculated above.
+ if (m[0] == ShaderMode::kClampToBorderFilter) {
+ fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errX), 1));", borderName);
+ }
+ if (m[1] == ShaderMode::kClampToBorderFilter) {
+ fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errY), 1));", borderName);
+ }
+
+ // Do hard-edge shader transition to border color for kClampToBorderNearest at the
+ // subset boundaries. Snap the input coordinates to nearest neighbor (with an
+ // epsilon) before comparing to the subset rect to avoid GPU interpolation errors
+ if (m[0] == ShaderMode::kClampToBorderNearest) {
+ fb->codeAppendf(
+ "float snappedX = floor(inCoord.x + 0.001) + 0.5;"
+ "if (snappedX < %s.x || snappedX > %s.z) {"
+ " textureColor = %s;"
+ "}",
+ subsetName, subsetName, borderName);
+ }
+ if (m[1] == ShaderMode::kClampToBorderNearest) {
+ fb->codeAppendf(
+ "float snappedY = floor(inCoord.y + 0.001) + 0.5;"
+ "if (snappedY < %s.y || snappedY > %s.w) {"
+ " textureColor = %s;"
+ "}",
+ subsetName, subsetName, borderName);
+ }
+ fb->codeAppendf("%s = %s * textureColor;", args.fOutputColor, args.fInputColor);
+ }
}
+void GrTextureEffect::Impl::onSetData(const GrGLSLProgramDataManager& pdm,
+ const GrFragmentProcessor& fp) {
+ const auto& te = fp.cast<GrTextureEffect>();
+
+ const float w = te.texture()->width();
+ const float h = te.texture()->height();
+ const auto& s = te.fSubset;
+ const auto& c = te.fClamp;
+
+ auto type = te.texture()->texturePriv().textureType();
+
+ float norm[4] = {w, h, 1.f/w, 1.f/h};
+
+ if (fNormUni.isValid()) {
+ pdm.set4fv(fNormUni, 1, norm);
+ SkASSERT(type != GrTextureType::kRectangle);
+ }
+
+ auto pushRect = [&](float rect[4], UniformHandle uni) {
+ if (te.view().origin() == kBottomLeft_GrSurfaceOrigin) {
+ rect[1] = h - rect[1];
+ rect[3] = h - rect[3];
+ std::swap(rect[1], rect[3]);
+ }
+ if (!fNormUni.isValid() && type != GrTextureType::kRectangle) {
+ rect[0] *= norm[2];
+ rect[2] *= norm[2];
+ rect[1] *= norm[3];
+ rect[3] *= norm[3];
+ }
+ pdm.set4fv(uni, 1, rect);
+ };
+
+ if (fSubsetUni.isValid()) {
+ float subset[] = {s.fLeft, s.fTop, s.fRight, s.fBottom};
+ pushRect(subset, fSubsetUni);
+ }
+ if (fClampUni.isValid()) {
+ float subset[] = {c.fLeft, c.fTop, c.fRight, c.fBottom};
+ pushRect(subset, fClampUni);
+ }
+ if (fBorderUni.isValid()) {
+ pdm.set4fv(fBorderUni, 1, te.fBorder);
+ }
+}
+
+GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { return new Impl; }
+
void GrTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
auto m0 = static_cast<uint32_t>(fShaderModes[0]);
auto m1 = static_cast<uint32_t>(fShaderModes[1]);
@@ -752,6 +735,12 @@
bool GrTextureEffect::onIsEqual(const GrFragmentProcessor& other) const {
auto& that = other.cast<GrTextureEffect>();
+ if (fView != that.fView) {
+ return false;
+ }
+ if (fSamplerState != that.fSamplerState) {
+ return false;
+ }
if (fShaderModes[0] != that.fShaderModes[0] || fShaderModes[1] != that.fShaderModes[1]) {
return false;
}
@@ -764,11 +753,14 @@
return true;
}
-GrTextureEffect::GrTextureEffect(GrSurfaceProxyView view, SkAlphaType alphaType,
- const Sampling& sampling, bool lazyProxyNormalization)
+GrTextureEffect::GrTextureEffect(GrSurfaceProxyView view,
+ SkAlphaType alphaType,
+ const Sampling& sampling,
+ bool lazyProxyNormalization)
: GrFragmentProcessor(kGrTextureEffect_ClassID,
ModulateForSamplerOptFlags(alphaType, sampling.hasBorderAlpha()))
- , fSampler(std::move(view), sampling.fHWSampler)
+ , fView(std::move(view))
+ , fSamplerState(sampling.fHWSampler)
, fSubset(sampling.fShaderSubset)
, fClamp(sampling.fShaderClamp)
, fShaderModes{sampling.fShaderModes[0], sampling.fShaderModes[1]}
@@ -777,20 +769,19 @@
// values.
SkASSERT(fShaderModes[0] != ShaderMode::kNone || (fSubset.fLeft == 0 && fSubset.fRight == 0));
SkASSERT(fShaderModes[1] != ShaderMode::kNone || (fSubset.fTop == 0 && fSubset.fBottom == 0));
- this->setTextureSamplerCnt(1);
this->setUsesSampleCoordsDirectly();
std::copy_n(sampling.fBorder, 4, fBorder);
}
GrTextureEffect::GrTextureEffect(const GrTextureEffect& src)
: INHERITED(kGrTextureEffect_ClassID, src.optimizationFlags())
- , fSampler(src.fSampler)
+ , fView(src.fView)
+ , fSamplerState(src.fSamplerState)
, fSubset(src.fSubset)
, fClamp(src.fClamp)
, fShaderModes{src.fShaderModes[0], src.fShaderModes[1]}
, fLazyProxyNormalization(src.fLazyProxyNormalization) {
std::copy_n(src.fBorder, 4, fBorder);
- this->setTextureSamplerCnt(1);
this->setUsesSampleCoordsDirectly();
}
@@ -798,10 +789,6 @@
return std::unique_ptr<GrFragmentProcessor>(new GrTextureEffect(*this));
}
-const GrFragmentProcessor::TextureSampler& GrTextureEffect::onTextureSampler(int) const {
- return fSampler;
-}
-
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTextureEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrTextureEffect::TestCreate(GrProcessorTestData* testData) {
diff --git a/src/gpu/effects/GrTextureEffect.h b/src/gpu/effects/GrTextureEffect.h
index 511cdb6..4692063 100644
--- a/src/gpu/effects/GrTextureEffect.h
+++ b/src/gpu/effects/GrTextureEffect.h
@@ -11,6 +11,8 @@
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "src/gpu/GrFragmentProcessor.h"
+#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
class GrTextureEffect : public GrFragmentProcessor {
public:
@@ -89,6 +91,29 @@
const char* name() const override { return "TextureEffect"; }
+ GrSamplerState samplerState() const { return fSamplerState; }
+
+ GrTexture* texture() const { return fView.asTextureProxy()->peekTexture(); }
+
+ const GrSurfaceProxyView& view() const { return fView; }
+
+ class Impl : public GrGLSLFragmentProcessor {
+ public:
+ void emitCode(EmitArgs&) override;
+ void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
+
+ void setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle) {
+ fSamplerHandle = handle;
+ }
+
+ private:
+ UniformHandle fSubsetUni;
+ UniformHandle fClampUni;
+ UniformHandle fNormUni;
+ UniformHandle fBorderUni;
+ GrGLSLShaderBuilder::SamplerHandle fSamplerHandle;
+ };
+
private:
struct Sampling;
@@ -109,7 +134,8 @@
static ShaderMode GetShaderMode(GrSamplerState::WrapMode, GrSamplerState::Filter);
static bool ShaderModeIsClampToBorder(ShaderMode);
- TextureSampler fSampler;
+ GrSurfaceProxyView fView;
+ GrSamplerState fSamplerState;
float fBorder[4];
SkRect fSubset;
SkRect fClamp;
@@ -127,8 +153,6 @@
bool onIsEqual(const GrFragmentProcessor&) const override;
- const TextureSampler& onTextureSampler(int) const override;
-
bool hasClampToBorderShaderMode() const {
return ShaderModeIsClampToBorder(fShaderModes[0]) ||
ShaderModeIsClampToBorder(fShaderModes[1]);
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index c453a3d..242deb5 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -159,13 +159,12 @@
#ifdef SK_DEBUG
SkString GrYUVtoRGBEffect::dumpInfo() const {
SkString str;
- for (int i = 0; i < this->numTextureSamplers(); ++i) {
- str.appendf("%d: %d %d ", i,
- this->textureSampler(i).view().proxy()->uniqueID().asUInt(),
- this->textureSampler(i).view().proxy()->underlyingUniqueID().asUInt());
+ for (int i = 0; i < 4; ++i) {
+ str.appendf("yuvindex_%d: %d %d\n", i, fYUVAIndices->fIndex,
+ static_cast<int>(fYUVAIndices->fChannel));
}
- str.appendf("\n");
-
+ str.appendf("cs: %d\n", static_cast<int>(fYUVColorSpace));
+ str.appendf("snap x: %d snap y: %d\n", fSnap[0], fSnap[1]);
return str;
}
#endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index ee19309..d97173d 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -140,14 +140,12 @@
}
int nextTexSamplerIdx = primProc.numTextureSamplers();
- GrFragmentProcessor::CIter fpIter(pipeline);
- for (; fpIter; ++fpIter) {
- for (int i = 0; i < fpIter->numTextureSamplers(); ++i) {
- const GrFragmentProcessor::TextureSampler& sampler = fpIter->textureSampler(i);
- fGpu->bindTexture(nextTexSamplerIdx++, sampler.samplerState(), sampler.view().swizzle(),
- static_cast<GrGLTexture*>(sampler.peekTexture()));
- }
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ GrSamplerState samplerState = te.samplerState();
+ GrSwizzle swizzle = te.view().swizzle();
+ auto* texture = static_cast<GrGLTexture*>(te.texture());
+ fGpu->bindTexture(nextTexSamplerIdx++, samplerState, swizzle, texture);
+ });
SkIPoint offset;
GrTexture* dstTexture = pipeline.peekDstTexture(&offset);
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
index 6d1ac02..eb84ee8 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.cpp
@@ -26,8 +26,6 @@
// Emit the child's helper function if this is the first time we've seen a call
if (fFunctionNames[childIndex].size() == 0) {
TransformedCoordVars coordVars = args.fTransformedCoords.childInputs(childIndex);
- TextureSamplers textureSamplers = args.fTexSamplers.childInputs(childIndex);
-
EmitArgs childArgs(fragBuilder,
args.fUniformHandler,
args.fShaderCaps,
@@ -35,8 +33,7 @@
"_output",
"_input",
"_coords",
- coordVars,
- textureSamplers);
+ coordVars);
fFunctionNames[childIndex] =
fragBuilder->writeProcessorFunction(this->childProcessor(childIndex), childArgs);
}
diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h
index f04e0c0..8f5fdb5 100644
--- a/src/gpu/glsl/GrGLSLFragmentProcessor.h
+++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h
@@ -73,8 +73,6 @@
public:
using TransformedCoordVars =
BuilderInputProvider<GrShaderVar, &GrFragmentProcessor::numVaryingCoordsUsed>;
- using TextureSamplers =
- BuilderInputProvider<SamplerHandle, &GrFragmentProcessor::numTextureSamplers>;
/** Called when the program stage should insert its code into the shaders. The code in each
shader will be in its own block ({}) and so locally scoped names will not collide across
@@ -96,9 +94,6 @@
@param localCoord The name of a local coord reference to a float2 variable.
@param transformedCoords Fragment shader variables containing the coords computed using
each of the GrFragmentProcessor's GrCoordTransforms.
- @param texSamplers Contains one entry for each TextureSampler of the GrProcessor.
- These can be passed to the builder to emit texture reads in the
- generated code.
*/
struct EmitArgs {
EmitArgs(GrGLSLFPFragmentBuilder* fragBuilder,
@@ -108,8 +103,7 @@
const char* outputColor,
const char* inputColor,
const char* sampleCoord,
- const TransformedCoordVars& transformedCoordVars,
- const TextureSamplers& textureSamplers)
+ const TransformedCoordVars& transformedCoordVars)
: fFragBuilder(fragBuilder)
, fUniformHandler(uniformHandler)
, fShaderCaps(caps)
@@ -117,8 +111,7 @@
, fOutputColor(outputColor)
, fInputColor(inputColor ? inputColor : "half4(1.0)")
, fSampleCoord(sampleCoord)
- , fTransformedCoords(transformedCoordVars)
- , fTexSamplers(textureSamplers) {}
+ , fTransformedCoords(transformedCoordVars) {}
GrGLSLFPFragmentBuilder* fFragBuilder;
GrGLSLUniformHandler* fUniformHandler;
const GrShaderCaps* fShaderCaps;
@@ -127,7 +120,6 @@
const char* fInputColor;
const char* fSampleCoord;
const TransformedCoordVars& fTransformedCoords;
- const TextureSamplers& fTexSamplers;
};
virtual void emitCode(EmitArgs&) = 0;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 1ec0e62..22be124 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -130,36 +130,31 @@
void GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
int transformedCoordVarsIdx = 0;
SkString** inOut = &color;
- SkSTArray<8, std::unique_ptr<GrGLSLFragmentProcessor>> glslFragmentProcessors;
- for (int i = 0; i < this->pipeline().numFragmentProcessors(); ++i) {
+ int fpCount = this->pipeline().numFragmentProcessors();
+ fFragmentProcessors.reset(new std::unique_ptr<GrGLSLFragmentProcessor>[fpCount]);
+ for (int i = 0; i < fpCount; ++i) {
if (i == this->pipeline().numColorFragmentProcessors()) {
inOut = &coverage;
}
SkString output;
const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
- output = this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, output,
- &glslFragmentProcessors);
+ fFragmentProcessors[i] = std::unique_ptr<GrGLSLFragmentProcessor>(fp.createGLSLInstance());
+ output = this->emitFragProc(fp, *fFragmentProcessors[i], transformedCoordVarsIdx, **inOut,
+ output);
for (const auto& subFP : GrFragmentProcessor::FPCRange(fp)) {
transformedCoordVarsIdx += subFP.numVaryingCoordsUsed();
}
**inOut = output;
}
- int fpCount = glslFragmentProcessors.count();
- fFragmentProcessors.reset(new std::unique_ptr<GrGLSLFragmentProcessor>[fpCount]);
- for (int i = 0; i < fpCount; ++i) {
- fFragmentProcessors[i] = std::move(glslFragmentProcessors[i]);
- }
}
// TODO Processors cannot output zeros because an empty string is all 1s
// the fix is to allow effects to take the SkString directly
-SkString GrGLSLProgramBuilder::emitAndInstallFragProc(
- const GrFragmentProcessor& fp,
- int index,
- int transformedCoordVarsIdx,
- const SkString& input,
- SkString output,
- SkTArray<std::unique_ptr<GrGLSLFragmentProcessor>>* glslFragmentProcessors) {
+SkString GrGLSLProgramBuilder::emitFragProc(const GrFragmentProcessor& fp,
+ GrGLSLFragmentProcessor& glslFP,
+ int transformedCoordVarsIdx,
+ const SkString& input,
+ SkString output) {
SkASSERT(input.size());
// Program builders have a bit of state we need to clear with each effect
AutoStageAdvance adv(this);
@@ -170,24 +165,21 @@
openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
fFS.codeAppend(openBrace.c_str());
- GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
-
- SkSTArray<4, SamplerHandle> texSamplers;
int samplerIdx = 0;
- for (const auto& subFP : GrFragmentProcessor::FPCRange(fp)) {
- for (int i = 0; i < subFP.numTextureSamplers(); ++i) {
+ for (auto [subFP, subGLSLFP] : GrGLSLFragmentProcessor::ParallelRange(fp, glslFP)) {
+ if (auto* te = subFP.asTextureEffect()) {
SkString name;
name.printf("TextureSampler_%d", samplerIdx++);
- const auto& sampler = subFP.textureSampler(i);
- texSamplers.emplace_back(this->emitSampler(sampler.view().proxy()->backendFormat(),
- sampler.samplerState(),
- sampler.view().swizzle(),
- name.c_str()));
+
+ GrSamplerState samplerState = te->samplerState();
+ const GrBackendFormat& format = te->view().proxy()->backendFormat();
+ GrSwizzle swizzle = te->view().swizzle();
+ SamplerHandle handle = this->emitSampler(format, samplerState, swizzle, name.c_str());
+ static_cast<GrTextureEffect::Impl&>(subGLSLFP).setSamplerHandle(handle);
}
}
const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
- GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, texSamplers.begin());
GrGLSLFragmentProcessor::EmitArgs args(&fFS,
this->uniformHandler(),
this->shaderCaps(),
@@ -195,8 +187,7 @@
output.c_str(),
input.c_str(),
"_coords",
- coords,
- textureSamplers);
+ coords);
if (fp.referencesSampleCoords()) {
// The fp's generated code expects a _coords variable, but we're at the root so _coords
@@ -222,12 +213,11 @@
}
}
- fragProc->emitCode(args);
+ glslFP.emitCode(args);
// We have to check that effects and the code they emit are consistent, ie if an effect
// asks for dst color, then the emit code needs to follow suit
SkDEBUGCODE(verify(fp);)
- glslFragmentProcessors->emplace_back(fragProc);
fFS.codeAppend("}");
return output;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index fcda22d..17fb4b1 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -153,12 +153,11 @@
void emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage);
void emitAndInstallFragProcs(SkString* colorInOut, SkString* coverageInOut);
- SkString emitAndInstallFragProc(const GrFragmentProcessor&,
- int index,
- int transformedCoordVarsIdx,
- const SkString& input,
- SkString output,
- SkTArray<std::unique_ptr<GrGLSLFragmentProcessor>>*);
+ SkString emitFragProc(const GrFragmentProcessor&,
+ GrGLSLFragmentProcessor&,
+ int transformedCoordVarsIdx,
+ const SkString& input,
+ SkString output);
void emitAndInstallXferProc(const SkString& colorIn, const SkString& coverageIn);
SamplerHandle emitSampler(const GrBackendFormat&, GrSamplerState, const GrSwizzle&,
const char* name);
diff --git a/src/gpu/mtl/GrMtlPipelineState.mm b/src/gpu/mtl/GrMtlPipelineState.mm
index e4a1e2d..0a15db2 100644
--- a/src/gpu/mtl/GrMtlPipelineState.mm
+++ b/src/gpu/mtl/GrMtlPipelineState.mm
@@ -97,14 +97,9 @@
fSamplerBindings.emplace_back(sampler.samplerState(), texture, fGpu);
}
- for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
- for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
- for (int s = 0; s < fp.numTextureSamplers(); ++s) {
- const auto& sampler = fp.textureSampler(s);
- fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(), fGpu);
- }
- }
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ fSamplerBindings.emplace_back(te.samplerState(), te.texture(), fGpu);
+ });
if (GrTextureProxy* dstTextureProxy = pipeline.dstProxyView().asTextureProxy()) {
fSamplerBindings.emplace_back(
diff --git a/src/gpu/vk/GrVkOpsRenderPass.cpp b/src/gpu/vk/GrVkOpsRenderPass.cpp
index 00f54b9..b26012d 100644
--- a/src/gpu/vk/GrVkOpsRenderPass.cpp
+++ b/src/gpu/vk/GrVkOpsRenderPass.cpp
@@ -529,10 +529,9 @@
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
check_sampled_texture(primProcTextures[i]->peekTexture(), fRenderTarget, fGpu);
}
- GrFragmentProcessor::PipelineTextureSamplerRange textureSamplerRange(pipeline);
- for (auto [sampler, fp] : textureSamplerRange) {
- check_sampled_texture(sampler.peekTexture(), fRenderTarget, fGpu);
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ check_sampled_texture(te.texture(), fRenderTarget, fGpu);
+ });
if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
check_sampled_texture(dstTexture, fRenderTarget, fGpu);
}
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 7ebed80..eaea83f 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -126,15 +126,11 @@
samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
}
- for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
- for (auto& fp : GrFragmentProcessor::FPCRange(pipeline.getFragmentProcessor(i))) {
- for (int s = 0; s < fp.numTextureSamplers(); ++s) {
- const auto& sampler = fp.textureSampler(s);
- samplerBindings[currTextureBinding++] = {
- sampler.samplerState(), static_cast<GrVkTexture*>(sampler.peekTexture())};
- }
- }
- }
+ pipeline.visitTextureEffects([&](const GrTextureEffect& te) {
+ GrSamplerState samplerState = te.samplerState();
+ auto* texture = static_cast<GrVkTexture*>(te.texture());
+ samplerBindings[currTextureBinding++] = {samplerState, texture};
+ });
if (GrTexture* dstTexture = pipeline.peekDstTexture()) {
samplerBindings[currTextureBinding++] = {
@@ -222,29 +218,6 @@
return true;
}
-void set_uniform_descriptor_writes(VkWriteDescriptorSet* descriptorWrite,
- VkDescriptorBufferInfo* bufferInfo,
- const GrVkUniformBuffer* buffer,
- VkDescriptorSet descriptorSet) {
-
- memset(bufferInfo, 0, sizeof(VkDescriptorBufferInfo));
- bufferInfo->buffer = buffer->buffer();
- bufferInfo->offset = buffer->offset();
- bufferInfo->range = buffer->size();
-
- memset(descriptorWrite, 0, sizeof(VkWriteDescriptorSet));
- descriptorWrite->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrite->pNext = nullptr;
- descriptorWrite->dstSet = descriptorSet;
- descriptorWrite->dstBinding = GrVkUniformHandler::kUniformBinding;
- descriptorWrite->dstArrayElement = 0;
- descriptorWrite->descriptorCount = 1;
- descriptorWrite->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrite->pImageInfo = nullptr;
- descriptorWrite->pBufferInfo = bufferInfo;
- descriptorWrite->pTexelBufferView = nullptr;
-}
-
void GrVkPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) {
// Load the RT height uniform if it is needed to y-flip gl_FragCoord.