Revert "Move GrGeometryProcessor's textures out of classes and into"
This reverts commit af87483873f0b370b90ebe956301a13cc8662cbe.
Revert "GrGeometryProcessor derives from GrNonAtomicRef not GrProgramElement."
This reverts commit 607be37e3d4ddbe2163c200d6e13bcee981f6bf7.
Revert "Store GrMeshDrawOps' meshes in GrOpFlushState's arena."
This reverts commit b948572c7862214fe2e1fa6cdfcab4fc7b1666ac.
Revert "Remove multitexturing support from GrTextureOp."
This reverts commit 986f64c601f3ed99f84f0c392d1a42e298f6d618.
Revert "Make result of GrOp::combineIfPossible be an enum."
This reverts commit 641ac7daa81cbfca06b310803fb1a607d0fc2b32.
Bug: b/112244393
Change-Id: I579491a3f2f2f2093f1e2a6141fa1e4cc7b760a4
Reviewed-on: https://skia-review.googlesource.com/145646
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp
index 3d9cf95..8a382c7 100644
--- a/src/atlastext/SkAtlasTextTarget.cpp
+++ b/src/atlastext/SkAtlasTextTarget.cpp
@@ -181,7 +181,7 @@
int n = SkTMin(kMaxBatchLookBack, fOps.count());
for (int i = 0; i < n; ++i) {
GrAtlasTextOp* other = fOps.fromBack(i).get();
- if (other->combineIfPossible(op.get(), caps) == GrOp::CombineResult::kMerged) {
+ if (other->combineIfPossible(op.get(), caps)) {
fOpMemoryPool->release(std::move(op));
return;
}
diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp
index d66f24c..42e00f3 100644
--- a/src/gpu/GrGpuCommandBuffer.cpp
+++ b/src/gpu/GrGpuCommandBuffer.cpp
@@ -44,14 +44,9 @@
auto resourceProvider = this->gpu()->getContext()->contextPriv().resourceProvider();
- if (pipeline.isBad()) {
+ if (pipeline.isBad() || !primProc.instantiate(resourceProvider)) {
return false;
}
- for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
- if (!fixedDynamicState->fPrimitiveProcessorTextures[i]->instantiate(resourceProvider)) {
- return false;
- }
- }
if (primProc.numVertexAttributes() > this->gpu()->caps()->maxVertexAttributes()) {
this->gpu()->stats()->incNumFailedDraws();
diff --git a/src/gpu/GrMesh.h b/src/gpu/GrMesh.h
index e8a3f5c..fb7b525 100644
--- a/src/gpu/GrMesh.h
+++ b/src/gpu/GrMesh.h
@@ -21,12 +21,12 @@
*/
class GrMesh {
public:
- GrMesh(GrPrimitiveType primitiveType = GrPrimitiveType::kTriangles)
- : fPrimitiveType(primitiveType), fBaseVertex(0) {
+ GrMesh(GrPrimitiveType primitiveType)
+ : fPrimitiveType(primitiveType)
+ , fBaseVertex(0) {
SkDEBUGCODE(fNonIndexNonInstanceData.fVertexCount = -1;)
}
- void setPrimitiveType(GrPrimitiveType type) { fPrimitiveType = type; }
GrPrimitiveType primitiveType() const { return fPrimitiveType; }
bool isIndexed() const { return SkToBool(fIndexBuffer.get()); }
diff --git a/src/gpu/GrOpFlushState.cpp b/src/gpu/GrOpFlushState.cpp
index 6385c9f..8d8b7bb 100644
--- a/src/gpu/GrOpFlushState.cpp
+++ b/src/gpu/GrOpFlushState.cpp
@@ -45,7 +45,8 @@
SkASSERT(fCurrDraw->fPipeline->proxy() == this->drawOpArgs().fProxy);
this->rtCommandBuffer()->draw(*fCurrDraw->fGeometryProcessor, *fCurrDraw->fPipeline,
fCurrDraw->fFixedDynamicState, fCurrDraw->fDynamicStateArrays,
- fCurrDraw->fMeshes, fCurrDraw->fMeshCnt, opBounds);
+ fMeshes.begin() + fCurrMesh, fCurrDraw->fMeshCnt, opBounds);
+ fCurrMesh += fCurrDraw->fMeshCnt;
fTokenTracker->flushToken();
++fCurrDraw;
}
@@ -60,6 +61,7 @@
// Setup execution iterators.
fCurrDraw = fDraws.begin();
fCurrUpload = fInlineUploads.begin();
+ fCurrMesh = 0;
}
void GrOpFlushState::reset() {
@@ -71,6 +73,8 @@
fASAPUploads.reset();
fInlineUploads.reset();
fDraws.reset();
+ fMeshes.reset();
+ fCurrMesh = 0;
fBaseDrawToken = GrDeferredUploadToken::AlreadyFlushedToken();
}
@@ -100,23 +104,36 @@
return fTokenTracker->nextTokenToFlush();
}
-void GrOpFlushState::draw(sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
+void GrOpFlushState::draw(const GrGeometryProcessor* gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState,
- const GrMesh meshes[], int meshCnt) {
+ const GrMesh& mesh) {
SkASSERT(fOpArgs);
SkASSERT(fOpArgs->fOp);
+ fMeshes.push_back(mesh);
bool firstDraw = fDraws.begin() == fDraws.end();
+ if (!firstDraw) {
+ Draw& lastDraw = *fDraws.begin();
+ // If the last draw shares a geometry processor and pipeline and there are no intervening
+ // uploads, add this mesh to it.
+ // Note, we could attempt to convert fixed dynamic states into dynamic state arrays here
+ // if everything else is equal. Maybe it's better to rely on Ops to do that?
+ if (lastDraw.fGeometryProcessor == gp && lastDraw.fPipeline == pipeline &&
+ lastDraw.fFixedDynamicState == fixedDynamicState) {
+ if (fInlineUploads.begin() == fInlineUploads.end() ||
+ fInlineUploads.tail()->fUploadBeforeToken != fTokenTracker->nextDrawToken()) {
+ ++lastDraw.fMeshCnt;
+ return;
+ }
+ }
+ }
auto& draw = fDraws.append(&fArena);
GrDeferredUploadToken token = fTokenTracker->issueDrawToken();
- for (int i = 0; i < gp->numTextureSamplers(); ++i) {
- fixedDynamicState->fPrimitiveProcessorTextures[i]->addPendingRead();
- }
- draw.fGeometryProcessor = std::move(gp);
+
+ draw.fGeometryProcessor.reset(gp);
draw.fPipeline = pipeline;
draw.fFixedDynamicState = fixedDynamicState;
draw.fDynamicStateArrays = nullptr;
- draw.fMeshes = meshes;
- draw.fMeshCnt = meshCnt;
+ draw.fMeshCnt = 1;
draw.fOpID = fOpArgs->fOp->uniqueID();
if (firstDraw) {
fBaseDrawToken = token;
diff --git a/src/gpu/GrOpFlushState.h b/src/gpu/GrOpFlushState.h
index 0a46ed2..66ac34c 100644
--- a/src/gpu/GrOpFlushState.h
+++ b/src/gpu/GrOpFlushState.h
@@ -73,11 +73,9 @@
GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) final;
/** Overrides of GrMeshDrawOp::Target. */
- void draw(sk_sp<const GrGeometryProcessor>,
- const GrPipeline*,
- const GrPipeline::FixedDynamicState*,
- const GrMesh[],
- int meshCount) final;
+
+ void draw(const GrGeometryProcessor*, const GrPipeline*, const GrPipeline::FixedDynamicState*,
+ const GrMesh&) final;
void* makeVertexSpace(size_t vertexSize, int vertexCount, const GrBuffer**,
int* startVertex) final;
uint16_t* makeIndexSpace(int indexCount, const GrBuffer**, int* startIndex) final;
@@ -120,18 +118,12 @@
// that share a geometry processor into a Draw is that it allows the Gpu object to setup
// the shared state once and then issue draws for each mesh.
struct Draw {
- ~Draw() {
- for (int i = 0; i < fGeometryProcessor->numTextureSamplers(); ++i) {
- fFixedDynamicState->fPrimitiveProcessorTextures[i]->completedRead();
- }
- }
- sk_sp<const GrGeometryProcessor> fGeometryProcessor;
- const GrPipeline* fPipeline = nullptr;
+ int fMeshCnt = 0;
+ GrPendingProgramElement<const GrGeometryProcessor> fGeometryProcessor;
+ const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
const GrPipeline::DynamicStateArrays* fDynamicStateArrays;
- const GrMesh* fMeshes = nullptr;
- int fMeshCnt = 0;
- uint32_t fOpID = SK_InvalidUniqueID;
+ uint32_t fOpID;
};
// Storage for ops' pipelines, draws, and inline uploads.
@@ -145,6 +137,9 @@
SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads;
SkArenaAllocList<InlineUpload> fInlineUploads;
SkArenaAllocList<Draw> fDraws;
+ // TODO: These should go in the arena. However, GrGpuCommandBuffer and other classes currently
+ // accept contiguous arrays of meshes.
+ SkSTArray<16, GrMesh> fMeshes;
// All draws we store have an implicit draw token. This is the draw token for the first draw
// in fDraws.
@@ -161,6 +156,7 @@
// Variables that are used to track where we are in lists as ops are executed
SkArenaAllocList<Draw>::Iter fCurrDraw;
+ int fCurrMesh;
SkArenaAllocList<InlineUpload>::Iter fCurrUpload;
// Used to track the proxies that need to be uninstantiated after we finish a flush
diff --git a/src/gpu/GrPendingProgramElement.h b/src/gpu/GrPendingProgramElement.h
new file mode 100644
index 0000000..ab1f437
--- /dev/null
+++ b/src/gpu/GrPendingProgramElement.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrPendingProgramElement_DEFINED
+#define GrPendingProgramElement_DEFINED
+
+#include "SkRefCnt.h"
+#include "GrTypes.h"
+
+/**
+ * Helper for owning a pending execution on a GrProgramElement. Using this rather than ref allows
+ * resources that are owned by the program element to be correctly tracked as having pending reads
+ * and writes rather than refs.
+ */
+template <typename T> class GrPendingProgramElement : SkNoncopyable {
+public:
+ GrPendingProgramElement() : fObj(nullptr) { }
+
+ // Adds a pending execution on obj.
+ explicit GrPendingProgramElement(T* obj) : fObj(obj) {
+ if (obj) {
+ obj->addPendingExecution();
+ }
+ }
+
+ void reset(T* obj) {
+ if (obj) {
+ obj->addPendingExecution();
+ }
+ if (fObj) {
+ fObj->completedExecution();
+ }
+ fObj = obj;
+ }
+
+ T* get() const { return fObj; }
+ operator T*() { return fObj; }
+
+ T *operator->() const { return fObj; }
+
+ ~GrPendingProgramElement() {
+ if (fObj) {
+ fObj->completedExecution();
+ }
+ }
+
+private:
+ T* fObj;
+
+ typedef SkNoncopyable INHERITED;
+};
+#endif
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index b2f6711..24dd9f8 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -12,6 +12,7 @@
#include "GrFragmentProcessor.h"
#include "GrNonAtomicRef.h"
#include "GrPendingIOResource.h"
+#include "GrPendingProgramElement.h"
#include "GrProcessorSet.h"
#include "GrProgramDesc.h"
#include "GrRect.h"
@@ -75,11 +76,8 @@
* 2) DynamicStateArrays - use this to specify per mesh values for dynamic state.
**/
struct FixedDynamicState {
- explicit FixedDynamicState(const SkIRect& scissorRect) : fScissorRect(scissorRect) {}
- FixedDynamicState() = default;
- SkIRect fScissorRect = SkIRect::EmptyIRect();
- // Must have GrPrimitiveProcessor::numTextureSamplers() entries. Can be null if no samplers.
- GrTextureProxy** fPrimitiveProcessorTextures = nullptr;
+ FixedDynamicState(const SkIRect& scissorRect) : fScissorRect(scissorRect) {}
+ SkIRect fScissorRect;
};
/**
diff --git a/src/gpu/GrPrimitiveProcessor.cpp b/src/gpu/GrPrimitiveProcessor.cpp
index 6d2b1e9..84db9ca 100644
--- a/src/gpu/GrPrimitiveProcessor.cpp
+++ b/src/gpu/GrPrimitiveProcessor.cpp
@@ -74,6 +74,33 @@
}
#endif
+void GrPrimitiveProcessor::addPendingIOs() const {
+ for (int i = 0; i < fTextureSamplerCnt; ++i) {
+ this->textureSampler(i).proxyRef()->markPendingIO();
+ }
+}
+
+void GrPrimitiveProcessor::removeRefs() const {
+ for (int i = 0; i < fTextureSamplerCnt; ++i) {
+ this->textureSampler(i).proxyRef()->removeRef();
+ }
+}
+
+void GrPrimitiveProcessor::pendingIOComplete() const {
+ for (int i = 0; i < fTextureSamplerCnt; ++i) {
+ this->textureSampler(i).proxyRef()->pendingIOComplete();
+ }
+}
+
+bool GrPrimitiveProcessor::instantiate(GrResourceProvider* resourceProvider) const {
+ for (int i = 0; i < fTextureSamplerCnt; ++i) {
+ if (!this->textureSampler(i).instantiate(resourceProvider)) {
+ return false;
+ }
+ }
+ return true;
+}
+
uint32_t
GrPrimitiveProcessor::getTransformKey(const SkTArray<const GrCoordTransform*, true>& coords,
int numCoords) const {
@@ -95,50 +122,34 @@
///////////////////////////////////////////////////////////////////////////////////////////////////
-static inline GrSamplerState::Filter clamp_filter(GrTextureType type,
- GrSamplerState::Filter requestedFilter) {
- if (GrTextureTypeHasRestrictedSampling(type)) {
- return SkTMin(requestedFilter, GrSamplerState::Filter::kBilerp);
- }
- return requestedFilter;
-}
-
-GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
- GrPixelConfig config,
+GrPrimitiveProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
const GrSamplerState& samplerState,
GrShaderFlags visibility) {
- this->reset(textureType, config, samplerState, visibility);
+ this->reset(std::move(proxy), samplerState, visibility);
}
-GrPrimitiveProcessor::TextureSampler::TextureSampler(GrTextureType textureType,
- GrPixelConfig config,
+GrPrimitiveProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
GrSamplerState::Filter filterMode,
GrSamplerState::WrapMode wrapXAndY,
GrShaderFlags visibility) {
- this->reset(textureType, config, filterMode, wrapXAndY, visibility);
+ this->reset(std::move(proxy), filterMode, wrapXAndY, visibility);
}
-void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
- GrPixelConfig config,
+void GrPrimitiveProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
const GrSamplerState& samplerState,
GrShaderFlags visibility) {
- SkASSERT(kUnknown_GrPixelConfig != config);
+ fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
fSamplerState = samplerState;
- fSamplerState.setFilterMode(clamp_filter(textureType, samplerState.filter()));
- fTextureType = textureType;
- fConfig = config;
+ fSamplerState.setFilterMode(SkTMin(samplerState.filter(), this->proxy()->highestFilterMode()));
fVisibility = visibility;
}
-void GrPrimitiveProcessor::TextureSampler::reset(GrTextureType textureType,
- GrPixelConfig config,
+void GrPrimitiveProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
GrSamplerState::Filter filterMode,
GrSamplerState::WrapMode wrapXAndY,
GrShaderFlags visibility) {
- SkASSERT(kUnknown_GrPixelConfig != config);
- filterMode = clamp_filter(textureType, filterMode);
+ fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
+ filterMode = SkTMin(filterMode, this->proxy()->highestFilterMode());
fSamplerState = GrSamplerState(wrapXAndY, filterMode);
- fTextureType = textureType;
- fConfig = config;
fVisibility = visibility;
}
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index 4becb54..ddebd21 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -9,7 +9,6 @@
#define GrPrimitiveProcessor_DEFINED
#include "GrColor.h"
-#include "GrNonAtomicRef.h"
#include "GrProcessor.h"
#include "GrProxyRef.h"
#include "GrShaderVar.h"
@@ -37,15 +36,12 @@
class GrGLSLPrimitiveProcessor;
-/**
+/*
* GrPrimitiveProcessor defines an interface which all subclasses must implement. All
* GrPrimitiveProcessors must proivide seed color and coverage for the Ganesh color / coverage
* pipelines, and they must provide some notion of equality
- *
- * TODO: This class does not really need to be ref counted. Instances should be allocated using
- * GrOpFlushState's arena and destroyed when the arena is torn down.
*/
-class GrPrimitiveProcessor : public GrProcessor, public GrNonAtomicRef<GrPrimitiveProcessor> {
+class GrPrimitiveProcessor : public GrProcessor, public GrProgramElement {
public:
class TextureSampler;
@@ -140,6 +136,8 @@
virtual float getSampleShading() const { return 0.0; }
+ bool instantiate(GrResourceProvider*) const;
+
protected:
void setVertexAttributeCnt(int cnt) {
SkASSERT(cnt >= 0);
@@ -166,6 +164,11 @@
inline static const TextureSampler& IthTextureSampler(int i);
private:
+ void addPendingIOs() const final;
+ void removeRefs() const final;
+ void pendingIOComplete() const final;
+ void notifyRefCntIsZero() const final {}
+
virtual const Attribute& onVertexAttribute(int) const = 0;
virtual const Attribute& onInstanceAttribute(int) const = 0;
virtual const TextureSampler& onTextureSampler(int) const { return IthTextureSampler(0); }
@@ -187,9 +190,9 @@
public:
TextureSampler() = default;
- TextureSampler(GrTextureType, GrPixelConfig, const GrSamplerState&, GrShaderFlags visibility);
+ TextureSampler(sk_sp<GrTextureProxy>, const GrSamplerState&, GrShaderFlags visibility);
- explicit TextureSampler(GrTextureType, GrPixelConfig,
+ explicit TextureSampler(sk_sp<GrTextureProxy>,
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
GrShaderFlags visibility = kFragment_GrShaderFlag);
@@ -197,25 +200,36 @@
TextureSampler(const TextureSampler&) = delete;
TextureSampler& operator=(const TextureSampler&) = delete;
- void reset(GrTextureType, GrPixelConfig, const GrSamplerState&,
+ void reset(sk_sp<GrTextureProxy>, const GrSamplerState&,
GrShaderFlags visibility = kFragment_GrShaderFlag);
- void reset(GrTextureType, GrPixelConfig,
+ void reset(sk_sp<GrTextureProxy>,
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
GrShaderFlags visibility = kFragment_GrShaderFlag);
- GrTextureType textureType() const { return fTextureType; }
- GrPixelConfig config() const { return fConfig; }
+ bool instantiate(GrResourceProvider* resourceProvider) const {
+ return SkToBool(fProxyRef.get()->instantiate(resourceProvider));
+ }
+ // 'peekTexture' should only ever be called after a successful 'instantiate' call
+ GrTexture* peekTexture() const {
+ SkASSERT(fProxyRef.get()->peekTexture());
+ return fProxyRef.get()->peekTexture();
+ }
+
+ GrTextureProxy* proxy() const { return fProxyRef.get(); }
GrShaderFlags visibility() const { return fVisibility; }
const GrSamplerState& samplerState() const { return fSamplerState; }
- bool isInitialized() const { return fConfig != kUnknown_GrPixelConfig; }
+ bool isInitialized() const { return SkToBool(fProxyRef.get()); }
+ /**
+ * For internal use by GrPrimitiveProcessor.
+ */
+ const GrTextureProxyRef* proxyRef() const { return &fProxyRef; }
private:
+ GrTextureProxyRef fProxyRef;
GrSamplerState fSamplerState;
- GrTextureType fTextureType = GrTextureType::k2D;
- GrPixelConfig fConfig = kUnknown_GrPixelConfig;
GrShaderFlags fVisibility = kNone_GrShaderFlags;
};
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 3c6662c..4afb246 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -12,6 +12,7 @@
#include "GrBuffer.h"
#include "GrColor.h"
#include "GrProcessorUnitTest.h"
+#include "GrProgramElement.h"
#include "GrSamplerState.h"
#include "GrShaderVar.h"
#include "GrSurfaceProxyPriv.h"
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 5c10b9f..e99a947 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -80,7 +80,8 @@
uint16_t* k16 = reinterpret_cast<uint16_t*>(b->add32n(word32Count));
for (int i = 0; i < numTextureSamplers; ++i) {
const GrPrimitiveProcessor::TextureSampler& sampler = pp.textureSampler(i);
- k16[i] = sampler_key(sampler.textureType(), sampler.config(), caps);
+ const GrTexture* tex = sampler.peekTexture();
+ k16[i] = sampler_key(tex->texturePriv().textureType(), tex->config(), caps);
}
// zero the last 16 bits if the number of uniforms for samplers is odd.
if (numTextureSamplers & 0x1) {
diff --git a/src/gpu/GrProgramElement.h b/src/gpu/GrProgramElement.h
new file mode 100644
index 0000000..ef96738
--- /dev/null
+++ b/src/gpu/GrProgramElement.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramElement_DEFINED
+#define GrProgramElement_DEFINED
+
+#include "../private/SkTArray.h"
+#include "SkRefCnt.h"
+
+/**
+ * Note: We are converting GrProcessor from ref counting to a single owner model using move
+ * semantics. This class will be removed.
+ *
+ * This is used to track "refs" for two separate types GrProcessor ownership. A regular ref is owned
+ * by any client that may continue to issue draws that use the GrProgramElement. A recorded op or
+ * GrPipeline uses "pending executions" instead of refs. A pending execution is cleared after the
+ * draw is executed (or aborted).
+ *
+ * While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
+ * into the state where it has pending executions AND no refs then it converts its ownership of
+ * its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is
+ * safe to recycle a resource even though we still have buffered GrOps that read or write to the
+ * the resource.
+ *
+ * To make this work the subclass GrProcessor implements addPendingIOs, removeRefs, and
+ * pendingIOComplete. addPendingIOs adds pending reads/writes to GrGpuResources owned by the
+ * processor as appropriate when the processor is recorded in a GrOpList. removeRefs is called when
+ * the ref count reaches 0 and the GrProcessor is only owned by "pending executions".
+ * pendingIOComplete occurs if the resource is still owned by a ref but all recorded draws have been
+ * completed. Whenever pending executions and refs reach zero the processor is deleted.
+ *
+ * The GrProcessor may also implement notifyRefCntIsZero in order to change its ownership of child
+ * processors from ref to pending execution when the processor is first owned exclusively in pending
+ * execution mode.
+ */
+class GrProgramElement : public SkNoncopyable {
+public:
+ virtual ~GrProgramElement() {
+ // fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
+ SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
+ // Set to invalid values.
+ SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
+ }
+
+ void ref() const {
+ this->validate();
+ // Once the ref cnt reaches zero it should never be ref'ed again.
+ SkASSERT(fRefCnt > 0);
+ ++fRefCnt;
+ this->validate();
+ }
+
+ void unref() const {
+ this->validate();
+ --fRefCnt;
+ if (0 == fRefCnt) {
+ this->notifyRefCntIsZero();
+ if (0 == fPendingExecutions) {
+ delete this;
+ return;
+ } else {
+ this->removeRefs();
+ }
+ }
+ this->validate();
+ }
+
+ void validate() const {
+#ifdef SK_DEBUG
+ SkASSERT(fRefCnt >= 0);
+ SkASSERT(fPendingExecutions >= 0);
+ SkASSERT(fRefCnt + fPendingExecutions > 0);
+#endif
+ }
+
+protected:
+ GrProgramElement() : fRefCnt(1), fPendingExecutions(0) {}
+
+ void addPendingExecution() const {
+ this->validate();
+ if (0 == fPendingExecutions) {
+ this->addPendingIOs();
+ }
+ ++fPendingExecutions;
+ this->validate();
+ }
+
+ void completedExecution() const {
+ this->validate();
+ --fPendingExecutions;
+ if (0 == fPendingExecutions) {
+ if (0 == fRefCnt) {
+ delete this;
+ return;
+ } else {
+ this->pendingIOComplete();
+ }
+ }
+ this->validate();
+ }
+
+private:
+ virtual void addPendingIOs() const = 0;
+ virtual void removeRefs() const = 0;
+ virtual void pendingIOComplete() const = 0;
+
+ /** This will be called when the ref cnt is zero. The object may or may not have pending
+ executions. */
+ virtual void notifyRefCntIsZero() const = 0;
+
+ mutable int32_t fRefCnt;
+ // Count of deferred executions not yet issued to the 3D API.
+ mutable int32_t fPendingExecutions;
+
+ // Only these classes can access addPendingExecution() and completedExecution().
+ template <typename T> friend class GrPendingProgramElement;
+ friend class GrProcessorSet;
+
+ typedef SkNoncopyable INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 33836a7..569b5fa 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -339,7 +339,7 @@
} else if (a.fDstProxy.proxy()) {
return false;
}
- return a.fOp->combineIfPossible(b, caps) == GrOp::CombineResult::kMerged;
+ return a.fOp->combineIfPossible(b, caps);
}
uint32_t GrRenderTargetOpList::recordOp(std::unique_ptr<GrOp> op,
diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp
index d29fe58..9ab5f90 100644
--- a/src/gpu/GrShaderCaps.cpp
+++ b/src/gpu/GrShaderCaps.cpp
@@ -64,6 +64,10 @@
fMaxFragmentSamplers = 0;
fMaxCombinedSamplers = 0;
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
+
+ // TODO: Default this to 0 and only enable image multitexturing when a "safe" threshold is
+ // known for a GPU class.
+ fDisableImageMultitexturingDstRectAreaThreshold = std::numeric_limits<size_t>::max();
}
void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const {
@@ -119,6 +123,8 @@
writer->appendS32("Max Combined Samplers", fMaxFragmentSamplers);
writer->appendString("Advanced blend equation interaction",
kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]);
+ writer->appendU64("Disable image multitexturing dst area threshold",
+ fDisableImageMultitexturingDstRectAreaThreshold);
writer->endObject();
}
@@ -139,5 +145,8 @@
}
#if GR_TEST_UTILS
fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending;
+ if (options.fDisableImageMultitexturing) {
+ fDisableImageMultitexturingDstRectAreaThreshold = 0;
+ }
#endif
}
diff --git a/src/gpu/GrShaderCaps.h b/src/gpu/GrShaderCaps.h
index d8422c7..a599f1d 100644
--- a/src/gpu/GrShaderCaps.h
+++ b/src/gpu/GrShaderCaps.h
@@ -205,6 +205,15 @@
int maxCombinedSamplers() const { return fMaxCombinedSamplers; }
/**
+ * In general using multiple texture units for image rendering seems to be a win at smaller
+ * sizes of dst rects and a loss at larger sizes. Dst rects above this pixel area threshold will
+ * not use multitexturing.
+ */
+ size_t disableImageMultitexturingDstRectAreaThreshold() const {
+ return fDisableImageMultitexturingDstRectAreaThreshold;
+ }
+
+ /**
* Given a texture's config, this determines what swizzle must be appended to accesses to the
* texture in generated shader code. Swizzling may be implemented in texture parameters or a
* sampler rather than in the shader. In this case the returned swizzle will always be "rgba".
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index aed0672..016756a 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -117,7 +117,7 @@
return RequiresDstTexture(analysis.requiresDstTexture());
}
-GrOp::CombineResult GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
+bool GrCCDrawPathsOp::onCombineIfPossible(GrOp* op, const GrCaps&) {
GrCCDrawPathsOp* that = op->cast<GrCCDrawPathsOp>();
SkASSERT(fOwningPerOpListPaths);
SkASSERT(fNumDraws);
@@ -126,7 +126,7 @@
if (fProcessors != that->fProcessors ||
fViewMatrixIfUsingLocalCoords != that->fViewMatrixIfUsingLocalCoords) {
- return CombineResult::kCannotCombine;
+ return false;
}
fDraws.append(std::move(that->fDraws), &fOwningPerOpListPaths->fAllocator);
@@ -134,7 +134,7 @@
SkDEBUGCODE(fNumDraws += that->fNumDraws);
SkDEBUGCODE(that->fNumDraws = 0);
- return CombineResult::kMerged;
+ return true;
}
void GrCCDrawPathsOp::wasRecorded(GrCCPerOpListPaths* owningPerOpListPaths) {
@@ -312,7 +312,7 @@
}
}
-inline void GrCCDrawPathsOp::recordInstance(GrTextureProxy* atlasProxy, int instanceIdx) {
+inline void GrCCDrawPathsOp::recordInstance(const GrTextureProxy* atlasProxy, int instanceIdx) {
if (fInstanceRanges.empty()) {
fInstanceRanges.push_back({atlasProxy, instanceIdx});
return;
@@ -347,9 +347,8 @@
for (const InstanceRange& range : fInstanceRanges) {
SkASSERT(range.fEndInstanceIdx > baseInstance);
- GrCCPathProcessor pathProc(range.fAtlasProxy, fViewMatrixIfUsingLocalCoords);
- GrTextureProxy* atlasProxy = range.fAtlasProxy;
- fixedDynamicState.fPrimitiveProcessorTextures = &atlasProxy;
+ GrCCPathProcessor pathProc(flushState->resourceProvider(), sk_ref_sp(range.fAtlasProxy),
+ fViewMatrixIfUsingLocalCoords);
pathProc.drawPaths(flushState, pipeline, &fixedDynamicState, *resources, baseInstance,
range.fEndInstanceIdx, this->bounds());
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h
index 40d9df4..9ef317f 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.h
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.h
@@ -37,7 +37,7 @@
const char* name() const override { return "GrCCDrawPathsOp"; }
FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override;
- CombineResult onCombineIfPossible(GrOp*, const GrCaps&) override;
+ bool onCombineIfPossible(GrOp*, const GrCaps&) override;
void visitProxies(const VisitProxyFunc& fn) const override { fProcessors.visitProxies(fn); }
void onPrepare(GrOpFlushState*) override {}
@@ -80,7 +80,7 @@
const SkIRect& maskDevIBounds, Visibility maskVisibility,
const SkRect& devBounds, GrPaint&&);
- void recordInstance(GrTextureProxy* atlasProxy, int instanceIdx);
+ void recordInstance(const GrTextureProxy* atlasProxy, int instanceIdx);
const SkMatrix fViewMatrixIfUsingLocalCoords;
@@ -110,7 +110,7 @@
GrProcessorSet fProcessors;
struct InstanceRange {
- GrTextureProxy* fAtlasProxy;
+ const GrTextureProxy* fAtlasProxy;
int fEndInstanceIdx;
};
diff --git a/src/gpu/ccpr/GrCCPathProcessor.cpp b/src/gpu/ccpr/GrCCPathProcessor.cpp
index 4a9a8aa..ae3cba3 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPathProcessor.cpp
@@ -79,14 +79,12 @@
}
}
-GrCCPathProcessor::GrCCPathProcessor(const GrTextureProxy* atlas,
+GrCCPathProcessor::GrCCPathProcessor(GrResourceProvider* resourceProvider,
+ sk_sp<GrTextureProxy> atlas,
const SkMatrix& viewMatrixIfUsingLocalCoords)
: INHERITED(kGrCCPathProcessor_ClassID)
- , fAtlasAccess(atlas->textureType(), atlas->config(), GrSamplerState::Filter::kNearest,
- GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag)
- , fAtlasSize(atlas->isize())
- , fAtlasOrigin(atlas->origin()) {
- // TODO: Can we just assert that atlas has GrCCAtlas::kTextureOrigin and remove fAtlasOrigin?
+ , fAtlasAccess(std::move(atlas), GrSamplerState::Filter::kNearest,
+ GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag) {
this->setInstanceAttributeCnt(kNumInstanceAttribs);
// Check that instance attributes exactly match Instance struct layout.
SkASSERT(!strcmp(this->instanceAttribute(0).name(), "devbounds"));
@@ -100,6 +98,8 @@
SkASSERT(this->debugOnly_instanceStride() == sizeof(Instance));
this->setVertexAttributeCnt(1);
+
+ fAtlasAccess.instantiate(resourceProvider);
this->setTextureSamplerCnt(1);
if (!viewMatrixIfUsingLocalCoords.invert(&fLocalMatrix)) {
@@ -115,8 +115,8 @@
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
FPCoordTransformIter&& transformIter) override {
const GrCCPathProcessor& proc = primProc.cast<GrCCPathProcessor>();
- pdman.set2f(fAtlasAdjustUniform, 1.0f / proc.atlasSize().fWidth,
- 1.0f / proc.atlasSize().fHeight);
+ pdman.set2f(fAtlasAdjustUniform, 1.0f / proc.atlas()->width(),
+ 1.0f / proc.atlas()->height());
this->setTransformDataHelper(proc.localMatrix(), pdman, &transformIter);
}
@@ -210,10 +210,10 @@
// Convert to atlas coordinates in order to do our texture lookup.
v->codeAppendf("float2 atlascoord = octocoord + float2(%s);",
proc.getInstanceAttrib(InstanceAttribs::kDevToAtlasOffset).name());
- if (kTopLeft_GrSurfaceOrigin == proc.atlasOrigin()) {
+ if (kTopLeft_GrSurfaceOrigin == proc.atlasProxy()->origin()) {
v->codeAppendf("%s.xy = atlascoord * %s;", texcoord.vsOut(), atlasAdjust);
} else {
- SkASSERT(kBottomLeft_GrSurfaceOrigin == proc.atlasOrigin());
+ SkASSERT(kBottomLeft_GrSurfaceOrigin == proc.atlasProxy()->origin());
v->codeAppendf("%s.xy = float2(atlascoord.x * %s.x, 1 - atlascoord.y * %s.y);",
texcoord.vsOut(), atlasAdjust, atlasAdjust);
}
diff --git a/src/gpu/ccpr/GrCCPathProcessor.h b/src/gpu/ccpr/GrCCPathProcessor.h
index 394746b..752083a 100644
--- a/src/gpu/ccpr/GrCCPathProcessor.h
+++ b/src/gpu/ccpr/GrCCPathProcessor.h
@@ -69,12 +69,12 @@
static sk_sp<const GrBuffer> FindVertexBuffer(GrOnFlushResourceProvider*);
static sk_sp<const GrBuffer> FindIndexBuffer(GrOnFlushResourceProvider*);
- GrCCPathProcessor(const GrTextureProxy* atlas,
+ GrCCPathProcessor(GrResourceProvider*, sk_sp<GrTextureProxy> atlas,
const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I());
const char* name() const override { return "GrCCPathProcessor"; }
- const SkISize& atlasSize() const { return fAtlasSize; }
- GrSurfaceOrigin atlasOrigin() const { return fAtlasOrigin; }
+ const GrSurfaceProxy* atlasProxy() const { return fAtlasAccess.proxy(); }
+ const GrTexture* atlas() const { return fAtlasAccess.peekTexture(); }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
const Attribute& getInstanceAttrib(InstanceAttribs attribID) const {
int idx = static_cast<int>(attribID);
@@ -96,9 +96,6 @@
const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; }
const TextureSampler fAtlasAccess;
- SkISize fAtlasSize;
- GrSurfaceOrigin fAtlasOrigin;
-
SkMatrix fLocalMatrix;
static constexpr Attribute kInstanceAttribs[kNumInstanceAttribs] = {
{"devbounds", kFloat4_GrVertexAttribType},
diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp
index 2b246c9..aed1af7 100644
--- a/src/gpu/ccpr/GrCCPerFlushResources.cpp
+++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp
@@ -27,9 +27,9 @@
RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*) override {
return RequiresDstTexture::kNo;
}
- CombineResult onCombineIfPossible(GrOp* other, const GrCaps&) override {
+ bool onCombineIfPossible(GrOp* other, const GrCaps&) override {
SK_ABORT("Only expected one Op per CCPR atlas.");
- return CombineResult::kMerged;
+ return true;
}
void onPrepare(GrOpFlushState*) override {}
@@ -65,18 +65,14 @@
void onExecute(GrOpFlushState* flushState) override {
SkASSERT(fStashedAtlasProxy);
- GrPipeline::FixedDynamicState dynamicState;
- auto atlasProxy = fStashedAtlasProxy.get();
- dynamicState.fPrimitiveProcessorTextures = &atlasProxy;
-
GrPipeline pipeline(flushState->proxy(), GrPipeline::ScissorState::kDisabled,
SkBlendMode::kSrc);
- GrCCPathProcessor pathProc(atlasProxy);
- pathProc.drawPaths(flushState, pipeline, &dynamicState, *fResources, fBaseInstance,
- fEndInstance, this->bounds());
+ GrCCPathProcessor pathProc(flushState->resourceProvider(), std::move(fStashedAtlasProxy));
+ pathProc.drawPaths(flushState, pipeline, nullptr, *fResources, fBaseInstance, fEndInstance,
+ this->bounds());
// Ensure we released the stashed atlas proxy. This allows its underlying texture to be
// reused as the current flush's mainline CCPR atlas if needed.
- fStashedAtlasProxy.reset();
+ SkASSERT(!fStashedAtlasProxy);
}
private:
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index ee38f43..32da45c 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -86,12 +86,13 @@
fColor = btgp.color();
}
- const SkISize& atlasSize = btgp.atlasSize();
- SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
+ SkASSERT(btgp.numTextureSamplers() >= 1);
+ GrTexture* atlas = btgp.textureSampler(0).peekTexture();
+ SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
- if (fAtlasSize != atlasSize) {
- pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
- fAtlasSize = atlasSize;
+ if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
+ pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
+ fAtlasSize.set(atlas->width(), atlas->height());
}
this->setTransformDataHelper(btgp.localMatrix(), pdman, &transformIter);
}
@@ -148,13 +149,9 @@
this->setVertexAttributeCnt(cnt);
- if (numActiveProxies) {
- fAtlasSize = proxies[0]->isize();
- }
for (int i = 0; i < numActiveProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
this->setTextureSamplerCnt(numActiveProxies);
}
@@ -168,16 +165,11 @@
const GrSamplerState& params) {
SkASSERT(numActiveProxies <= kMaxTextures);
- if (!fTextureSamplers[0].isInitialized()) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numActiveProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
}
this->setTextureSamplerCnt(numActiveProxies);
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index d2d530e..1bc0620 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -21,7 +21,6 @@
*/
class GrBitmapTextGeoProc : public GrGeometryProcessor {
public:
- static constexpr int kMaxTextures = 4;
static sk_sp<GrGeometryProcessor> Make(GrColor color,
const sk_sp<GrTextureProxy>* proxies,
@@ -45,7 +44,6 @@
bool hasVertexColor() const { return fInColor.isInitialized(); }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
bool usesW() const { return fUsesW; }
- const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@@ -54,6 +52,8 @@
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
private:
+ static constexpr int kMaxTextures = 4;
+
GrBitmapTextGeoProc(GrColor, const sk_sp<GrTextureProxy>* proxies, int numProxies,
const GrSamplerState& params, GrMaskFormat format,
const SkMatrix& localMatrix, bool usesW);
@@ -64,7 +64,6 @@
GrColor fColor;
SkMatrix fLocalMatrix;
bool fUsesW;
- SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
TextureSampler fTextureSamplers[kMaxTextures];
Attribute fInPosition;
Attribute fInColor;
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 099cc7e..b9e5681 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -172,13 +172,15 @@
}
#endif
- const SkISize& atlasSize = dfa8gp.atlasSize();
- SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
+ SkASSERT(dfa8gp.numTextureSamplers() >= 1);
+ GrTexture* atlas = dfa8gp.textureSampler(0).peekTexture();
+ SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
- if (fAtlasSize != atlasSize) {
- pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
- fAtlasSize = atlasSize;
+ if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
+ fAtlasSize.set(atlas->width(), atlas->height());
+ pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
}
+
this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter);
}
@@ -232,13 +234,9 @@
}
this->setVertexAttributeCnt(3);
- if (numProxies) {
- fAtlasSize = proxies[0]->isize();
- }
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
this->setTextureSamplerCnt(numProxies);
}
@@ -248,15 +246,10 @@
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
- if (!fTextureSamplers[0].isInitialized()) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
}
this->setTextureSamplerCnt(numProxies);
@@ -467,11 +460,13 @@
pdman.setMatrix3f(fMatrixUniform, matrix);
}
- const SkISize& atlasSize = dfpgp.atlasSize();
- SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
- if (fAtlasSize != atlasSize) {
- pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
- fAtlasSize = atlasSize;
+ SkASSERT(dfpgp.numTextureSamplers() >= 1);
+ GrTexture* atlas = dfpgp.textureSampler(0).peekTexture();
+ SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
+
+ if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
+ fAtlasSize.set(atlas->width(), atlas->height());
+ pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
}
if (dfpgp.matrix().hasPerspective()) {
@@ -520,15 +515,9 @@
SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
this->setVertexAttributeCnt(3);
-
- if (numProxies) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
this->setTextureSamplerCnt(numProxies);
}
@@ -538,16 +527,11 @@
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
- if (!fTextureSamplers[0].isInitialized()) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
}
this->setTextureSamplerCnt(numProxies);
@@ -789,11 +773,13 @@
fDistanceAdjust = wa;
}
- const SkISize& atlasSize = dflcd.atlasSize();
- SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
- if (fAtlasSize != atlasSize) {
- pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
- fAtlasSize = atlasSize;
+ SkASSERT(dflcd.numTextureSamplers() >= 1);
+ GrTexture* atlas = dflcd.textureSampler(0).peekTexture();
+ SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
+
+ if (fAtlasSize.fWidth != atlas->width() || fAtlasSize.fHeight != atlas->height()) {
+ fAtlasSize.set(atlas->width(), atlas->height());
+ pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlas->width(), 1.0f / atlas->height());
}
this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter);
}
@@ -843,14 +829,9 @@
}
this->setVertexAttributeCnt(3);
- if (numProxies) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
this->setTextureSamplerCnt(numProxies);
}
@@ -860,16 +841,11 @@
const GrSamplerState& params) {
SkASSERT(numProxies <= kMaxTextures);
- if (!fTextureSamplers[0].isInitialized()) {
- fAtlasSize = proxies[0]->isize();
- }
-
for (int i = 0; i < numProxies; ++i) {
SkASSERT(proxies[i]);
- SkASSERT(proxies[i]->isize() == fAtlasSize);
if (!fTextureSamplers[i].isInitialized()) {
- fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
+ fTextureSamplers[i].reset(std::move(proxies[i]), params);
}
}
this->setTextureSamplerCnt(numProxies);
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index fcd98aa..a0fb9d7 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -53,8 +53,6 @@
*/
class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor {
public:
- static constexpr int kMaxTextures = 4;
-
/** The local matrix should be identity if local coords are not required by the GrPipeline. */
#ifdef SK_GAMMA_APPLY_TO_A8
static sk_sp<GrGeometryProcessor> Make(const sk_sp<GrTextureProxy>* proxies,
@@ -86,7 +84,6 @@
float getDistanceAdjust() const { return fDistanceAdjust; }
#endif
uint32_t getFlags() const { return fFlags; }
- const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>* proxies, int numProxies, const GrSamplerState&);
@@ -109,8 +106,9 @@
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
+ static constexpr int kMaxTextures = 4;
+
TextureSampler fTextureSamplers[kMaxTextures];
- SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
SkMatrix fLocalMatrix;
Attribute fInPosition;
uint32_t fFlags;
@@ -134,7 +132,6 @@
*/
class GrDistanceFieldPathGeoProc : public GrGeometryProcessor {
public:
- static constexpr int kMaxTextures = 4;
/** The local matrix should be identity if local coords are not required by the GrPipeline. */
static sk_sp<GrGeometryProcessor> Make(const SkMatrix& matrix,
@@ -154,7 +151,6 @@
const Attribute& inTextureCoords() const { return kInTextureCoords; }
const SkMatrix& matrix() const { return fMatrix; }
uint32_t getFlags() const { return fFlags; }
- const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@@ -163,6 +159,8 @@
GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
private:
+ static constexpr int kMaxTextures = 4;
+
GrDistanceFieldPathGeoProc(const SkMatrix& matrix,
const sk_sp<GrTextureProxy>* proxies,
int numActiveProxies,
@@ -171,9 +169,8 @@
const Attribute& onVertexAttribute(int i) const override;
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
- SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise
+ SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise
TextureSampler fTextureSamplers[kMaxTextures];
- SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
uint32_t fFlags;
static constexpr Attribute kInPosition = {"inPosition", kFloat2_GrVertexAttribType};
static constexpr Attribute kInColor = {"inColor", kUByte4_norm_GrVertexAttribType};
@@ -192,8 +189,6 @@
*/
class GrDistanceFieldLCDTextGeoProc : public GrGeometryProcessor {
public:
- static constexpr int kMaxTextures = 4;
-
struct DistanceAdjust {
SkScalar fR, fG, fB;
static DistanceAdjust Make(SkScalar r, SkScalar g, SkScalar b) {
@@ -230,7 +225,6 @@
DistanceAdjust getDistanceAdjust() const { return fDistanceAdjust; }
uint32_t getFlags() const { return fFlags; }
const SkMatrix& localMatrix() const { return fLocalMatrix; }
- const SkISize& atlasSize() const { return fAtlasSize; }
void addNewProxies(const sk_sp<GrTextureProxy>*, int numActiveProxies, const GrSamplerState&);
@@ -246,8 +240,9 @@
const Attribute& onVertexAttribute(int) const override;
const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
+ static constexpr int kMaxTextures = 4;
+
TextureSampler fTextureSamplers[kMaxTextures];
- SkISize fAtlasSize; // size for all textures used with fTextureSamplers[].
const SkMatrix fLocalMatrix;
DistanceAdjust fDistanceAdjust;
Attribute fInPosition;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index f496044..c0549e9 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -364,6 +364,30 @@
GR_GL_GetIntegerv(gli, GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxSamplers);
shaderCaps->fMaxCombinedSamplers = SkTMin<GrGLint>(kMaxSaneSamplers, maxSamplers);
+ // This is all *very* approximate.
+ switch (ctxInfo.vendor()) {
+ case kNVIDIA_GrGLVendor:
+ // We've seen a range from 100 x 100 (TegraK1, GTX660) up to 300 x 300 (GTX 1070)
+ // but it doesn't clearly align with Pascal vs Maxwell vs Kepler.
+ fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold = 150 * 150;
+ break;
+ case kImagination_GrGLVendor:
+ // Two PowerVR Rogues, Nexus Player and Chromebook Cb5-312T (PowerVR GX6250), show that
+ // it is always a win to use multitexturing.
+ if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
+ fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold =
+ std::numeric_limits<size_t>::max();
+ }
+ break;
+ case kATI_GrGLVendor:
+ // So far no AMD GPU shows a performance difference. A tie goes to disabling
+ // multitexturing for simplicity's sake.
+ fShaderCaps->fDisableImageMultitexturingDstRectAreaThreshold = 0;
+ break;
+ default:
+ break;
+ }
+
// SGX and Mali GPUs that are based on a tiled-deferred architecture that have trouble with
// frequently changing VBOs. We've measured a performance increase using non-VBO vertex
// data for dynamic content on these GPUs. Perhaps we should read the renderer string and
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 7ef043b..cc858a8 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1675,10 +1675,8 @@
}
void GrGLGpu::generateMipmapsForProcessorTextures(const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrTextureProxy* const primProcTextures[]) {
+ const GrPipeline& pipeline) {
auto genLevelsIfNeeded = [this](GrTexture* tex, const GrSamplerState& sampler) {
- SkASSERT(tex);
if (sampler.filter() == GrSamplerState::Filter::kMipMap &&
tex->texturePriv().mipMapped() == GrMipMapped::kYes &&
tex->texturePriv().mipMapsAreDirty()) {
@@ -1688,8 +1686,8 @@
};
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
- GrTexture* tex = primProcTextures[i]->peekTexture();
- genLevelsIfNeeded(tex, primProc.textureSampler(i).samplerState());
+ const auto& textureSampler = primProc.textureSampler(i);
+ genLevelsIfNeeded(textureSampler.peekTexture(), textureSampler.samplerState());
}
GrFragmentProcessor::Iter iter(pipeline);
@@ -1710,11 +1708,8 @@
GrCapsDebugf(this->caps(), "Failed to create program!\n");
return false;
}
- const GrTextureProxy* const* primProcProxies = nullptr;
- if (fixedDynamicState) {
- primProcProxies = fixedDynamicState->fPrimitiveProcessorTextures;
- }
- this->generateMipmapsForProcessorTextures(primProc, pipeline, primProcProxies);
+
+ this->generateMipmapsForProcessorTextures(primProc, pipeline);
GrXferProcessor::BlendInfo blendInfo;
pipeline.getXferProcessor().getBlendInfo(&blendInfo);
@@ -1731,7 +1726,7 @@
this->flushBlend(blendInfo, swizzle);
}
- fHWProgram->updateUniformsAndTextureBindings(primProc, pipeline, primProcProxies);
+ fHWProgram->setData(primProc, pipeline);
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.renderTarget());
GrStencilSettings stencil;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 0f1127a..32b2945 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -247,9 +247,7 @@
void setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]);
- void generateMipmapsForProcessorTextures(
- const GrPrimitiveProcessor&, const GrPipeline&,
- const GrTextureProxy* const primitiveProcessorTextures[]);
+ void generateMipmapsForProcessorTextures(const GrPrimitiveProcessor&, const GrPipeline&);
// Flushes state from GrPipeline to GL. Returns false if the state couldn't be set.
// willDrawPoints must be true if point primitives will be rendered after setting the GL state.
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 9e90642..e0eccf2 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -72,10 +72,7 @@
///////////////////////////////////////////////////////////////////////////////
-void GrGLProgram::updateUniformsAndTextureBindings(const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrTextureProxy* const primProcTextures[]) {
- SkASSERT(primProcTextures || !primProc.numTextureSamplers());
+void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline) {
this->setRenderTargetState(primProc, pipeline.proxy());
// we set the textures, and uniforms for installed processors in a generic way, but subclasses
@@ -88,8 +85,9 @@
fPrimitiveProcessor->setData(fProgramDataManager, primProc,
GrFragmentProcessor::CoordTransformIter(pipeline));
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
- auto* tex = static_cast<GrGLTexture*>(primProcTextures[i]->peekTexture());
- fGpu->bindTexture(nextTexSamplerIdx++, primProc.textureSampler(i).samplerState(), tex);
+ const GrPrimitiveProcessor::TextureSampler& sampler = primProc.textureSampler(i);
+ fGpu->bindTexture(nextTexSamplerIdx++, sampler.samplerState(),
+ static_cast<GrGLTexture*>(sampler.peekTexture()));
}
this->setFragmentData(pipeline, &nextTexSamplerIdx);
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index ca9253c..b05b536 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -19,7 +19,6 @@
class GrPipeline;
class GrPrimitiveProcessor;
class GrRenderTargetProxy;
-class GrTextureProxy;
/**
* This class manages a GPU program and records per-program information. It also records the vertex
@@ -111,13 +110,12 @@
};
/**
- * This function uploads uniforms, calls each GrGLSL*Processor's setData. It binds all fragment
- * processor textures. Primitive process textures are also bound here but are passed separately.
- *
- * It is the caller's responsibility to ensure the program is bound before calling.
+ * This function uploads uniforms, calls each GrGL*Processor's setData, and retrieves the
+ * textures that need to be bound on each unit. It is the caller's responsibility to ensure
+ * the program is bound before calling, and to bind the outgoing textures to their respective
+ * units upon return. (Each index in the array corresponds to its matching GL texture unit.)
*/
- void updateUniformsAndTextureBindings(const GrPrimitiveProcessor&, const GrPipeline&,
- const GrTextureProxy* const primitiveProcessorTextures[]);
+ void setData(const GrPrimitiveProcessor&, const GrPipeline&);
int vertexStride() const { return fVertexStride; }
int instanceStride() const { return fInstanceStride; }
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index ba290ac..b60088d 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -33,7 +33,11 @@
const GrPipeline& pipeline,
GrProgramDesc* desc,
GrGLGpu* gpu) {
- SkASSERT(!pipeline.isBad());
+#ifdef SK_DEBUG
+ GrResourceProvider* resourceProvider = gpu->getContext()->contextPriv().resourceProvider();
+
+ SkASSERT(!pipeline.isBad() && primProc.instantiate(resourceProvider));
+#endif
ATRACE_ANDROID_FRAMEWORK("Shader Compile");
GrAutoLocaleSetter als("C");
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 66e333a..b0cf816 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -101,8 +101,9 @@
SkString name;
name.printf("TextureSampler_%d", i);
const auto& sampler = proc.textureSampler(i);
- texSamplers[i] = this->emitSampler(sampler.textureType(), sampler.config(), name.c_str(),
- sampler.visibility());
+ GrTextureType textureType = sampler.peekTexture()->texturePriv().textureType();
+ texSamplers[i] = this->emitSampler(textureType, sampler.peekTexture()->config(),
+ name.c_str(), sampler.visibility());
}
GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index e9a612f..783cac7 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -843,11 +843,11 @@
extract_lines_only_verts(tess, verts, vertexStride, args.fColor, idxs,
fHelper.compatibleWithAlphaAsCoverage());
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexed(indexBuffer, tess.numIndices(), firstIndex, 0, tess.numPts() - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
}
@@ -928,38 +928,37 @@
SkSTArray<kPreallocDrawCnt, Draw, true> draws;
create_vertices(segments, fanPt, args.fColor, &draws, verts, idxs);
- GrMesh* meshes = target->allocMeshes(draws.count());
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+
for (int j = 0; j < draws.count(); ++j) {
const Draw& draw = draws[j];
- meshes[j].setPrimitiveType(GrPrimitiveType::kTriangles);
- meshes[j].setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0,
- draw.fVertexCnt - 1, GrPrimitiveRestart::kNo);
- meshes[j].setVertexData(vertexBuffer, firstVertex);
+ mesh.setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0, draw.fVertexCnt - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(quadProcessor.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
firstIndex += draw.fIndexCnt;
firstVertex += draw.fVertexCnt;
}
- target->draw(quadProcessor, pipe.fPipeline, pipe.fFixedDynamicState, meshes,
- draws.count());
}
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAConvexPathOp* that = t->cast<AAConvexPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fPaths[0].fViewMatrix.cheapEqualTo(that->fPaths[0].fViewMatrix)) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fLinesOnly != that->fLinesOnly) {
- return CombineResult::kCannotCombine;
+ return false;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct PathData {
diff --git a/src/gpu/ops/GrAAFillRectOp.cpp b/src/gpu/ops/GrAAFillRectOp.cpp
index 9d66299..592c0b2 100644
--- a/src/gpu/ops/GrAAFillRectOp.cpp
+++ b/src/gpu/ops/GrAAFillRectOp.cpp
@@ -265,9 +265,10 @@
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
sk_sp<const GrBuffer> indexBuffer = get_index_buffer(target->resourceProvider());
- PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
- kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt);
- void* vertices = helper.vertices();
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices =
+ helper.init(target, vertexStride, indexBuffer.get(), kVertsPerAAFillRect,
+ kIndicesPerAAFillRect, fRectCnt);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -291,19 +292,19 @@
info = this->next(info);
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAFillRectOp* that = t->cast<AAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
fRectCnt += that->fRectCnt;
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct RectInfo {
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index 7cff875..05f1fbd 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -835,41 +835,41 @@
typedef SkTArray<int, true> IntArray;
typedef SkTArray<float, true> FloatArray;
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAHairlineOp* that = t->cast<AAHairlineOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->viewMatrix().hasPerspective() != that->viewMatrix().hasPerspective()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// We go to identity if we don't have perspective
if (this->viewMatrix().hasPerspective() &&
!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
// TODO we can actually combine hairlines if they are the same color in a kind of bulk
// method but we haven't implemented this yet
// TODO investigate going to vertex color and coverage?
if (this->coverage() != that->coverage()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->color() != that->color()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
GrColor color() const { return fColor; }
@@ -975,11 +975,11 @@
add_line(&lines[2*i], toSrc, this->coverage(), &verts);
}
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexedPatterned(linesIndexBuffer.get(), kIdxsPerLineSeg, kLineSegNumVertices,
- lineCount, kLineSegsNumInIdxBuffer);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(std::move(lineGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexedPatterned(linesIndexBuffer.get(), kIdxsPerLineSeg, kLineSegNumVertices,
+ lineCount, kLineSegsNumInIdxBuffer);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(lineGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
if (quadCount || conicCount) {
@@ -1030,20 +1030,20 @@
}
if (quadCount > 0) {
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
- quadCount, kQuadsNumInIdxBuffer);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(std::move(quadGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
+ quadCount, kQuadsNumInIdxBuffer);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(quadGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
firstVertex += quadCount * kQuadNumVertices;
}
if (conicCount > 0) {
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
- conicCount, kQuadsNumInIdxBuffer);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(std::move(conicGP), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexedPatterned(quadsIndexBuffer.get(), kIdxsPerQuad, kQuadNumVertices,
+ conicCount, kQuadsNumInIdxBuffer);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(conicGP.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
}
}
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index c40aa71..75662d3 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -210,13 +210,14 @@
}
private:
- void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
+ void draw(Target* target, const GrGeometryProcessor* gp, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState, int vertexCount,
size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
if (vertexCount == 0 || indexCount == 0) {
return;
}
const GrBuffer* vertexBuffer;
+ GrMesh mesh(GrPrimitiveType::kTriangles);
int firstVertex;
void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
&firstVertex);
@@ -234,11 +235,10 @@
return;
}
memcpy(idxs, indices, indexCount * sizeof(uint16_t));
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
+ mesh.setIndexed(indexBuffer, indexCount, firstIndex, 0, vertexCount - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(gp, pipeline, fixedDynamicState, mesh);
}
void onPrepareDraws(Target* target) override {
@@ -279,7 +279,7 @@
if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
// if we added the current instance, we would overflow the indices we can store in a
// uint16_t. Draw what we've got so far and reset.
- this->draw(target, gp, pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
+ this->draw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
vertexStride, vertices, indexCount, indices);
vertexCount = 0;
indexCount = 0;
@@ -311,22 +311,22 @@
indexCount += currentIndices;
}
if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
- this->draw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
+ this->draw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, vertexCount,
vertexStride, vertices, indexCount, indices);
}
sk_free(vertices);
sk_free(indices);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
diff --git a/src/gpu/ops/GrAAStrokeRectOp.cpp b/src/gpu/ops/GrAAStrokeRectOp.cpp
index 0362946..92d1c01 100644
--- a/src/gpu/ops/GrAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrAAStrokeRectOp.cpp
@@ -227,7 +227,7 @@
const SkMatrix& viewMatrix() const { return fViewMatrix; }
bool miterStroke() const { return fMiterStroke; }
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
+ bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
void generateAAStrokeRectGeometry(void* vertices,
size_t offset,
@@ -282,11 +282,11 @@
int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt;
int instanceCount = fRects.count();
- sk_sp<const GrBuffer> indexBuffer =
- GetIndexBuffer(target->resourceProvider(), this->miterStroke());
- PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
- verticesPerInstance, indicesPerInstance, instanceCount);
- void* vertices = helper.vertices();
+ sk_sp<const GrBuffer> indexBuffer = GetIndexBuffer(target->resourceProvider(), this->miterStroke());
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices =
+ helper.init(target, vertexStride, indexBuffer.get(),
+ verticesPerInstance, indicesPerInstance, instanceCount);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -308,7 +308,7 @@
fHelper.compatibleWithAlphaAsCoverage());
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
sk_sp<const GrBuffer> AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider,
@@ -405,27 +405,27 @@
}
}
-GrOp::CombineResult AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
+bool AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
AAStrokeRectOp* that = t->cast<AAStrokeRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
// TODO combine across miterstroke changes
if (this->miterStroke() != that->miterStroke()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
// local coords then we won't be able to combine. TODO: Upload local coords as an attribute.
if (fHelper.usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
static void setup_scale(int* scale, SkScalar inset) {
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index ba39b97..cfd0c45 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -295,16 +295,9 @@
}
SkASSERT(proxies[0]);
- static constexpr int kMaxTextures = GrBitmapTextGeoProc::kMaxTextures;
- GR_STATIC_ASSERT(GrDistanceFieldA8TextGeoProc::kMaxTextures == kMaxTextures);
- GR_STATIC_ASSERT(GrDistanceFieldLCDTextGeoProc::kMaxTextures == kMaxTextures);
-
static const uint32_t kPipelineFlags = 0;
auto pipe = target->makePipeline(kPipelineFlags, std::move(fProcessors),
- target->detachAppliedClip(), kMaxTextures);
- for (unsigned i = 0; i < numActiveProxies; ++i) {
- pipe.fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
- }
+ target->detachAppliedClip());
FlushInfo flushInfo;
flushInfo.fPipeline = pipe.fPipeline;
@@ -407,9 +400,6 @@
if (gp->numTextureSamplers() != (int) numActiveProxies) {
// During preparation the number of atlas pages has increased.
// Update the proxies used in the GP to match.
- for (unsigned i = gp->numTextureSamplers(); i < numActiveProxies; ++i) {
- flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
- }
if (this->usesDistanceFields()) {
if (this->isLCD()) {
reinterpret_cast<GrDistanceFieldLCDTextGeoProc*>(gp)->addNewProxies(
@@ -425,60 +415,62 @@
samplerState);
}
}
+
+ GrMesh mesh(GrPrimitiveType::kTriangles);
int maxGlyphsPerDraw =
static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
- flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
- mesh->setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
- target->draw(flushInfo->fGeometryProcessor, flushInfo->fPipeline, flushInfo->fFixedDynamicState,
- mesh);
+ mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerGlyph, kVerticesPerGlyph,
+ flushInfo->fGlyphsToFlush, maxGlyphsPerDraw);
+ mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
+ target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline,
+ flushInfo->fFixedDynamicState, mesh);
flushInfo->fVertexOffset += kVerticesPerGlyph * flushInfo->fGlyphsToFlush;
flushInfo->fGlyphsToFlush = 0;
}
-GrOp::CombineResult GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
+bool GrAtlasTextOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrAtlasTextOp* that = t->cast<GrAtlasTextOp>();
if (fProcessors != that->fProcessors) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!fCanCombineOnTouchOrOverlap && GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fMaskType != that->fMaskType) {
- return CombineResult::kCannotCombine;
+ return false;
}
const SkMatrix& thisFirstMatrix = fGeoData[0].fViewMatrix;
const SkMatrix& thatFirstMatrix = that->fGeoData[0].fViewMatrix;
if (this->usesLocalCoords() && !thisFirstMatrix.cheapEqualTo(thatFirstMatrix)) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fNeedsGlyphTransform != that->fNeedsGlyphTransform) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fNeedsGlyphTransform &&
(thisFirstMatrix.hasPerspective() != thatFirstMatrix.hasPerspective())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->usesDistanceFields()) {
if (fDFGPFlags != that->fDFGPFlags) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fLuminanceColor != that->fLuminanceColor) {
- return CombineResult::kCannotCombine;
+ return false;
}
} else {
if (kColorBitmapMask_MaskType == fMaskType && this->color() != that->color()) {
- return CombineResult::kCannotCombine;
+ return false;
}
+
}
// Keep the batch vertex buffer size below 32K so we don't have to create a special one
@@ -486,7 +478,7 @@
static const int kVertexSize = sizeof(SkPoint) + sizeof(SkColor) + 2 * sizeof(uint16_t);
static const int kMaxGlyphs = 32768 / (kVerticesPerGlyph * kVertexSize);
if (this->fNumGlyphs + that->fNumGlyphs > kMaxGlyphs) {
- return CombineResult::kCannotCombine;
+ return false;
}
fNumGlyphs += that->numGlyphs();
@@ -516,7 +508,7 @@
fGeoCount = newGeoCount;
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
// TODO trying to figure out why lcd is so whack
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index e6e08dc..14f7e95 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -107,7 +107,7 @@
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
- GrPipeline::FixedDynamicState* fFixedDynamicState;
+ const GrPipeline::FixedDynamicState* fFixedDynamicState;
int fGlyphsToFlush;
int fVertexOffset;
};
@@ -149,7 +149,7 @@
bool usesLocalCoords() const { return fUsesLocalCoords; }
int numGlyphs() const { return fNumGlyphs; }
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override;
sk_sp<GrGeometryProcessor> setupDfProcessor(const sk_sp<GrTextureProxy>* proxies,
unsigned int numActiveProxies) const;
diff --git a/src/gpu/ops/GrClearOp.h b/src/gpu/ops/GrClearOp.h
index e62667d..6e76191 100644
--- a/src/gpu/ops/GrClearOp.h
+++ b/src/gpu/ops/GrClearOp.h
@@ -62,23 +62,23 @@
this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
// This could be much more complicated. Currently we look at cases where the new clear
// contains the old clear, or when the new clear is a subset of the old clear and is the
// same color.
GrClearOp* cb = t->cast<GrClearOp>();
if (fClip.windowRectsState() != cb->fClip.windowRectsState()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (cb->contains(this)) {
fClip = cb->fClip;
this->replaceBounds(*t);
fColor = cb->fColor;
- return CombineResult::kMerged;
+ return true;
} else if (cb->fColor == fColor && this->contains(cb)) {
- return CombineResult::kMerged;
+ return true;
}
- return CombineResult::kCannotCombine;
+ return false;
}
bool contains(const GrClearOp* that) const {
diff --git a/src/gpu/ops/GrClearStencilClipOp.h b/src/gpu/ops/GrClearStencilClipOp.h
index 5861fca..3e7ad50 100644
--- a/src/gpu/ops/GrClearStencilClipOp.h
+++ b/src/gpu/ops/GrClearStencilClipOp.h
@@ -52,6 +52,8 @@
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
}
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
+
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;
diff --git a/src/gpu/ops/GrCopySurfaceOp.h b/src/gpu/ops/GrCopySurfaceOp.h
index b93cbb7..bc0e33f 100644
--- a/src/gpu/ops/GrCopySurfaceOp.h
+++ b/src/gpu/ops/GrCopySurfaceOp.h
@@ -53,6 +53,8 @@
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
}
+ bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
+
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;
diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp
index 075df70..43acc5c 100644
--- a/src/gpu/ops/GrDashOp.cpp
+++ b/src/gpu/ops/GrDashOp.cpp
@@ -625,6 +625,7 @@
return;
}
+ QuadHelper helper;
size_t vertexStride;
if (fullDash) {
vertexStride =
@@ -633,8 +634,7 @@
vertexStride = sizeof(SkPoint);
}
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
- QuadHelper helper(target, vertexStride, totalRectCount);
- void* vertices = helper.vertices();
+ void* vertices = helper.init(target, vertexStride, totalRectCount);
if (!vertices) {
return;
}
@@ -696,43 +696,43 @@
}
auto pipe = target->makePipeline(pipelineFlags, std::move(fProcessorSet),
target->detachAppliedClip());
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DashOp* that = t->cast<DashOp>();
if (fProcessorSet != that->fProcessorSet) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fDisallowCombineOnTouchOrOverlap &&
GrRectsTouchOrOverlap(this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->aaMode() != that->aaMode()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->fullDash() != that->fullDash()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->cap() != that->cap()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// TODO vertex color
if (this->color() != that->color()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fUsesLocalCoords && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fLines.push_back_n(that->fLines.count(), that->fLines.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
GrColor color() const { return fColor; }
diff --git a/src/gpu/ops/GrDebugMarkerOp.h b/src/gpu/ops/GrDebugMarkerOp.h
index 96c5477..061f676 100644
--- a/src/gpu/ops/GrDebugMarkerOp.h
+++ b/src/gpu/ops/GrDebugMarkerOp.h
@@ -39,6 +39,8 @@
this->makeFullScreen(proxy);
}
+ bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
+
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 4e038df..07e40f0 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -65,12 +65,12 @@
class PathGeoBuilder {
public:
PathGeoBuilder(GrPrimitiveType primitiveType, GrMeshDrawOp::Target* target,
- sk_sp<const GrGeometryProcessor> geometryProcessor, const GrPipeline* pipeline,
+ GrGeometryProcessor* geometryProcessor, const GrPipeline* pipeline,
const GrPipeline::FixedDynamicState* fixedDynamicState)
- : fPrimitiveType(primitiveType)
+ : fMesh(primitiveType)
, fTarget(target)
, fVertexStride(sizeof(SkPoint))
- , fGeometryProcessor(std::move(geometryProcessor))
+ , fGeometryProcessor(geometryProcessor)
, fPipeline(pipeline)
, fFixedDynamicState(fixedDynamicState)
, fIndexBuffer(nullptr)
@@ -200,15 +200,15 @@
* TODO: Cache some of these for better performance, rather than re-computing?
*/
bool isIndexed() const {
- return GrPrimitiveType::kLines == fPrimitiveType ||
- GrPrimitiveType::kTriangles == fPrimitiveType;
+ return GrPrimitiveType::kLines == fMesh.primitiveType() ||
+ GrPrimitiveType::kTriangles == fMesh.primitiveType();
}
bool isHairline() const {
- return GrPrimitiveType::kLines == fPrimitiveType ||
- GrPrimitiveType::kLineStrip == fPrimitiveType;
+ return GrPrimitiveType::kLines == fMesh.primitiveType() ||
+ GrPrimitiveType::kLineStrip == fMesh.primitiveType();
}
int indexScale() const {
- switch (fPrimitiveType) {
+ switch (fMesh.primitiveType()) {
case GrPrimitiveType::kLines:
return 2;
case GrPrimitiveType::kTriangles:
@@ -271,15 +271,14 @@
SkASSERT(indexCount <= fIndicesInChunk);
if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
- GrMesh* mesh = fTarget->allocMesh(fPrimitiveType);
if (!this->isIndexed()) {
- mesh->setNonIndexedNonInstanced(vertexCount);
+ fMesh.setNonIndexedNonInstanced(vertexCount);
} else {
- mesh->setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1,
+ fMesh.setIndexed(fIndexBuffer, indexCount, fFirstIndex, 0, vertexCount - 1,
GrPrimitiveRestart::kNo);
}
- mesh->setVertexData(fVertexBuffer, fFirstVertex);
- fTarget->draw(fGeometryProcessor, fPipeline, fFixedDynamicState, mesh);
+ fMesh.setVertexData(fVertexBuffer, fFirstVertex);
+ fTarget->draw(fGeometryProcessor, fPipeline, fFixedDynamicState, fMesh);
}
fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
@@ -312,10 +311,10 @@
}
}
- GrPrimitiveType fPrimitiveType;
+ GrMesh fMesh;
GrMeshDrawOp::Target* fTarget;
size_t fVertexStride;
- sk_sp<const GrGeometryProcessor> fGeometryProcessor;
+ GrGeometryProcessor* fGeometryProcessor;
const GrPipeline* fPipeline;
const GrPipeline::FixedDynamicState* fFixedDynamicState;
@@ -429,7 +428,7 @@
primitiveType = GrPrimitiveType::kTriangles;
}
auto pipe = fHelper.makePipeline(target);
- PathGeoBuilder pathGeoBuilder(primitiveType, target, std::move(gp), pipe.fPipeline,
+ PathGeoBuilder pathGeoBuilder(primitiveType, target, gp.get(), pipe.fPipeline,
pipe.fFixedDynamicState);
// fill buffers
@@ -439,31 +438,31 @@
}
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DefaultPathOp* that = t->cast<DefaultPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->color() != that->color()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->coverage() != that->coverage()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->isHairline() != that->isHairline()) {
- return CombineResult::kCannotCombine;
+ return false;
}
fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
GrColor color() const { return fColor; }
diff --git a/src/gpu/ops/GrDrawAtlasOp.cpp b/src/gpu/ops/GrDrawAtlasOp.cpp
index 107b0be..d280ad9 100644
--- a/src/gpu/ops/GrDrawAtlasOp.cpp
+++ b/src/gpu/ops/GrDrawAtlasOp.cpp
@@ -130,9 +130,9 @@
sizeof(SkPoint) + sizeof(SkPoint) + (this->hasColors() ? sizeof(GrColor) : 0);
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
+ QuadHelper helper;
int numQuads = this->quadCount();
- QuadHelper helper(target, vertexStride, numQuads);
- void* verts = helper.vertices();
+ void* verts = helper.init(target, vertexStride, numQuads);
if (!verts) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -147,34 +147,34 @@
vertPtr += allocSize;
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
-GrOp::CombineResult GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
+bool GrDrawAtlasOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrDrawAtlasOp* that = t->cast<GrDrawAtlasOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
// We currently use a uniform viewmatrix for this op.
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->hasColors() != that->hasColors()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!this->hasColors() && this->color() != that->color()) {
- return CombineResult::kCannotCombine;
+ return false;
}
fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
fQuadCount += that->quadCount();
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
GrDrawOp::FixedFunctionFlags GrDrawAtlasOp::fixedFunctionFlags() const {
diff --git a/src/gpu/ops/GrDrawAtlasOp.h b/src/gpu/ops/GrDrawAtlasOp.h
index d15bd3c..4e894ce 100644
--- a/src/gpu/ops/GrDrawAtlasOp.h
+++ b/src/gpu/ops/GrDrawAtlasOp.h
@@ -56,7 +56,7 @@
bool hasColors() const { return fHasColors; }
int quadCount() const { return fQuadCount; }
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
+ bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
struct Geometry {
GrColor fColor;
diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h
index 3016fd7..63986d7 100644
--- a/src/gpu/ops/GrDrawPathOp.h
+++ b/src/gpu/ops/GrDrawPathOp.h
@@ -93,6 +93,8 @@
this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
+
void onExecute(GrOpFlushState* state) override;
GrPendingIOResource<const GrPath, kRead_GrIOType> fPath;
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index dd91452..d227920 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -261,7 +261,7 @@
indices);
// Draw the vertices.
- this->drawVertices(target, std::move(gp), vertexBuffer, firstVertex, indexBuffer, firstIndex);
+ this->drawVertices(target, gp.get(), vertexBuffer, firstVertex, indexBuffer, firstIndex);
}
void GrDrawVerticesOp::drawNonVolatile(Target* target) {
@@ -298,7 +298,7 @@
// Draw using the cached buffers if possible.
if (vertexBuffer && (!this->isIndexed() || indexBuffer)) {
- this->drawVertices(target, std::move(gp), vertexBuffer.get(), 0, indexBuffer.get(), 0);
+ this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
return;
}
@@ -353,7 +353,7 @@
rp->assignUniqueKeyToResource(indexKey, indexBuffer.get());
// Draw the vertices.
- this->drawVertices(target, std::move(gp), vertexBuffer.get(), 0, indexBuffer.get(), 0);
+ this->drawVertices(target, gp.get(), vertexBuffer.get(), 0, indexBuffer.get(), 0);
}
void GrDrawVerticesOp::fillBuffers(bool hasColorAttribute,
@@ -465,58 +465,59 @@
}
void GrDrawVerticesOp::drawVertices(Target* target,
- sk_sp<const GrGeometryProcessor> gp,
+ GrGeometryProcessor* gp,
const GrBuffer* vertexBuffer,
int firstVertex,
const GrBuffer* indexBuffer,
int firstIndex) {
- GrMesh* mesh = target->allocMesh(this->primitiveType());
+ GrMesh mesh(this->primitiveType());
if (this->isIndexed()) {
- mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertexCount - 1,
- GrPrimitiveRestart::kNo);
+ mesh.setIndexed(indexBuffer, fIndexCount,
+ firstIndex, 0, fVertexCount - 1,
+ GrPrimitiveRestart::kNo);
} else {
- mesh->setNonIndexedNonInstanced(fVertexCount);
+ mesh.setNonIndexedNonInstanced(fVertexCount);
}
- mesh->setVertexData(vertexBuffer, firstVertex);
+ mesh.setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
-GrOp::CombineResult GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
+bool GrDrawVerticesOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
GrDrawVerticesOp* that = t->cast<GrDrawVerticesOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
// Meshes with bones cannot be combined because different meshes use different bones, so to
// combine them, the matrices would have to be combined, and the bone indices on each vertex
// would change, thus making the vertices uncacheable.
if (this->hasBones() || that->hasBones()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// Non-volatile meshes cannot batch, because if a non-volatile mesh batches with another mesh,
// then on the next frame, if that non-volatile mesh is drawn, it will draw the other mesh
// that was saved in its vertex buffer, which is not necessarily there anymore.
if (!this->fMeshes[0].fVertices->isVolatile() || !that->fMeshes[0].fVertices->isVolatile()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!this->combinablePrimitive() || this->primitiveType() != that->primitiveType()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fMeshes[0].fVertices->hasIndices() != that->fMeshes[0].fVertices->hasIndices()) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fColorArrayType != that->fColorArrayType) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fVertexCount + that->fVertexCount > SkTo<int>(UINT16_MAX)) {
- return CombineResult::kCannotCombine;
+ return false;
}
// NOTE: For SkColor vertex colors, the source color space is always sRGB, and the destination
@@ -541,7 +542,7 @@
fIndexCount += that->fIndexCount;
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h
index 07227e0..7695dd9 100644
--- a/src/gpu/ops/GrDrawVerticesOp.h
+++ b/src/gpu/ops/GrDrawVerticesOp.h
@@ -80,7 +80,7 @@
uint16_t* indices) const;
void drawVertices(Target*,
- sk_sp<const GrGeometryProcessor>,
+ GrGeometryProcessor*,
const GrBuffer* vertexBuffer,
int firstVertex,
const GrBuffer* indexBuffer,
@@ -98,7 +98,7 @@
GrPrimitiveType::kPoints == fPrimitiveType;
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
+ bool onCombineIfPossible(GrOp* t, const GrCaps&) override;
struct Mesh {
GrColor fColor; // Used if this->hasPerVertexColors() is false.
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index 4832ee7..00dbef5 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -32,10 +32,10 @@
GrColor fColor;
};
- static sk_sp<GrGeometryProcessor> Make(const GrTextureProxy* proxy,
+ static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxy,
sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter) {
- return sk_sp<GrGeometryProcessor>(new LatticeGP(proxy, std::move(csxf), filter));
+ return sk_sp<GrGeometryProcessor>(new LatticeGP(std::move(proxy), std::move(csxf), filter));
}
const char* name() const override { return "LatticeGP"; }
@@ -92,10 +92,10 @@
}
private:
- LatticeGP(const GrTextureProxy* proxy, sk_sp<GrColorSpaceXform> csxf,
+ LatticeGP(sk_sp<GrTextureProxy> proxy, sk_sp<GrColorSpaceXform> csxf,
GrSamplerState::Filter filter)
: INHERITED(kLatticeGP_ClassID), fColorSpaceXform(std::move(csxf)) {
- fSampler.reset(proxy->textureType(), proxy->config(), filter);
+ fSampler.reset(std::move(proxy), filter);
this->setTextureSamplerCnt(1);
this->setVertexAttributeCnt(4);
}
@@ -202,7 +202,7 @@
private:
void onPrepareDraws(Target* target) override {
- auto gp = LatticeGP::Make(fProxy.get(), fColorSpaceXform, fFilter);
+ auto gp = LatticeGP::Make(fProxy, fColorSpaceXform, fFilter);
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
@@ -223,9 +223,9 @@
}
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStide, indexBuffer.get(),
- kVertsPerRect, kIndicesPerRect, numRects);
- void* vertices = helper.vertices();
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices = helper.init(target, kVertexStide, indexBuffer.get(), kVertsPerRect,
+ kIndicesPerRect, numRects);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -281,29 +281,28 @@
kVertsPerRect * patch.fIter->numRectsToDraw());
}
}
- auto pipe = fHelper.makePipeline(target, 1);
- pipe.fFixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy.get();
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ auto pipe = fHelper.makePipeline(target);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAALatticeOp* that = t->cast<NonAALatticeOp>();
if (fProxy != that->fProxy) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fFilter != that->fFilter) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fPatches.move_back_n(that->fPatches.count(), that->fPatches.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct Patch {
diff --git a/src/gpu/ops/GrMeshDrawOp.cpp b/src/gpu/ops/GrMeshDrawOp.cpp
index 620ea47..0bac5ef 100644
--- a/src/gpu/ops/GrMeshDrawOp.cpp
+++ b/src/gpu/ops/GrMeshDrawOp.cpp
@@ -14,68 +14,56 @@
void GrMeshDrawOp::onPrepare(GrOpFlushState* state) { this->onPrepareDraws(state); }
+void* GrMeshDrawOp::PatternHelper::init(Target* target, size_t vertexStride,
+ const GrBuffer* indexBuffer, int verticesPerRepetition,
+ int indicesPerRepetition, int repeatCount) {
+ SkASSERT(target);
+ if (!indexBuffer) {
+ return nullptr;
+ }
+ const GrBuffer* vertexBuffer;
+ int firstVertex;
+ int vertexCount = verticesPerRepetition * repeatCount;
+ void* vertices =
+ target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex);
+ if (!vertices) {
+ SkDebugf("Vertices could not be allocated for instanced rendering.");
+ return nullptr;
+ }
+ SkASSERT(vertexBuffer);
+ size_t ibSize = indexBuffer->gpuMemorySize();
+ int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition));
+
+ fMesh.setIndexedPatterned(indexBuffer, indicesPerRepetition, verticesPerRepetition,
+ repeatCount, maxRepetitions);
+ fMesh.setVertexData(vertexBuffer, firstVertex);
+ return vertices;
+}
+
+void GrMeshDrawOp::PatternHelper::recordDraw(
+ Target* target, const GrGeometryProcessor* gp, const GrPipeline* pipeline,
+ const GrPipeline::FixedDynamicState* fixedDynamicState) {
+ target->draw(gp, pipeline, fixedDynamicState, fMesh);
+}
+
+void* GrMeshDrawOp::QuadHelper::init(Target* target, size_t vertexStride, int quadsToDraw) {
+ sk_sp<const GrBuffer> quadIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
+ if (!quadIndexBuffer) {
+ SkDebugf("Could not get quad index buffer.");
+ return nullptr;
+ }
+ return this->INHERITED::init(target, vertexStride, quadIndexBuffer.get(), kVerticesPerQuad,
+ kIndicesPerQuad, quadsToDraw);
+}
+
void GrMeshDrawOp::onExecute(GrOpFlushState* state) {
state->executeDrawsAndUploadsForMeshDrawOp(this->uniqueID(), this->bounds());
}
//////////////////////////////////////////////////////////////////////////////
-GrMeshDrawOp::PatternHelper::PatternHelper(Target* target, GrPrimitiveType primitiveType,
- size_t vertexStride, const GrBuffer* indexBuffer,
- int verticesPerRepetition, int indicesPerRepetition,
- int repeatCount) {
- this->init(target, primitiveType, vertexStride, indexBuffer, verticesPerRepetition,
- indicesPerRepetition, repeatCount);
-}
-
-void GrMeshDrawOp::PatternHelper::init(Target* target, GrPrimitiveType primitiveType,
- size_t vertexStride, const GrBuffer* indexBuffer,
- int verticesPerRepetition, int indicesPerRepetition,
- int repeatCount) {
- SkASSERT(target);
- if (!indexBuffer) {
- return;
- }
- const GrBuffer* vertexBuffer;
- int firstVertex;
- int vertexCount = verticesPerRepetition * repeatCount;
- fVertices = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex);
- if (!fVertices) {
- SkDebugf("Vertices could not be allocated for patterned rendering.");
- return;
- }
- SkASSERT(vertexBuffer);
- size_t ibSize = indexBuffer->gpuMemorySize();
- int maxRepetitions = static_cast<int>(ibSize / (sizeof(uint16_t) * indicesPerRepetition));
- fMesh = target->allocMesh(primitiveType);
- fMesh->setIndexedPatterned(indexBuffer, indicesPerRepetition, verticesPerRepetition,
- repeatCount, maxRepetitions);
- fMesh->setVertexData(vertexBuffer, firstVertex);
-}
-
-void GrMeshDrawOp::PatternHelper::recordDraw(
- Target* target, sk_sp<const GrGeometryProcessor> gp, const GrPipeline* pipeline,
- const GrPipeline::FixedDynamicState* fixedDynamicState) const {
- target->draw(std::move(gp), pipeline, fixedDynamicState, fMesh);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-GrMeshDrawOp::QuadHelper::QuadHelper(Target* target, size_t vertexStride, int quadsToDraw) {
- sk_sp<const GrBuffer> quadIndexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- if (!quadIndexBuffer) {
- SkDebugf("Could not get quad index buffer.");
- return;
- }
- this->init(target, GrPrimitiveType::kTriangles, vertexStride, quadIndexBuffer.get(),
- kVerticesPerQuad, kIndicesPerQuad, quadsToDraw);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
GrMeshDrawOp::Target::PipelineAndFixedDynamicState GrMeshDrawOp::Target::makePipeline(
- uint32_t pipelineFlags, GrProcessorSet&& processorSet, GrAppliedClip&& clip,
- int numPrimProcTextures) {
+ uint32_t pipelineFlags, GrProcessorSet&& processorSet, GrAppliedClip&& clip) {
GrPipeline::InitArgs pipelineArgs;
pipelineArgs.fFlags = pipelineFlags;
pipelineArgs.fProxy = this->proxy();
@@ -83,12 +71,8 @@
pipelineArgs.fCaps = &this->caps();
pipelineArgs.fResourceProvider = this->resourceProvider();
GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
- if (clip.scissorState().enabled() || numPrimProcTextures) {
+ if (clip.scissorState().enabled()) {
fixedDynamicState = this->allocFixedDynamicState(clip.scissorState().rect());
- if (numPrimProcTextures) {
- fixedDynamicState->fPrimitiveProcessorTextures =
- this->allocPrimitiveProcessorTextureArray(numPrimProcTextures);
- }
}
return {this->allocPipeline(pipelineArgs, std::move(processorSet), std::move(clip)),
fixedDynamicState};
diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h
index a6e7da5..e90de47 100644
--- a/src/gpu/ops/GrMeshDrawOp.h
+++ b/src/gpu/ops/GrMeshDrawOp.h
@@ -12,6 +12,7 @@
#include "GrDrawOp.h"
#include "GrGeometryProcessor.h"
#include "GrMesh.h"
+#include "GrPendingProgramElement.h"
class GrAtlasManager;
class GrCaps;
@@ -33,23 +34,18 @@
space for the vertices and flushes the draws to the GrMeshDrawOp::Target. */
class PatternHelper {
public:
- PatternHelper(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
- int verticesPerRepetition, int indicesPerRepetition, int repeatCount);
+ PatternHelper(GrPrimitiveType primitiveType) : fMesh(primitiveType) {}
+ /** Returns the allocated storage for the vertices. The caller should populate the vertices
+ before calling recordDraws(). */
+ void* init(Target*, size_t vertexStride, const GrBuffer*, int verticesPerRepetition,
+ int indicesPerRepetition, int repeatCount);
- /** Called to issue draws to the GrMeshDrawOp::Target.*/
- void recordDraw(Target*, sk_sp<const GrGeometryProcessor>, const GrPipeline*,
- const GrPipeline::FixedDynamicState*) const;
-
- void* vertices() const { return fVertices; }
-
- protected:
- PatternHelper() = default;
- void init(Target*, GrPrimitiveType, size_t vertexStride, const GrBuffer*,
- int verticesPerRepetition, int indicesPerRepetition, int repeatCount);
+ /** Call after init() to issue draws to the GrMeshDrawOp::Target.*/
+ void recordDraw(Target*, const GrGeometryProcessor*, const GrPipeline*,
+ const GrPipeline::FixedDynamicState*);
private:
- void* fVertices = nullptr;
- GrMesh* fMesh = nullptr;
+ GrMesh fMesh;
};
static const int kVerticesPerQuad = 4;
@@ -58,11 +54,13 @@
/** A specialization of InstanceHelper for quad rendering. */
class QuadHelper : private PatternHelper {
public:
- QuadHelper() = delete;
- QuadHelper(Target* target, size_t vertexStride, int quadsToDraw);
+ QuadHelper() : INHERITED(GrPrimitiveType::kTriangles) {}
+ /** Finds the cached quad index buffer and reserves vertex space. Returns nullptr on failure
+ and on success a pointer to the vertex data that the caller should populate before
+ calling recordDraws(). */
+ void* init(Target*, size_t vertexStride, int quadsToDraw);
using PatternHelper::recordDraw;
- using PatternHelper::vertices;
private:
typedef PatternHelper INHERITED;
@@ -80,19 +78,8 @@
virtual ~Target() {}
/** Adds a draw of a mesh. */
- virtual void draw(sk_sp<const GrGeometryProcessor>,
- const GrPipeline*,
- const GrPipeline::FixedDynamicState*,
- const GrMesh[],
- int meshCount) = 0;
-
- /** Helper for drawing a single GrMesh. */
- void draw(sk_sp<const GrGeometryProcessor> gp,
- const GrPipeline* pipeline,
- const GrPipeline::FixedDynamicState* fixedDynamicState,
- const GrMesh* mesh) {
- this->draw(std::move(gp), pipeline, fixedDynamicState, mesh, 1);
- }
+ virtual void draw(const GrGeometryProcessor*, const GrPipeline*,
+ const GrPipeline::FixedDynamicState*, const GrMesh&) = 0;
/**
* Makes space for vertex data. The returned pointer is the location where vertex data
@@ -145,25 +132,10 @@
return this->pipelineArena()->make<GrPipeline>(std::forward<Args>(args)...);
}
- GrMesh* allocMesh(GrPrimitiveType primitiveType) {
- return this->pipelineArena()->make<GrMesh>(primitiveType);
- }
-
- GrMesh* allocMeshes(int n) { return this->pipelineArena()->makeArray<GrMesh>(n); }
-
- GrPipeline::FixedDynamicState* allocFixedDynamicState(const SkIRect& rect,
- int numPrimitiveProcessorTextures = 0) {
- auto result = this->pipelineArena()->make<GrPipeline::FixedDynamicState>(rect);
- if (numPrimitiveProcessorTextures) {
- result->fPrimitiveProcessorTextures =
- this->allocPrimitiveProcessorTextureArray(numPrimitiveProcessorTextures);
- }
- return result;
- }
-
- GrTextureProxy** allocPrimitiveProcessorTextureArray(int n) {
- SkASSERT(n > 0);
- return this->pipelineArena()->makeArrayDefault<GrTextureProxy*>(n);
+ template <typename... Args>
+ GrPipeline::FixedDynamicState* allocFixedDynamicState(Args&... args) {
+ return this->pipelineArena()->make<GrPipeline::FixedDynamicState>(
+ std::forward<Args>(args)...);
}
// Once we have C++17 structured bindings make this just be a tuple because then we can do:
@@ -172,7 +144,7 @@
// std::tie(flushInfo.fPipeline, flushInfo.fFixedState) = target->makePipeline(...);
struct PipelineAndFixedDynamicState {
const GrPipeline* fPipeline;
- GrPipeline::FixedDynamicState* fFixedDynamicState;
+ const GrPipeline::FixedDynamicState* fFixedDynamicState;
};
/**
@@ -180,8 +152,7 @@
* GrAppliedClip and uses a fixed dynamic state.
*/
PipelineAndFixedDynamicState makePipeline(uint32_t pipelineFlags, GrProcessorSet&&,
- GrAppliedClip&&,
- int numPrimitiveProcessorTextures = 0);
+ GrAppliedClip&&);
virtual GrRenderTargetProxy* proxy() const = 0;
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index fd8a9b3..c554232 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -192,9 +192,9 @@
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
- kVertsPerRect, kIndicesPerRect, rectCount);
- void* vertices = helper.vertices();
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices = helper.init(target, kVertexStride, indexBuffer.get(), kVertsPerRect,
+ kIndicesPerRect, rectCount);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -207,17 +207,17 @@
fRects[i].fRect, &fRects[i].fLocalQuad);
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct RectInfo {
@@ -325,9 +325,9 @@
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
- kVertsPerRect, kIndicesPerRect, rectCount);
- void* vertices = helper.vertices();
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices = helper.init(target, vertexStride, indexBuffer.get(), kVertsPerRect,
+ kIndicesPerRect, rectCount);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -345,29 +345,29 @@
}
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
// We could combine across perspective vm changes if we really wanted to.
if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHasLocalRect != that->fHasLocalRect) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct RectInfo {
diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.cpp b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
index 500b2eb..21636b2 100644
--- a/src/gpu/ops/GrNonAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
@@ -188,14 +188,18 @@
vertex[4].set(fRect.fLeft, fRect.fTop);
}
- GrMesh* mesh = target->allocMesh(primType);
- mesh->setNonIndexedNonInstanced(vertexCount);
- mesh->setVertexData(vertexBuffer, firstVertex);
+ GrMesh mesh(primType);
+ mesh.setNonIndexedNonInstanced(vertexCount);
+ mesh.setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
- // TODO: override onCombineIfPossible
+ bool onCombineIfPossible(GrOp* t, const GrCaps&) override {
+ // NonAA stroke rects cannot combine right now
+ // TODO make these combinable.
+ return false;
+ }
Helper fHelper;
GrColor fColor;
diff --git a/src/gpu/ops/GrOp.h b/src/gpu/ops/GrOp.h
index 57e028e..5c776fc 100644
--- a/src/gpu/ops/GrOp.h
+++ b/src/gpu/ops/GrOp.h
@@ -75,21 +75,9 @@
// This default implementation assumes the op has no proxies
}
- enum class CombineResult {
- /**
- * The op that combineIfPossible was called on now represents its own work plus that of
- * the passed op. The passed op should be destroyed without being flushed.
- */
- kMerged,
- /**
- * The ops cannot be combined.
- */
- kCannotCombine
- };
-
- CombineResult combineIfPossible(GrOp* that, const GrCaps& caps) {
+ bool combineIfPossible(GrOp* that, const GrCaps& caps) {
if (this->classID() != that->classID()) {
- return CombineResult::kCannotCombine;
+ return false;
}
return this->onCombineIfPossible(that, caps);
@@ -223,9 +211,7 @@
static uint32_t GenOpClassID() { return GenID(&gCurrOpClassID); }
private:
- virtual CombineResult onCombineIfPossible(GrOp*, const GrCaps&) {
- return CombineResult::kCannotCombine;
- }
+ virtual bool onCombineIfPossible(GrOp*, const GrCaps& caps) = 0;
virtual void onPrepare(GrOpFlushState*) = 0;
virtual void onExecute(GrOpFlushState*) = 0;
diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp
index c0158ba..54bb37c 100644
--- a/src/gpu/ops/GrOvalOpFactory.cpp
+++ b/src/gpu/ops/GrOvalOpFactory.cpp
@@ -1470,29 +1470,29 @@
vertices += circle_type_to_vert_count(circle.fStroked) * vertexStride;
}
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CircleOp* that = t->cast<CircleOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
- return CombineResult::kCannotCombine;
+ return false;
}
// Because we've set up the ops that don't use the planes with noop values
@@ -1507,7 +1507,7 @@
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
fAllFill = fAllFill && that->fAllFill;
- return CombineResult::kMerged;
+ return true;
}
struct Circle {
@@ -1786,36 +1786,36 @@
vertices += circle_type_to_vert_count(true) * kVertexStride;
}
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
ButtCapDashedCircleOp* that = t->cast<ButtCapDashedCircleOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
- return CombineResult::kCannotCombine;
+ return false;
}
fCircles.push_back_n(that->fCircles.count(), that->fCircles.begin());
this->joinBounds(*that);
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
- return CombineResult::kMerged;
+ return true;
}
struct Circle {
@@ -1984,9 +1984,10 @@
// Setup geometry processor
sk_sp<GrGeometryProcessor> gp(new EllipseGeometryProcessor(fStroked, localMatrix));
+ QuadHelper helper;
SkASSERT(sizeof(EllipseVertex) == gp->debugOnly_vertexStride());
- QuadHelper helper(target, sizeof(EllipseVertex), fEllipses.count());
- EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(helper.vertices());
+ EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
+ helper.init(target, sizeof(EllipseVertex), fEllipses.count()));
if (!verts) {
return;
}
@@ -2039,28 +2040,28 @@
verts += kVerticesPerQuad;
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
EllipseOp* that = t->cast<EllipseOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fStroked != that->fStroked) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
- return CombineResult::kCannotCombine;
+ return false;
}
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct Ellipse {
@@ -2218,8 +2219,9 @@
new DIEllipseGeometryProcessor(this->viewMatrix(), this->style()));
SkASSERT(sizeof(DIEllipseVertex) == gp->debugOnly_vertexStride());
- QuadHelper helper(target, sizeof(DIEllipseVertex), fEllipses.count());
- DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(helper.vertices());
+ QuadHelper helper;
+ DIEllipseVertex* verts = reinterpret_cast<DIEllipseVertex*>(
+ helper.init(target, sizeof(DIEllipseVertex), fEllipses.count()));
if (!verts) {
return;
}
@@ -2272,27 +2274,27 @@
verts += kVerticesPerQuad;
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
DIEllipseOp* that = t->cast<DIEllipseOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->style() != that->style()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// TODO rewrite to allow positioning on CPU
if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
- return CombineResult::kCannotCombine;
+ return false;
}
fEllipses.push_back_n(that->fEllipses.count(), that->fEllipses.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
const SkMatrix& viewMatrix() const { return fEllipses[0].fViewMatrix; }
@@ -2723,29 +2725,29 @@
currStartVertex += rrect_type_to_vert_count(rrect.fType);
}
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
CircularRRectOp* that = t->cast<CircularRRectOp>();
// can only represent 65535 unique vertices with 16-bit indices
if (fVertCount + that->fVertCount > 65536) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
@@ -2753,7 +2755,7 @@
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
fAllFill = fAllFill && that->fAllFill;
- return CombineResult::kMerged;
+ return true;
}
struct RRect {
@@ -2925,10 +2927,10 @@
sk_sp<const GrBuffer> indexBuffer = get_rrect_index_buffer(
fStroked ? kStroke_RRectType : kFill_RRectType, target->resourceProvider());
- PatternHelper helper(target, GrPrimitiveType::kTriangles, sizeof(EllipseVertex),
- indexBuffer.get(), kVertsPerStandardRRect, indicesPerInstance,
- fRRects.count());
- EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(helper.vertices());
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(
+ helper.init(target, sizeof(EllipseVertex), indexBuffer.get(),
+ kVertsPerStandardRRect, indicesPerInstance, fRRects.count()));
if (!verts || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -2995,28 +2997,28 @@
}
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
EllipticalRRectOp* that = t->cast<EllipticalRRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fStroked != that->fStroked) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fHelper.usesLocalCoords() &&
!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsingLocalCoords)) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRRects.push_back_n(that->fRRects.count(), that->fRRects.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct RRect {
diff --git a/src/gpu/ops/GrRegionOp.cpp b/src/gpu/ops/GrRegionOp.cpp
index b876295..d0c24e6 100644
--- a/src/gpu/ops/GrRegionOp.cpp
+++ b/src/gpu/ops/GrRegionOp.cpp
@@ -129,9 +129,9 @@
return;
}
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
- PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
- kVertsPerInstance, kIndicesPerInstance, numRects);
- void* vertices = helper.vertices();
+ PatternHelper helper(GrPrimitiveType::kTriangles);
+ void* vertices = helper.init(target, kVertexStride, indexBuffer.get(), kVertsPerInstance,
+ kIndicesPerInstance, numRects);
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
@@ -144,22 +144,22 @@
verts += numRectsInRegion * kVertsPerInstance * kVertexStride;
}
auto pipe = fHelper.makePipeline(target);
- helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
+ helper.recordDraw(target, gp.get(), pipe.fPipeline, pipe.fFixedDynamicState);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
RegionOp* that = t->cast<RegionOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (fViewMatrix != that->fViewMatrix) {
- return CombineResult::kCannotCombine;
+ return false;
}
fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
struct RegionInfo {
diff --git a/src/gpu/ops/GrSemaphoreOp.h b/src/gpu/ops/GrSemaphoreOp.h
index 53c76c3..234c76c 100644
--- a/src/gpu/ops/GrSemaphoreOp.h
+++ b/src/gpu/ops/GrSemaphoreOp.h
@@ -34,6 +34,7 @@
sk_sp<GrSemaphore> fSemaphore;
private:
+ bool onCombineIfPossible(GrOp* that, const GrCaps& caps) override { return false; }
void onPrepare(GrOpFlushState*) override {}
typedef GrOp INHERITED;
diff --git a/src/gpu/ops/GrShadowRRectOp.cpp b/src/gpu/ops/GrShadowRRectOp.cpp
index 69489a2..09a2442 100644
--- a/src/gpu/ops/GrShadowRRectOp.cpp
+++ b/src/gpu/ops/GrShadowRRectOp.cpp
@@ -627,20 +627,20 @@
auto pipe = target->makePipeline(kPipelineFlags, GrProcessorSet::MakeEmptySet(),
target->detachAppliedClip());
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
- mesh->setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
- GrPrimitiveRestart::kNo);
- mesh->setVertexData(vertexBuffer, firstVertex);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
+ mesh.setIndexed(indexBuffer, fIndexCount, firstIndex, 0, fVertCount - 1,
+ GrPrimitiveRestart::kNo);
+ mesh.setVertexData(vertexBuffer, firstVertex);
+ target->draw(gp.get(), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
ShadowCircularRRectOp* that = t->cast<ShadowCircularRRectOp>();
fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin());
this->joinBounds(*that);
fVertCount += that->fVertCount;
fIndexCount += that->fIndexCount;
- return CombineResult::kMerged;
+ return true;
}
SkSTArray<1, Geometry, true> fGeoData;
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index f1692e6..7ed74c3 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -135,8 +135,7 @@
}
auto GrSimpleMeshDrawOpHelper::internalMakePipeline(GrMeshDrawOp::Target* target,
- const GrPipeline::InitArgs& args,
- int numPrimitiveProcessorProxies)
+ const GrPipeline::InitArgs& args)
-> PipelineAndFixedDynamicState {
// A caller really should only call this once as the processor set and applied clip get
// moved into the GrPipeline.
@@ -144,12 +143,8 @@
SkDEBUGCODE(fMadePipeline = true);
auto clip = target->detachAppliedClip();
GrPipeline::FixedDynamicState* fixedDynamicState = nullptr;
- if (clip.scissorState().enabled() || numPrimitiveProcessorProxies) {
+ if (clip.scissorState().enabled()) {
fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect());
- if (numPrimitiveProcessorProxies) {
- fixedDynamicState->fPrimitiveProcessorTextures =
- target->allocPrimitiveProcessorTextureArray(numPrimitiveProcessorProxies);
- }
}
if (fProcessors) {
return {target->allocPipeline(args, std::move(*fProcessors), std::move(clip)),
@@ -181,12 +176,11 @@
fStencilSettings == that.fStencilSettings;
}
-auto GrSimpleMeshDrawOpHelperWithStencil::makePipeline(GrMeshDrawOp::Target* target,
- int numPrimitiveProcessorTextures)
+auto GrSimpleMeshDrawOpHelperWithStencil::makePipeline(GrMeshDrawOp::Target* target)
-> PipelineAndFixedDynamicState {
auto args = INHERITED::pipelineInitArgs(target);
args.fUserStencil = fStencilSettings;
- return this->internalMakePipeline(target, args, numPrimitiveProcessorTextures);
+ return this->internalMakePipeline(target, args);
}
SkString GrSimpleMeshDrawOpHelperWithStencil::dumpInfo() const {
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index cd72786..2bffa09 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -88,10 +88,8 @@
using PipelineAndFixedDynamicState = GrOpFlushState::PipelineAndFixedDynamicState;
/** Makes a pipeline that consumes the processor set and the op's applied clip. */
- PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target* target,
- int numPrimitiveProcessorTextures = 0) {
- return this->internalMakePipeline(target, this->pipelineInitArgs(target),
- numPrimitiveProcessorTextures);
+ PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target* target) {
+ return this->internalMakePipeline(target, this->pipelineInitArgs(target));
}
struct MakeArgs {
@@ -118,8 +116,7 @@
GrPipeline::InitArgs pipelineInitArgs(GrMeshDrawOp::Target* target) const;
PipelineAndFixedDynamicState internalMakePipeline(GrMeshDrawOp::Target*,
- const GrPipeline::InitArgs&,
- int numPrimitiveProcessorTextures);
+ const GrPipeline::InitArgs&);
private:
GrProcessorSet* fProcessors;
@@ -165,8 +162,7 @@
bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that, const GrCaps&,
const SkRect& thisBounds, const SkRect& thatBounds) const;
- PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target*,
- int numPrimitiveProcessorTextures = 0);
+ PipelineAndFixedDynamicState makePipeline(GrMeshDrawOp::Target*);
SkString dumpInfo() const;
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index c480bc0..286fab7 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -304,7 +304,7 @@
sk_sp<const GrBuffer> fIndexBuffer;
sk_sp<GrGeometryProcessor> fGeometryProcessor;
const GrPipeline* fPipeline;
- GrPipeline::FixedDynamicState* fFixedDynamicState;
+ const GrPipeline::FixedDynamicState* fFixedDynamicState;
int fVertexOffset;
int fInstancesToFlush;
};
@@ -312,15 +312,7 @@
void onPrepareDraws(Target* target) override {
int instanceCount = fShapes.count();
- static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures;
- GR_STATIC_ASSERT(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
-
- auto pipe = fHelper.makePipeline(target, kMaxTextures);
- int numActiveProxies = fAtlas->numActivePages();
- const auto proxies = fAtlas->getProxies();
- for (int i = 0; i < numActiveProxies; ++i) {
- pipe.fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
- }
+ auto pipe = fHelper.makePipeline(target);
FlushInfo flushInfo;
flushInfo.fPipeline = pipe.fPipeline;
@@ -815,12 +807,7 @@
void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const {
GrGeometryProcessor* gp = flushInfo->fGeometryProcessor.get();
- int numAtlasTextures = SkToInt(fAtlas->numActivePages());
- auto proxies = fAtlas->getProxies();
- if (gp->numTextureSamplers() != numAtlasTextures) {
- for (int i = gp->numTextureSamplers(); i < numAtlasTextures; ++i) {
- flushInfo->fFixedDynamicState->fPrimitiveProcessorTextures[i] = proxies[i].get();
- }
+ if (gp->numTextureSamplers() != (int)fAtlas->numActivePages()) {
// During preparation the number of atlas pages has increased.
// Update the proxies used in the GP to match.
if (fUsesDistanceField) {
@@ -833,14 +820,14 @@
}
if (flushInfo->fInstancesToFlush) {
- GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
+ GrMesh mesh(GrPrimitiveType::kTriangles);
int maxInstancesPerDraw =
static_cast<int>(flushInfo->fIndexBuffer->gpuMemorySize() / sizeof(uint16_t) / 6);
- mesh->setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerQuad,
- kVerticesPerQuad, flushInfo->fInstancesToFlush,
- maxInstancesPerDraw);
- mesh->setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
- target->draw(flushInfo->fGeometryProcessor, flushInfo->fPipeline,
+ mesh.setIndexedPatterned(flushInfo->fIndexBuffer.get(), kIndicesPerQuad,
+ kVerticesPerQuad, flushInfo->fInstancesToFlush,
+ maxInstancesPerDraw);
+ mesh.setVertexData(flushInfo->fVertexBuffer.get(), flushInfo->fVertexOffset);
+ target->draw(flushInfo->fGeometryProcessor.get(), flushInfo->fPipeline,
flushInfo->fFixedDynamicState, mesh);
flushInfo->fVertexOffset += kVerticesPerQuad * flushInfo->fInstancesToFlush;
flushInfo->fInstancesToFlush = 0;
@@ -850,41 +837,41 @@
GrColor color() const { return fShapes[0].fColor; }
bool usesDistanceField() const { return fUsesDistanceField; }
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
SmallPathOp* that = t->cast<SmallPathOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->usesDistanceField() != that->usesDistanceField()) {
- return CombineResult::kCannotCombine;
+ return false;
}
const SkMatrix& thisCtm = this->fShapes[0].fViewMatrix;
const SkMatrix& thatCtm = that->fShapes[0].fViewMatrix;
if (thisCtm.hasPerspective() != thatCtm.hasPerspective()) {
- return CombineResult::kCannotCombine;
+ return false;
}
// We can position on the cpu unless we're in perspective,
// but also need to make sure local matrices are identical
if ((thisCtm.hasPerspective() || fHelper.usesLocalCoords()) &&
!thisCtm.cheapEqualTo(thatCtm)) {
- return CombineResult::kCannotCombine;
+ return false;
}
// Depending on the ctm we may have a different shader for SDF paths
if (this->usesDistanceField()) {
if (thisCtm.isScaleTranslate() != thatCtm.isScaleTranslate() ||
thisCtm.isSimilarity() != thatCtm.isSimilarity()) {
- return CombineResult::kCannotCombine;
+ return false;
}
}
fShapes.push_back_n(that->fShapes.count(), that->fShapes.begin());
this->joinBounds(*that);
- return CombineResult::kMerged;
+ return true;
}
bool fUsesDistanceField;
diff --git a/src/gpu/ops/GrStencilPathOp.h b/src/gpu/ops/GrStencilPathOp.h
index edfcaa8..563bdc3 100644
--- a/src/gpu/ops/GrStencilPathOp.h
+++ b/src/gpu/ops/GrStencilPathOp.h
@@ -56,6 +56,8 @@
this->setBounds(path->getBounds(), HasAABloat::kNo, IsZeroArea::kNo);
}
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { return false; }
+
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;
diff --git a/src/gpu/ops/GrTessellatingPathRenderer.cpp b/src/gpu/ops/GrTessellatingPathRenderer.cpp
index f722868..2fea9cb 100644
--- a/src/gpu/ops/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/ops/GrTessellatingPathRenderer.cpp
@@ -237,7 +237,7 @@
return path;
}
- void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
+ void draw(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
SkASSERT(!fAntiAlias);
GrResourceProvider* rp = target->resourceProvider();
bool inverseFill = fShape.inverseFilled();
@@ -261,7 +261,7 @@
SkScalar tol = GrPathUtils::kDefaultTolerance;
tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
- this->drawVertices(target, std::move(gp), cachedVertexBuffer.get(), 0, actualCount);
+ this->drawVertices(target, gp, cachedVertexBuffer.get(), 0, actualCount);
return;
}
@@ -280,7 +280,7 @@
if (count == 0) {
return;
}
- this->drawVertices(target, std::move(gp), allocator.vertexBuffer(), 0, count);
+ this->drawVertices(target, gp, allocator.vertexBuffer(), 0, count);
TessInfo info;
info.fTolerance = isLinear ? 0 : tol;
info.fCount = count;
@@ -289,7 +289,7 @@
fShape.addGenIDChangeListener(sk_make_sp<PathInvalidator>(key, target->contextUniqueID()));
}
- void drawAA(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
+ void drawAA(Target* target, const GrGeometryProcessor* gp, size_t vertexStride) {
SkASSERT(fAntiAlias);
SkPath path = getPath();
if (path.isEmpty()) {
@@ -306,8 +306,7 @@
if (count == 0) {
return;
}
- this->drawVertices(target, std::move(gp), allocator.vertexBuffer(), allocator.firstVertex(),
- count);
+ this->drawVertices(target, gp, allocator.vertexBuffer(), allocator.firstVertex(), count);
}
void onPrepareDraws(Target* target) override {
@@ -350,22 +349,23 @@
}
SkASSERT(vertexStride == gp->debugOnly_vertexStride());
if (fAntiAlias) {
- this->drawAA(target, std::move(gp), vertexStride);
+ this->drawAA(target, gp.get(), vertexStride);
} else {
- this->draw(target, std::move(gp), vertexStride);
+ this->draw(target, gp.get(), vertexStride);
}
}
- void drawVertices(Target* target, sk_sp<const GrGeometryProcessor> gp, const GrBuffer* vb,
+ void drawVertices(Target* target, const GrGeometryProcessor* gp, const GrBuffer* vb,
int firstVertex, int count) {
- GrMesh* mesh = target->allocMesh(TESSELLATOR_WIREFRAME ? GrPrimitiveType::kLines
- : GrPrimitiveType::kTriangles);
- mesh->setNonIndexedNonInstanced(count);
- mesh->setVertexData(vb, firstVertex);
+ GrMesh mesh(TESSELLATOR_WIREFRAME ? GrPrimitiveType::kLines : GrPrimitiveType::kTriangles);
+ mesh.setNonIndexedNonInstanced(count);
+ mesh.setVertexData(vb, firstVertex);
auto pipe = fHelper.makePipeline(target);
- target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
+ target->draw(gp, pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
+ bool onCombineIfPossible(GrOp*, const GrCaps&) override { return false; }
+
Helper fHelper;
GrColor fColor;
GrShape fShape;
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 2ba3639..72900ed 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -37,6 +37,8 @@
namespace {
+enum class MultiTexture : bool { kNo = false, kYes = true };
+
enum class Domain : bool { kNo = false, kYes = true };
/**
@@ -53,40 +55,79 @@
SkPoint fTextureCoords;
};
- template <typename Pos, Domain D> struct OptionalDomainVertex;
+ template <typename Pos, MultiTexture MT> struct OptionalMultiTextureVertex;
template <typename Pos>
- struct OptionalDomainVertex<Pos, Domain::kNo> : VertexCommon<Pos> {
- static constexpr Domain kDomain = Domain::kNo;
+ struct OptionalMultiTextureVertex<Pos, MultiTexture::kNo> : VertexCommon<Pos> {
+ static constexpr MultiTexture kMultiTexture = MultiTexture::kNo;
};
template <typename Pos>
- struct OptionalDomainVertex<Pos, Domain::kYes> : VertexCommon<Pos> {
+ struct OptionalMultiTextureVertex<Pos, MultiTexture::kYes> : VertexCommon<Pos> {
+ static constexpr MultiTexture kMultiTexture = MultiTexture::kYes;
+ int fTextureIdx;
+ };
+
+ template <typename Pos, MultiTexture MT, Domain D> struct OptionalDomainVertex;
+ template <typename Pos, MultiTexture MT>
+ struct OptionalDomainVertex<Pos, MT, Domain::kNo> : OptionalMultiTextureVertex<Pos, MT> {
+ static constexpr Domain kDomain = Domain::kNo;
+ };
+ template <typename Pos, MultiTexture MT>
+ struct OptionalDomainVertex<Pos, MT, Domain::kYes> : OptionalMultiTextureVertex<Pos, MT> {
static constexpr Domain kDomain = Domain::kYes;
SkRect fTextureDomain;
};
- template <typename Pos, Domain D, GrAA> struct OptionalAAVertex;
- template <typename Pos, Domain D>
- struct OptionalAAVertex<Pos, D, GrAA::kNo> : OptionalDomainVertex<Pos, D> {
+ template <typename Pos, MultiTexture MT, Domain D, GrAA> struct OptionalAAVertex;
+ template <typename Pos, MultiTexture MT, Domain D>
+ struct OptionalAAVertex<Pos, MT, D, GrAA::kNo> : OptionalDomainVertex<Pos, MT, D> {
static constexpr GrAA kAA = GrAA::kNo;
};
- template <typename Pos, Domain D>
- struct OptionalAAVertex<Pos, D, GrAA::kYes> : OptionalDomainVertex<Pos, D> {
+ template <typename Pos, MultiTexture MT, Domain D>
+ struct OptionalAAVertex<Pos, MT, D, GrAA::kYes> : OptionalDomainVertex<Pos, MT, D> {
static constexpr GrAA kAA = GrAA::kYes;
SkPoint3 fEdges[4];
};
- template <typename Pos, Domain D, GrAA AA>
- using Vertex = OptionalAAVertex<Pos, D, AA>;
+ template <typename Pos, MultiTexture MT, Domain D, GrAA AA>
+ using Vertex = OptionalAAVertex<Pos, MT, D, AA>;
- static sk_sp<GrGeometryProcessor> Make(GrTextureType textureType, GrPixelConfig textureConfig,
- const GrSamplerState::Filter filter,
+ // Maximum number of textures supported by this op. Must also be checked against the caps
+ // limit. These numbers were based on some limited experiments on a HP Z840 and Pixel XL 2016
+ // and could probably use more tuning.
+#ifdef SK_BUILD_FOR_ANDROID
+ static constexpr int kMaxTextures = 4;
+#else
+ static constexpr int kMaxTextures = 8;
+#endif
+
+ static int SupportsMultitexture(const GrShaderCaps& caps) {
+ return caps.integerSupport() && caps.maxFragmentSamplers() > 1;
+ }
+
+ static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
sk_sp<GrColorSpaceXform> paintColorSpaceXform,
- bool coverageAA, bool perspective, Domain domain,
+ bool coverageAA,
+ bool perspective, Domain domain,
+ const GrSamplerState::Filter filters[],
const GrShaderCaps& caps) {
- return sk_sp<TextureGeometryProcessor>(new TextureGeometryProcessor(
- textureType, textureConfig, filter, std::move(textureColorSpaceXform),
- std::move(paintColorSpaceXform), coverageAA, perspective, domain, caps));
+ // We use placement new to avoid always allocating space for kMaxTextures TextureSampler
+ // instances.
+ int samplerCnt = NumSamplersToUse(proxyCnt, caps);
+ size_t size = sizeof(TextureGeometryProcessor) + sizeof(TextureSampler) * (samplerCnt - 1);
+ void* mem = GrGeometryProcessor::operator new(size);
+ return sk_sp<TextureGeometryProcessor>(
+ new (mem) TextureGeometryProcessor(proxies, proxyCnt, samplerCnt,
+ std::move(textureColorSpaceXform),
+ std::move(paintColorSpaceXform),
+ coverageAA, perspective, domain, filters, caps));
+ }
+
+ ~TextureGeometryProcessor() override {
+ int cnt = this->numTextureSamplers();
+ for (int i = 1; i < cnt; ++i) {
+ fSamplers[i].~TextureSampler();
+ }
}
const char* name() const override { return "TextureGeometryProcessor"; }
@@ -156,10 +197,28 @@
args.fFragBuilder->codeAppend(
"texCoord = clamp(texCoord, domain.xy, domain.zw);");
}
- args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
- args.fFragBuilder->appendTextureLookupAndModulate(
- args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
- &fTextureColorSpaceXformHelper);
+ if (textureGP.numTextureSamplers() > 1) {
+ // If this changes to float, reconsider Interpolation::kMustBeFlat.
+ SkASSERT(kInt_GrVertexAttribType == textureGP.fTextureIdx.type());
+ SkASSERT(args.fShaderCaps->integerSupport());
+ args.fFragBuilder->codeAppend("int texIdx;");
+ args.fVaryingHandler->addPassThroughAttribute(textureGP.fTextureIdx, "texIdx",
+ Interpolation::kMustBeFlat);
+ args.fFragBuilder->codeAppend("switch (texIdx) {");
+ for (int i = 0; i < textureGP.numTextureSamplers(); ++i) {
+ args.fFragBuilder->codeAppendf("case %d: %s = ", i, args.fOutputColor);
+ args.fFragBuilder->appendTextureLookupAndModulate(
+ args.fOutputColor, args.fTexSamplers[i], "texCoord",
+ kFloat2_GrSLType, &fTextureColorSpaceXformHelper);
+ args.fFragBuilder->codeAppend("; break;");
+ }
+ args.fFragBuilder->codeAppend("}");
+ } else {
+ args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor);
+ args.fFragBuilder->appendTextureLookupAndModulate(
+ args.fOutputColor, args.fTexSamplers[0], "texCoord",
+ kFloat2_GrSLType, &fTextureColorSpaceXformHelper);
+ }
args.fFragBuilder->codeAppend(";");
if (textureGP.usesCoverageEdgeAA()) {
bool mulByFragCoordW = false;
@@ -212,16 +271,36 @@
bool usesCoverageEdgeAA() const { return SkToBool(fAAEdges[0].isInitialized()); }
private:
- TextureGeometryProcessor(GrTextureType textureType, GrPixelConfig textureConfig,
- GrSamplerState::Filter filter,
+ // This exists to reduce the number of shaders generated. It does some rounding of sampler
+ // counts.
+ static int NumSamplersToUse(int numRealProxies, const GrShaderCaps& caps) {
+ SkASSERT(numRealProxies > 0 && numRealProxies <= kMaxTextures &&
+ numRealProxies <= caps.maxFragmentSamplers());
+ if (1 == numRealProxies) {
+ return 1;
+ }
+ if (numRealProxies <= 4) {
+ return 4;
+ }
+ // Round to the next power of 2 and then clamp to kMaxTextures and the max allowed by caps.
+ return SkTMin(SkNextPow2(numRealProxies), SkTMin(kMaxTextures, caps.maxFragmentSamplers()));
+ }
+
+ TextureGeometryProcessor(sk_sp<GrTextureProxy> proxies[], int proxyCnt, int samplerCnt,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
- sk_sp<GrColorSpaceXform> paintColorSpaceXform, bool coverageAA,
- bool perspective, Domain domain, const GrShaderCaps& caps)
+ sk_sp<GrColorSpaceXform> paintColorSpaceXform,
+ bool coverageAA, bool perspective, Domain domain,
+ const GrSamplerState::Filter filters[], const GrShaderCaps& caps)
: INHERITED(kTextureGeometryProcessor_ClassID)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
- , fPaintColorSpaceXform(std::move(paintColorSpaceXform))
- , fSampler(textureType, textureConfig, filter) {
- this->setTextureSamplerCnt(1);
+ , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) {
+ SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt);
+ fSamplers[0].reset(std::move(proxies[0]), filters[0]);
+ for (int i = 1; i < proxyCnt; ++i) {
+ // This class has one sampler built in, the rest come from memory this processor was
+ // placement-newed into and so haven't been constructed.
+ new (&fSamplers[i]) TextureSampler(std::move(proxies[i]), filters[i]);
+ }
if (perspective) {
fPositions = {"position", kFloat3_GrVertexAttribType};
@@ -232,6 +311,17 @@
fTextureCoords = {"textureCoords", kFloat2_GrVertexAttribType};
int vertexAttributeCnt = 3;
+ if (samplerCnt > 1) {
+ // Here we initialize any extra samplers by repeating the last one samplerCnt - proxyCnt
+ // times.
+ GrTextureProxy* dupeProxy = fSamplers[proxyCnt - 1].proxy();
+ for (int i = proxyCnt; i < samplerCnt; ++i) {
+ new (&fSamplers[i]) TextureSampler(sk_ref_sp(dupeProxy), filters[proxyCnt - 1]);
+ }
+ SkASSERT(caps.integerSupport());
+ fTextureIdx = {"textureIdx", kInt_GrVertexAttribType};
+ ++vertexAttributeCnt;
+ }
if (domain == Domain::kYes) {
fDomain = {"domain", kFloat4_GrVertexAttribType};
++vertexAttributeCnt;
@@ -244,23 +334,25 @@
vertexAttributeCnt += 4;
}
this->setVertexAttributeCnt(vertexAttributeCnt);
+ this->setTextureSamplerCnt(samplerCnt);
}
const Attribute& onVertexAttribute(int i) const override {
- return IthInitializedAttribute(i, fPositions, fColors, fTextureCoords, fDomain, fAAEdges[0],
- fAAEdges[1], fAAEdges[2], fAAEdges[3]);
+ return IthInitializedAttribute(i, fPositions, fColors, fTextureCoords, fTextureIdx, fDomain,
+ fAAEdges[0], fAAEdges[1], fAAEdges[2], fAAEdges[3]);
}
- const TextureSampler& onTextureSampler(int) const override { return fSampler; }
+ const TextureSampler& onTextureSampler(int i) const override { return fSamplers[i]; }
Attribute fPositions;
Attribute fColors;
Attribute fTextureCoords;
+ Attribute fTextureIdx;
Attribute fDomain;
Attribute fAAEdges[4];
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
- TextureSampler fSampler;
+ TextureSampler fSamplers[1];
typedef GrGeometryProcessor INHERITED;
};
@@ -435,6 +527,20 @@
}
};
+template <typename V, MultiTexture MT = V::kMultiTexture> struct TexIdAssigner;
+
+template <typename V> struct TexIdAssigner<V, MultiTexture::kYes> {
+ static void Assign(V* vertices, int textureIdx) {
+ for (int i = 0; i < 4; ++i) {
+ vertices[i].fTextureIdx = textureIdx;
+ }
+ }
+};
+
+template <typename V> struct TexIdAssigner<V, MultiTexture::kNo> {
+ static void Assign(V* vertices, int textureIdx) {}
+};
+
template <typename V, Domain D = V::kDomain> struct DomainAssigner;
template <typename V> struct DomainAssigner<V, Domain::kYes> {
@@ -479,7 +585,7 @@
template <typename V>
static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, GrColor color,
GrSurfaceOrigin origin, GrSamplerState::Filter filter, V* vertices,
- SkScalar iw, SkScalar ih, Domain domain) {
+ SkScalar iw, SkScalar ih, int textureIdx, Domain domain) {
SkRect texRect = {
iw * srcRect.fLeft,
ih * srcRect.fTop,
@@ -495,6 +601,7 @@
vertices[1].fColor = color;
vertices[2].fColor = color;
vertices[3].fColor = color;
+ TexIdAssigner<V>::Assign(vertices, textureIdx);
DomainAssigner<V>::Assign(vertices, domain, filter, srcRect, origin, iw, ih);
}
@@ -525,27 +632,42 @@
~TextureOp() override {
if (fFinalized) {
- fProxy->completedRead();
+ auto proxies = this->proxies();
+ for (int i = 0; i < fProxyCnt; ++i) {
+ proxies[i]->completedRead();
+ }
+ if (fProxyCnt > 1) {
+ delete[] reinterpret_cast<const char*>(proxies);
+ }
} else {
- fProxy->unref();
+ SkASSERT(1 == fProxyCnt);
+ fProxy0->unref();
}
}
const char* name() const override { return "TextureOp"; }
- void visitProxies(const VisitProxyFunc& func) const override { func(fProxy); }
+ void visitProxies(const VisitProxyFunc& func) const override {
+ auto proxies = this->proxies();
+ for (int i = 0; i < fProxyCnt; ++i) {
+ func(proxies[i]);
+ }
+ }
SkString dumpInfo() const override {
SkString str;
str.appendf("# draws: %d\n", fDraws.count());
- str.appendf("Proxy ID: %d, Filter: %d\n", fProxy->uniqueID().asUInt(),
- static_cast<int>(fFilter));
+ auto proxies = this->proxies();
+ for (int i = 0; i < fProxyCnt; ++i) {
+ str.appendf("Proxy ID %d: %d, Filter: %d\n", i, proxies[i]->uniqueID().asUInt(),
+ static_cast<int>(this->filters()[i]));
+ }
for (int i = 0; i < fDraws.count(); ++i) {
const Draw& draw = fDraws[i];
str.appendf(
- "%d: Color: 0x%08x, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
+ "%d: Color: 0x%08x, ProxyIdx: %d, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] "
"Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n",
- i, draw.color(), draw.srcRect().fLeft, draw.srcRect().fTop,
+ i, draw.color(), draw.textureIdx(), draw.srcRect().fLeft, draw.srcRect().fTop,
draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX,
draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY,
draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX,
@@ -557,9 +679,10 @@
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkASSERT(!fFinalized);
+ SkASSERT(1 == fProxyCnt);
fFinalized = true;
- fProxy->addPendingRead();
- fProxy->unref();
+ fProxy0->addPendingRead();
+ fProxy0->unref();
return RequiresDstTexture::kNo;
}
@@ -573,6 +696,17 @@
private:
friend class ::GrOpMemoryPool;
+ // This is used in a heursitic for choosing a code path. We don't care what happens with
+ // really large rects, infs, nans, etc.
+#if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007
+__attribute__((no_sanitize("float-cast-overflow")))
+#endif
+ size_t RectSizeAsSizeT(const SkRect& rect) {;
+ return static_cast<size_t>(SkTMax(rect.width(), 1.f) * SkTMax(rect.height(), 1.f));
+ }
+
+ static constexpr int kMaxTextures = TextureGeometryProcessor::kMaxTextures;
+
TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color,
const SkRect& srcRect, const SkRect& dstRect, GrAAType aaType,
SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
@@ -581,8 +715,9 @@
: INHERITED(ClassID())
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fPaintColorSpaceXform(std::move(paintColorSpaceXform))
- , fProxy(proxy.release())
- , fFilter(filter)
+ , fProxy0(proxy.release())
+ , fFilter0(filter)
+ , fProxyCnt(1)
, fAAType(static_cast<unsigned>(aaType))
, fFinalized(0) {
SkASSERT(aaType != GrAAType::kMixedSamples);
@@ -605,39 +740,46 @@
}
}
#endif
- const auto& draw = fDraws.emplace_back(srcRect, quad, constraint, color);
+ const auto& draw = fDraws.emplace_back(srcRect, 0, quad, constraint, color);
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
fDomain = static_cast<bool>(draw.domain());
+ fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds);
}
- template <typename Pos, Domain D, GrAA AA>
- void tess(void* v, const GrGeometryProcessor* gp) {
- using Vertex = TextureGeometryProcessor::Vertex<Pos, D, AA>;
+ template <typename Pos, MultiTexture MT, Domain D, GrAA AA>
+ void tess(void* v, const float iw[], const float ih[], const GrGeometryProcessor* gp) {
+ using Vertex = TextureGeometryProcessor::Vertex<Pos, MT, D, AA>;
SkASSERT(gp->debugOnly_vertexStride() == sizeof(Vertex));
auto vertices = static_cast<Vertex*>(v);
- auto origin = fProxy->origin();
- const auto* texture = fProxy->peekTexture();
- float iw = 1.f / texture->width();
- float ih = 1.f / texture->height();
-
+ auto proxies = this->proxies();
+ auto filters = this->filters();
for (const auto& draw : fDraws) {
- tessellate_quad<Vertex>(draw.quad(), draw.srcRect(), draw.color(), origin, fFilter,
- vertices, iw, ih, draw.domain());
+ auto textureIdx = draw.textureIdx();
+ auto origin = proxies[textureIdx]->origin();
+ tessellate_quad<Vertex>(draw.quad(), draw.srcRect(), draw.color(), origin,
+ filters[textureIdx], vertices, iw[textureIdx], ih[textureIdx],
+ textureIdx, draw.domain());
vertices += 4;
}
}
void onPrepareDraws(Target* target) override {
- if (!fProxy->instantiate(target->resourceProvider())) {
- return;
+ sk_sp<GrTextureProxy> proxiesSPs[kMaxTextures];
+ auto proxies = this->proxies();
+ auto filters = this->filters();
+ for (int i = 0; i < fProxyCnt; ++i) {
+ if (!proxies[i]->instantiate(target->resourceProvider())) {
+ return;
+ }
+ proxiesSPs[i] = sk_ref_sp(proxies[i]);
}
Domain domain = fDomain ? Domain::kYes : Domain::kNo;
bool coverageAA = GrAAType::kCoverage == this->aaType();
sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(
- fProxy->textureType(), fProxy->config(), fFilter,
- std::move(fTextureColorSpaceXform), std::move(fPaintColorSpaceXform), coverageAA,
- fPerspective, domain, *target->caps().shaderCaps());
+ proxiesSPs, fProxyCnt, std::move(fTextureColorSpaceXform),
+ std::move(fPaintColorSpaceXform), coverageAA, fPerspective,
+ domain, filters, *target->caps().shaderCaps());
GrPipeline::InitArgs args;
args.fProxy = target->proxy();
args.fCaps = &target->caps();
@@ -648,34 +790,43 @@
}
auto clip = target->detachAppliedClip();
- auto* fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect(), 1);
- fixedDynamicState->fPrimitiveProcessorTextures[0] = fProxy;
+ const auto* fixedDynamicState = target->allocFixedDynamicState(clip.scissorState().rect());
const auto* pipeline =
target->allocPipeline(args, GrProcessorSet::MakeEmptySet(), std::move(clip));
- using TessFn = decltype(&TextureOp::tess<SkPoint, Domain::kNo, GrAA::kNo>);
-#define TESS_FN_AND_VERTEX_SIZE(Point, Domain, AA) \
- { \
- &TextureOp::tess<Point, Domain, AA>, \
- sizeof(TextureGeometryProcessor::Vertex<Point, Domain, AA>) \
+ using TessFn =
+ decltype(&TextureOp::tess<SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kNo>);
+#define TESS_FN_AND_VERTEX_SIZE(Point, MT, Domain, AA) \
+ { \
+ &TextureOp::tess<Point, MT, Domain, AA>, \
+ sizeof(TextureGeometryProcessor::Vertex<Point, MT, Domain, AA>) \
}
static constexpr struct {
TessFn fTessFn;
size_t fVertexSize;
} kTessFnsAndVertexSizes[] = {
- TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kNo),
- TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kNo, GrAA::kYes),
- TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kNo),
- TESS_FN_AND_VERTEX_SIZE(SkPoint, Domain::kYes, GrAA::kYes),
- TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kNo),
- TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kNo, GrAA::kYes),
- TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kNo),
- TESS_FN_AND_VERTEX_SIZE(SkPoint3, Domain::kYes, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kNo, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kYes, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kNo, Domain::kYes, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kNo, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kNo, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kYes, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint, MultiTexture::kYes, Domain::kYes, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kNo, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kNo, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kYes, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kNo, Domain::kYes, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kNo, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kNo, GrAA::kYes),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kYes, GrAA::kNo),
+ TESS_FN_AND_VERTEX_SIZE(SkPoint3, MultiTexture::kYes, Domain::kYes, GrAA::kYes),
};
#undef TESS_FN_AND_VERTEX_SIZE
int tessFnIdx = 0;
- tessFnIdx |= coverageAA ? 0x1 : 0x0;
- tessFnIdx |= fDomain ? 0x2 : 0x0;
- tessFnIdx |= fPerspective ? 0x4 : 0x0;
+ tessFnIdx |= coverageAA ? 0x1 : 0x0;
+ tessFnIdx |= fDomain ? 0x2 : 0x0;
+ tessFnIdx |= (fProxyCnt > 1) ? 0x4 : 0x0;
+ tessFnIdx |= fPerspective ? 0x8 : 0x0;
SkASSERT(kTessFnsAndVertexSizes[tessFnIdx].fVertexSize == gp->debugOnly_vertexStride());
@@ -688,75 +839,212 @@
return;
}
- (this->*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, gp.get());
+ float iw[kMaxTextures];
+ float ih[kMaxTextures];
+ for (int t = 0; t < fProxyCnt; ++t) {
+ const auto* texture = proxies[t]->peekTexture();
+ iw[t] = 1.f / texture->width();
+ ih[t] = 1.f / texture->height();
+ }
+
+ (this->*(kTessFnsAndVertexSizes[tessFnIdx].fTessFn))(vdata, iw, ih, gp.get());
GrPrimitiveType primitiveType =
fDraws.count() > 1 ? GrPrimitiveType::kTriangles : GrPrimitiveType::kTriangleStrip;
- GrMesh* mesh = target->allocMesh(primitiveType);
+ GrMesh mesh(primitiveType);
if (fDraws.count() > 1) {
sk_sp<const GrBuffer> ibuffer = target->resourceProvider()->refQuadIndexBuffer();
if (!ibuffer) {
SkDebugf("Could not allocate quad indices\n");
return;
}
- mesh->setIndexedPatterned(ibuffer.get(), 6, 4, fDraws.count(),
- GrResourceProvider::QuadCountOfQuadBuffer());
+ mesh.setIndexedPatterned(ibuffer.get(), 6, 4, fDraws.count(),
+ GrResourceProvider::QuadCountOfQuadBuffer());
} else {
- mesh->setNonIndexedNonInstanced(4);
+ mesh.setNonIndexedNonInstanced(4);
}
- mesh->setVertexData(vbuffer, vstart);
- target->draw(std::move(gp), pipeline, fixedDynamicState, mesh);
+ mesh.setVertexData(vbuffer, vstart);
+ target->draw(gp.get(), pipeline, fixedDynamicState, mesh);
}
- CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override {
+ bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
const auto* that = t->cast<TextureOp>();
+ const auto& shaderCaps = *caps.shaderCaps();
if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(),
that->fTextureColorSpaceXform.get())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (!GrColorSpaceXform::Equals(fPaintColorSpaceXform.get(),
that->fPaintColorSpaceXform.get())) {
- return CombineResult::kCannotCombine;
+ return false;
}
if (this->aaType() != that->aaType()) {
- return CombineResult::kCannotCombine;
+ return false;
}
- if (fProxy->uniqueID() != that->fProxy->uniqueID() || fFilter != that->fFilter) {
- return CombineResult::kCannotCombine;
+ // Because of an issue where GrColorSpaceXform adds the same function every time it is used
+ // in a texture lookup, we only allow multiple textures when there is no transform.
+ if (TextureGeometryProcessor::SupportsMultitexture(shaderCaps) &&
+ !fTextureColorSpaceXform &&
+ fMaxApproxDstPixelArea <= shaderCaps.disableImageMultitexturingDstRectAreaThreshold() &&
+ that->fMaxApproxDstPixelArea <=
+ shaderCaps.disableImageMultitexturingDstRectAreaThreshold()) {
+ int map[kMaxTextures];
+ int numNewProxies = this->mergeProxies(that, map, shaderCaps);
+ if (numNewProxies < 0) {
+ return false;
+ }
+ if (1 == fProxyCnt && numNewProxies) {
+ void* mem = new char[(sizeof(GrSamplerState::Filter) + sizeof(GrTextureProxy*)) *
+ kMaxTextures];
+ auto proxies = reinterpret_cast<GrTextureProxy**>(mem);
+ auto filters = reinterpret_cast<GrSamplerState::Filter*>(proxies + kMaxTextures);
+ proxies[0] = fProxy0;
+ filters[0] = fFilter0;
+ fProxyArray = proxies;
+ }
+ fProxyCnt += numNewProxies;
+ auto thisProxies = fProxyArray;
+ auto thatProxies = that->proxies();
+ auto thatFilters = that->filters();
+ auto thisFilters = reinterpret_cast<GrSamplerState::Filter*>(thisProxies +
+ kMaxTextures);
+ for (int i = 0; i < that->fProxyCnt; ++i) {
+ if (map[i] < 0) {
+ thatProxies[i]->addPendingRead();
+
+ thisProxies[-map[i]] = thatProxies[i];
+ thisFilters[-map[i]] = thatFilters[i];
+ map[i] = -map[i];
+ }
+ }
+ int firstNewDraw = fDraws.count();
+ fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
+ for (int i = firstNewDraw; i < fDraws.count(); ++i) {
+ fDraws[i].setTextureIdx(map[fDraws[i].textureIdx()]);
+ }
+ } else {
+ // We can get here when one of the ops is already multitextured but the other cannot
+ // be because of the dst rect size.
+ if (fProxyCnt > 1 || that->fProxyCnt > 1) {
+ return false;
+ }
+ if (fProxy0->uniqueID() != that->fProxy0->uniqueID() || fFilter0 != that->fFilter0) {
+ return false;
+ }
+ fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
}
- fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin());
this->joinBounds(*that);
+ fMaxApproxDstPixelArea = SkTMax(that->fMaxApproxDstPixelArea, fMaxApproxDstPixelArea);
fPerspective |= that->fPerspective;
fDomain |= that->fDomain;
- return CombineResult::kMerged;
+ return true;
+ }
+
+ /**
+ * Determines a mapping of indices from that's proxy array to this's proxy array. A negative map
+ * value means that's proxy should be added to this's proxy array at the absolute value of
+ * the map entry. If it is determined that the ops shouldn't combine their proxies then a
+ * negative value is returned. Otherwise, return value indicates the number of proxies that have
+ * to be added to this op or, equivalently, the number of negative entries in map.
+ */
+ int mergeProxies(const TextureOp* that, int map[kMaxTextures], const GrShaderCaps& caps) const {
+ std::fill_n(map, kMaxTextures, -kMaxTextures);
+ int sharedProxyCnt = 0;
+ auto thisProxies = this->proxies();
+ auto thisFilters = this->filters();
+ auto thatProxies = that->proxies();
+ auto thatFilters = that->filters();
+ for (int i = 0; i < fProxyCnt; ++i) {
+ for (int j = 0; j < that->fProxyCnt; ++j) {
+ if (thisProxies[i]->uniqueID() == thatProxies[j]->uniqueID()) {
+ if (thisFilters[i] != thatFilters[j]) {
+ // In GL we don't currently support using the same texture with different
+ // samplers. If we added support for sampler objects and a cap bit to know
+ // it's ok to use different filter modes then we could support this.
+ // Otherwise, we could also only allow a single filter mode for each op
+ // instance.
+ return -1;
+ }
+ map[j] = i;
+ ++sharedProxyCnt;
+ break;
+ }
+ }
+ }
+ int actualMaxTextures = SkTMin(caps.maxFragmentSamplers(), kMaxTextures);
+ int newProxyCnt = that->fProxyCnt - sharedProxyCnt;
+ if (newProxyCnt + fProxyCnt > actualMaxTextures) {
+ return -1;
+ }
+ GrPixelConfig config = thisProxies[0]->config();
+ int nextSlot = fProxyCnt;
+ for (int j = 0; j < that->fProxyCnt; ++j) {
+ // We want to avoid making many shaders because of different permutations of shader
+ // based swizzle and sampler types. The approach taken here is to require the configs to
+ // be the same and to only allow already instantiated proxies that have the most
+ // common sampler type. Otherwise we don't merge.
+ if (thatProxies[j]->config() != config) {
+ return -1;
+ }
+ if (GrTexture* tex = thatProxies[j]->peekTexture()) {
+ if (tex->texturePriv().textureType() != GrTextureType::k2D) {
+ return -1;
+ }
+ }
+ if (map[j] < 0) {
+ map[j] = -(nextSlot++);
+ }
+ }
+ return newProxyCnt;
}
GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
+ GrTextureProxy* const* proxies() const { return fProxyCnt > 1 ? fProxyArray : &fProxy0; }
+
+ const GrSamplerState::Filter* filters() const {
+ if (fProxyCnt > 1) {
+ return reinterpret_cast<const GrSamplerState::Filter*>(fProxyArray + kMaxTextures);
+ }
+ return &fFilter0;
+ }
+
class Draw {
public:
- Draw(const SkRect& srcRect, const GrPerspQuad& quad, SkCanvas::SrcRectConstraint constraint,
- GrColor color)
+ Draw(const SkRect& srcRect, int textureIdx, const GrPerspQuad& quad,
+ SkCanvas::SrcRectConstraint constraint, GrColor color)
: fSrcRect(srcRect)
+ , fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint)
+ , fTextureIdx(SkToUInt(textureIdx))
, fQuad(quad)
- , fColor(color)
- , fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint) {}
+ , fColor(color) {}
const GrPerspQuad& quad() const { return fQuad; }
+ int textureIdx() const { return SkToInt(fTextureIdx); }
const SkRect& srcRect() const { return fSrcRect; }
GrColor color() const { return fColor; }
Domain domain() const { return Domain(fHasDomain); }
+ void setTextureIdx(int i) { fTextureIdx = SkToUInt(i); }
private:
SkRect fSrcRect;
+ unsigned fHasDomain : 1;
+ unsigned fTextureIdx : 31;
GrPerspQuad fQuad;
GrColor fColor;
- bool fHasDomain;
};
SkSTArray<1, Draw, true> fDraws;
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
sk_sp<GrColorSpaceXform> fPaintColorSpaceXform;
- GrTextureProxy* fProxy;
- GrSamplerState::Filter fFilter;
+ // Initially we store a single proxy ptr and a single filter. If we grow to have more than
+ // one proxy we instead store pointers to dynamically allocated arrays of size kMaxTextures
+ // followed by kMaxTextures filters.
+ union {
+ GrTextureProxy* fProxy0;
+ GrTextureProxy** fProxyArray;
+ };
+ size_t fMaxApproxDstPixelArea;
+ GrSamplerState::Filter fFilter0;
+ uint8_t fProxyCnt;
unsigned fAAType : 2;
unsigned fPerspective : 1;
unsigned fDomain : 1;
@@ -766,6 +1054,9 @@
typedef GrMeshDrawOp INHERITED;
};
+constexpr int TextureGeometryProcessor::kMaxTextures;
+constexpr int TextureOp::kMaxTextures;
+
} // anonymous namespace
namespace GrTextureOp {
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 3cbc6ad..013c1d7 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -585,11 +585,7 @@
}
fLastPipelineState = pipelineState;
- const GrTextureProxy* const* primProcProxies = nullptr;
- if (fixedDynamicState) {
- primProcProxies = fixedDynamicState->fPrimitiveProcessorTextures;
- }
- pipelineState->setData(fGpu, primProc, pipeline, primProcProxies);
+ pipelineState->setData(fGpu, primProc, pipeline);
pipelineState->bind(fGpu, cbInfo.currentCmdBuf());
@@ -647,8 +643,8 @@
};
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
- auto texture = fixedDynamicState->fPrimitiveProcessorTextures[i]->peekTexture();
- prepareSampledImage(texture, primProc.textureSampler(i).samplerState().filter());
+ const GrPrimitiveProcessor::TextureSampler& sampler = primProc.textureSampler(i);
+ prepareSampledImage(sampler.peekTexture(), sampler.samplerState().filter());
}
GrFragmentProcessor::Iter iter(pipeline);
while (const GrFragmentProcessor* fp = iter.next()) {
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index 011db9d..04a85a4 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -167,9 +167,7 @@
void GrVkPipelineState::setData(GrVkGpu* gpu,
const GrPrimitiveProcessor& primProc,
- const GrPipeline& pipeline,
- const GrTextureProxy* const primProcTextures[]) {
- SkASSERT(primProcTextures || !primProc.numTextureSamplers());
+ const GrPipeline& pipeline) {
// This is here to protect against someone calling setData multiple times in a row without
// freeing the tempData between calls.
this->freeTempResources(gpu);
@@ -183,8 +181,8 @@
GrFragmentProcessor::CoordTransformIter(pipeline));
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const auto& sampler = primProc.textureSampler(i);
- auto texture = static_cast<GrVkTexture*>(primProcTextures[i]->peekTexture());
- samplerBindings[currTextureBinding++] = {sampler.samplerState(), texture};
+ samplerBindings[currTextureBinding++] = {sampler.samplerState(),
+ static_cast<GrVkTexture*>(sampler.peekTexture())};
}
GrFragmentProcessor::Iter iter(pipeline);
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index d61359c..1df4bb5 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -56,8 +56,7 @@
~GrVkPipelineState();
- void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&,
- const GrTextureProxy* const primitiveProcessorTextures[]);
+ void setData(GrVkGpu*, const GrPrimitiveProcessor&, const GrPipeline&);
void bind(const GrVkGpu* gpu, GrVkCommandBuffer* commandBuffer);