aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar csmartdalton <csmartdalton@google.com>2016-08-17 10:00:21 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-17 10:00:22 -0700
commit28341fad8438b294ed7311edbc68d8cb34a990ab (patch)
tree7f4573e0cbf2c58c8e44496bf3b1e5136f6f3702
parent8d3f92a92be713cedfee48e01987264bd4f3083f (diff)
Implement difference clip rects with window rectangles
Plumbs the pipeline for window rectangles and uses them for a very basic implementation of difference clip rects. This puts a common Blink pattern on fast path, but we will still eventually need to make more comprehensive use of window rectangles during clipping. GTX 960 perf result: gpu glinst4 glinst16 desk_jsfiddlebigcar.skp 0.254 -> 0.177 [70%] 0.279 -> 0.197 [71%] 0.577 -> 0.196 [34%] keymobi_sfgate_com_.skp 0.697 -> 0.513 [74%] 0.766 -> 0.451 [59%] 0.769 -> 0.597 [78%] keymobi_blogger.skp 0.406 -> 0.314 [77%] 0.436 -> 0.292 [67%] 0.696 -> 0.319 [46%] desk_pokemonwiki.skp 0.121 -> 0.098 [81%] 0.13 -> 0.105 [81%] 0.216 -> 0.097 [45%] desk_wikipedia.skp 0.121 -> 0.098 [81%] 0.13 -> 0.104 [80%] 0.199 -> 0.104 [52%] keymobi_androidpolice_co... 0.443 -> 0.382 [86%] 0.447 -> 0.398 [89%] 0.444 -> 0.396 [89%] keymobi_booking_com_sear... 1 .15 -> 1.03 [90%] 1.17 -> 1.06 [91%] 1.17 -> 1.05 [90%] keymobi_theverge_com.skp 0.417 -> 0.396 [95%] 0.426 -> 0.405 [95%] 0.429 -> 0.4 [93%] BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2251573002 Review-Url: https://codereview.chromium.org/2251573002
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrClip.h47
-rw-r--r--src/gpu/GrAppliedClip.h72
-rw-r--r--src/gpu/GrCaps.cpp6
-rw-r--r--src/gpu/GrClip.cpp1
-rw-r--r--src/gpu/GrClipStackClip.cpp19
-rw-r--r--src/gpu/GrDrawTarget.cpp2
-rw-r--r--src/gpu/GrNonAtomicRef.h2
-rw-r--r--src/gpu/GrPipeline.cpp2
-rw-r--r--src/gpu/GrPipeline.h5
-rw-r--r--src/gpu/GrWindowRectangles.h110
-rw-r--r--src/gpu/gl/GrGLCaps.cpp2
-rw-r--r--src/gpu/gl/GrGLGpu.cpp44
-rw-r--r--src/gpu/gl/GrGLGpu.h39
-rw-r--r--src/gpu/gl/GrGLIRect.h19
-rw-r--r--tests/WindowRectanglesTest.cpp92
16 files changed, 415 insertions, 49 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index a856cb495b..e85b72ee35 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -67,6 +67,7 @@
'<(skia_include_path)/private/GrSurfaceProxy.h',
'<(skia_include_path)/private/GrTextureProxy.h',
+ '<(skia_src_path)/gpu/GrAppliedClip.h',
'<(skia_src_path)/gpu/GrAuditTrail.cpp',
'<(skia_src_path)/gpu/GrAutoLocaleSetter.h',
'<(skia_src_path)/gpu/GrAllocator.h',
@@ -200,6 +201,7 @@
'<(skia_src_path)/gpu/GrTextureAccess.cpp',
'<(skia_src_path)/gpu/GrTRecorder.h',
'<(skia_src_path)/gpu/GrUserStencilSettings.h',
+ '<(skia_src_path)/gpu/GrWindowRectangles.h',
'<(skia_src_path)/gpu/GrXferProcessor.cpp',
'<(skia_src_path)/gpu/GrYUVProvider.cpp',
'<(skia_src_path)/gpu/GrYUVProvider.h',
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
index a6a0a665bd..6457d03051 100644
--- a/include/gpu/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -11,55 +11,10 @@
#include "GrFragmentProcessor.h"
#include "GrTypesPriv.h"
+class GrAppliedClip;
class GrDrawContext;
/**
- * Produced by GrClip. It provides a set of modifications to the drawing state that are used to
- * create the final GrPipeline for a GrBatch.
- */
-class GrAppliedClip : public SkNoncopyable {
-public:
- GrAppliedClip(const SkRect& drawBounds)
- : fHasStencilClip(false)
- , fClippedDrawBounds(drawBounds) {
- }
-
- const GrScissorState& scissorState() const { return fScissorState; }
- GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP.get(); }
- bool hasStencilClip() const { return fHasStencilClip; }
-
- /**
- * Intersects the applied clip with the provided rect. Returns false if the draw became empty.
- */
- bool addScissor(const SkIRect& irect) {
- return fScissorState.intersect(irect) && fClippedDrawBounds.intersect(SkRect::Make(irect));
- }
-
- void addCoverageFP(sk_sp<GrFragmentProcessor> fp) {
- SkASSERT(!fClipCoverageFP);
- fClipCoverageFP = fp;
- }
-
- void addStencilClip() {
- SkASSERT(!fHasStencilClip);
- fHasStencilClip = true;
- }
-
- /**
- * Returns the device bounds of the draw after clip has been applied. TODO: Ideally this would
- * consider the combined effect of all clipping techniques in play (scissor, stencil, fp, etc.).
- */
- const SkRect& clippedDrawBounds() const { return fClippedDrawBounds; }
-
-private:
- GrScissorState fScissorState;
- sk_sp<GrFragmentProcessor> fClipCoverageFP;
- bool fHasStencilClip;
- SkRect fClippedDrawBounds;
- typedef SkNoncopyable INHERITED;
-};
-
-/**
* GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and
* fills out a GrAppliedClip instructing the caller on how to set up the draw state.
*/
diff --git a/src/gpu/GrAppliedClip.h b/src/gpu/GrAppliedClip.h
new file mode 100644
index 0000000000..c02e9d01c2
--- /dev/null
+++ b/src/gpu/GrAppliedClip.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrAppliedClip_DEFINED
+#define GrAppliedClip_DEFINED
+
+#include "GrTypesPriv.h"
+#include "GrWindowRectangles.h"
+
+class GrFragmentProcessor;
+
+/**
+ * Produced by GrClip. It provides a set of modifications to the drawing state that are used to
+ * create the final GrPipeline for a GrBatch.
+ */
+class GrAppliedClip : public SkNoncopyable {
+public:
+ GrAppliedClip(const SkRect& drawBounds)
+ : fHasStencilClip(false)
+ , fClippedDrawBounds(drawBounds) {
+ }
+
+ const GrScissorState& scissorState() const { return fScissorState; }
+ const GrWindowRectangles& windowRects() const { return fWindowRects; }
+ GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP.get(); }
+ bool hasStencilClip() const { return fHasStencilClip; }
+
+ /**
+ * Intersects the applied clip with the provided rect. Returns false if the draw became empty.
+ */
+ bool addScissor(const SkIRect& irect) {
+ return fScissorState.intersect(irect) && fClippedDrawBounds.intersect(SkRect::Make(irect));
+ }
+
+ /**
+ * Adds an exclusive window rectangle to the clip. It is not currently supported to switch the
+ * windows to inclusive mode.
+ */
+ void addWindowRectangle(const SkIRect& window) {
+ fWindowRects.addWindow(window);
+ }
+
+ void addCoverageFP(sk_sp<GrFragmentProcessor> fp) {
+ SkASSERT(!fClipCoverageFP);
+ fClipCoverageFP = fp;
+ }
+
+ void addStencilClip() {
+ SkASSERT(!fHasStencilClip);
+ fHasStencilClip = true;
+ }
+
+ /**
+ * Returns the device bounds of the draw after clip has been applied. TODO: Ideally this would
+ * consider the combined effect of all clipping techniques in play (scissor, stencil, fp, etc.).
+ */
+ const SkRect& clippedDrawBounds() const { return fClippedDrawBounds; }
+
+private:
+ GrScissorState fScissorState;
+ GrWindowRectangles fWindowRects;
+ sk_sp<GrFragmentProcessor> fClipCoverageFP;
+ bool fHasStencilClip;
+ SkRect fClippedDrawBounds;
+ typedef SkNoncopyable INHERITED;
+};
+
+#endif
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 19ef38c49d..622c6855fa 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -7,6 +7,7 @@
#include "GrCaps.h"
#include "GrContextOptions.h"
+#include "GrWindowRectangles.h"
GrShaderCaps::GrShaderCaps() {
fShaderDerivativeSupport = false;
@@ -131,6 +132,7 @@ GrCaps::GrCaps(const GrContextOptions& options) {
}
void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
+ this->onApplyOptionsOverrides(options);
fMaxTextureSize = SkTMin(fMaxTextureSize, options.fMaxTextureSizeOverride);
// If the max tile override is zero, it means we should use the max texture size.
if (!options.fMaxTileSizeOverride || options.fMaxTileSizeOverride > fMaxTextureSize) {
@@ -138,7 +140,9 @@ void GrCaps::applyOptionsOverrides(const GrContextOptions& options) {
} else {
fMaxTileSize = options.fMaxTileSizeOverride;
}
- this->onApplyOptionsOverrides(options);
+ if (fMaxWindowRectangles > GrWindowRectangles::kMaxWindows) {
+ fMaxWindowRectangles = GrWindowRectangles::kMaxWindows;
+ }
}
static SkString map_flags_to_string(uint32_t flags) {
diff --git a/src/gpu/GrClip.cpp b/src/gpu/GrClip.cpp
index ef9c9cdfa6..f89a366963 100644
--- a/src/gpu/GrClip.cpp
+++ b/src/gpu/GrClip.cpp
@@ -7,6 +7,7 @@
#include "GrClip.h"
+#include "GrAppliedClip.h"
#include "GrDrawContext.h"
void GrNoClip::getConservativeBounds(int width, int height, SkIRect* devResult,
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index 0d6270f8d0..975f56a757 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -7,9 +7,11 @@
#include "GrClipStackClip.h"
+#include "GrAppliedClip.h"
#include "GrDrawingManager.h"
#include "GrDrawContextPriv.h"
#include "GrGpuResourcePriv.h"
+#include "GrRenderTargetPriv.h"
#include "GrStencilAttachment.h"
#include "GrSWMaskHelper.h"
#include "effects/GrConvexPolyEffect.h"
@@ -280,6 +282,23 @@ bool GrClipStackClip::apply(GrContext* context, GrDrawContext* drawContext, bool
SkASSERT(reducedClip.hasIBounds());
+ // Attempt to implement difference clip rects with window rectangles. This will eventually
+ // become more comprehensive.
+ if (drawContext->accessRenderTarget()->renderTargetPriv().supportsWindowRectangles() &&
+ 1 == reducedClip.elements().count() && !reducedClip.requiresAA() &&
+ InitialState::kAllIn == reducedClip.initialState()) {
+ const Element* element = reducedClip.elements().head();
+ SkRegion::Op op = element->getOp();
+ if (Element::kRect_Type == element->getType() &&
+ (SkRegion::kDifference_Op == op || SkRegion::kXOR_Op == op)) {
+ SkIRect window;
+ element->getRect().round(&window);
+ window.offset(-fOrigin);
+ out->addWindowRectangle(window);
+ return true;
+ }
+ }
+
// An element count of 4 was chosen because of the common pattern in Blink of:
// isect RR
// diff RR
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index b4142eb40b..1889b87133 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -7,6 +7,7 @@
#include "GrDrawTarget.h"
+#include "GrAppliedClip.h"
#include "GrAuditTrail.h"
#include "GrCaps.h"
#include "GrDrawContext.h"
@@ -379,6 +380,7 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
sk_sp_address_as_pointer_address(pipelineBuilder.fCoverageFragmentProcessors.begin()),
pipelineBuilder.numCoverageFragmentProcessors());
args.fScissor = &appliedClip.scissorState();
+ args.fWindowRects = &appliedClip.windowRects();
args.fHasStencilClip = appliedClip.hasStencilClip();
if (!this->setupDstReadIfNecessary(pipelineBuilder, drawContext->accessRenderTarget(),
clip, args.fOpts,
diff --git a/src/gpu/GrNonAtomicRef.h b/src/gpu/GrNonAtomicRef.h
index e1503bcf06..c23637f467 100644
--- a/src/gpu/GrNonAtomicRef.h
+++ b/src/gpu/GrNonAtomicRef.h
@@ -28,6 +28,8 @@ public:
}
#endif
+ bool unique() const { return 1 == fRefCnt; }
+
void ref() const {
// Once the ref cnt reaches zero it should never be ref'ed again.
SkASSERT(fRefCnt > 0);
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index c60a94be7e..8fe321d667 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -27,6 +27,7 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
pipeline->fRenderTarget.reset(rt);
SkASSERT(pipeline->fRenderTarget);
pipeline->fScissorState = *args.fScissor;
+ pipeline->fWindowRects = *args.fWindowRects;
if (builder.hasUserStencilSettings() || args.fHasStencilClip) {
const GrRenderTargetPriv& rtPriv = rt->renderTargetPriv();
pipeline->fStencilSettings.reset(*builder.getUserStencil(), args.fHasStencilClip,
@@ -229,6 +230,7 @@ bool GrPipeline::AreEqual(const GrPipeline& a, const GrPipeline& b,
a.fFragmentProcessors.count() != b.fFragmentProcessors.count() ||
a.fNumColorProcessors != b.fNumColorProcessors ||
a.fScissorState != b.fScissorState ||
+ a.fWindowRects != b.fWindowRects ||
a.fFlags != b.fFlags ||
a.fStencilSettings != b.fStencilSettings ||
a.fDrawFace != b.fDrawFace ||
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 1457dbc3f5..18f1a2a266 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -18,6 +18,7 @@
#include "GrProgramDesc.h"
#include "GrStencilSettings.h"
#include "GrTypesPriv.h"
+#include "GrWindowRectangles.h"
#include "SkMatrix.h"
#include "SkRefCnt.h"
@@ -59,6 +60,7 @@ public:
const GrCaps* fCaps;
GrPipelineOptimizations fOpts;
const GrScissorState* fScissor;
+ const GrWindowRectangles* fWindowRects;
bool fHasStencilClip;
GrXferProcessor::DstTexture fDstTexture;
};
@@ -152,6 +154,8 @@ public:
const GrScissorState& getScissorState() const { return fScissorState; }
+ const GrWindowRectangles& getWindowRectangles() const { return fWindowRects; }
+
bool isHWAntialiasState() const { return SkToBool(fFlags & kHWAA_Flag); }
bool snapVerticesToPixelCenters() const { return SkToBool(fFlags & kSnapVertices_Flag); }
bool getDisableOutputConversionToSRGB() const {
@@ -219,6 +223,7 @@ private:
typedef GrPendingProgramElement<const GrXferProcessor> ProgramXferProcessor;
RenderTarget fRenderTarget;
GrScissorState fScissorState;
+ GrWindowRectangles fWindowRects;
GrStencilSettings fStencilSettings;
GrDrawFace fDrawFace;
uint32_t fFlags;
diff --git a/src/gpu/GrWindowRectangles.h b/src/gpu/GrWindowRectangles.h
new file mode 100644
index 0000000000..682af9353d
--- /dev/null
+++ b/src/gpu/GrWindowRectangles.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrWindowRectangles_DEFINED
+#define GrWindowRectangles_DEFINED
+
+#include "GrNonAtomicRef.h"
+#include "SkRect.h"
+
+class GrWindowRectangles {
+public:
+ constexpr static int kMaxWindows = 16;
+
+ enum class Mode : bool {
+ kExclusive,
+ kInclusive
+ };
+
+ GrWindowRectangles(Mode mode = Mode::kExclusive) : fMode(mode), fCount(0) {}
+ GrWindowRectangles(const GrWindowRectangles& that) : fCount(0) { *this = that; }
+ ~GrWindowRectangles() { SkSafeUnref(this->rec()); }
+
+ Mode mode() const { return fMode; }
+ uint16_t count() const { return fCount; }
+ bool disabled() const { return Mode::kExclusive == fMode && !fCount; }
+ const SkIRect* data() const;
+
+ void reset(Mode = Mode::kExclusive);
+ GrWindowRectangles& operator=(const GrWindowRectangles&);
+
+ SkIRect& addWindow(const SkIRect& window) { return this->addWindow() = window; }
+ SkIRect& addWindow();
+
+ bool operator!=(const GrWindowRectangles& that) const { return !(*this == that); }
+ bool operator==(const GrWindowRectangles&) const;
+
+private:
+ constexpr static int kNumLocalWindows = 1;
+ struct Rec;
+
+ const Rec* rec() const { return fCount <= kNumLocalWindows ? nullptr : fRec; }
+
+ Mode fMode;
+ uint8_t fCount;
+ union {
+ SkIRect fLocalWindows[kNumLocalWindows]; // If fCount <= kNumLocalWindows.
+ Rec* fRec; // If fCount > kNumLocalWindows.
+ };
+};
+
+struct GrWindowRectangles::Rec : public GrNonAtomicRef<Rec> {
+ Rec(const SkIRect* windows, int numWindows) {
+ SkASSERT(numWindows < kMaxWindows);
+ memcpy(fData, windows, sizeof(SkIRect) * numWindows);
+ }
+
+ SkIRect fData[kMaxWindows];
+};
+
+inline const SkIRect* GrWindowRectangles::data() const {
+ return fCount <= kNumLocalWindows ? fLocalWindows : fRec->fData;
+}
+
+inline void GrWindowRectangles::reset(Mode mode) {
+ SkSafeUnref(this->rec());
+ fMode = mode;
+ fCount = 0;
+}
+
+inline GrWindowRectangles& GrWindowRectangles::operator=(const GrWindowRectangles& that) {
+ SkSafeUnref(this->rec());
+ fMode = that.fMode;
+ fCount = that.fCount;
+ if (fCount <= kNumLocalWindows) {
+ memcpy(fLocalWindows, that.fLocalWindows, fCount * sizeof(SkIRect));
+ } else {
+ fRec = SkRef(that.fRec);
+ }
+ return *this;
+}
+
+inline SkIRect& GrWindowRectangles::addWindow() {
+ SkASSERT(fCount < kMaxWindows);
+ if (fCount < kNumLocalWindows) {
+ return fLocalWindows[fCount++];
+ }
+ if (fCount == kNumLocalWindows) {
+ fRec = new Rec(fLocalWindows, kNumLocalWindows);
+ } else if (!fRec->unique()) { // Simple copy-on-write.
+ fRec->unref();
+ fRec = new Rec(fRec->fData, fCount);
+ }
+ return fRec->fData[fCount++];
+}
+
+inline bool GrWindowRectangles::operator==(const GrWindowRectangles& that) const {
+ if (fMode != that.fMode || fCount != that.fCount) {
+ return false;
+ }
+ if (fCount > kNumLocalWindows && fRec == that.fRec) {
+ return true;
+ }
+ return !fCount || !memcmp(this->data(), that.data(), sizeof(SkIRect) * fCount);
+}
+
+#endif
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 4d856ac932..75ae776879 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -463,8 +463,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
if (ctxInfo.hasExtension("GL_EXT_window_rectangles")) {
GR_GL_GetIntegerv(gli, GR_GL_MAX_WINDOW_RECTANGLES, &fMaxWindowRectangles);
- // Protect ourselves against tracking huge amounts of window rectangle state.
- fMaxWindowRectangles = SkTMin(31, fMaxWindowRectangles);
}
if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer() ||
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 1300bb7a03..3e44138328 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -563,6 +563,7 @@ void GrGLGpu::onResetContext(uint32_t resetBits) {
if (resetBits & kView_GrGLBackendState) {
fHWScissorSettings.invalidate();
+ fHWWindowRects.invalidate();
fHWViewport.invalidate();
}
@@ -1995,6 +1996,37 @@ void GrGLGpu::flushScissor(const GrScissorState& scissorState,
this->disableScissor();
}
+void GrGLGpu::flushWindowRectangles(const GrWindowRectangles& windows, const GrGLRenderTarget* rt) {
+ typedef GrWindowRectangles::Mode Mode;
+ SkASSERT(windows.count() <= this->caps()->maxWindowRectangles());
+ SkASSERT(windows.disabled() || rt->renderFBOID()); // Window rectangles can't be used on-screen.
+
+ if (!this->caps()->maxWindowRectangles() ||
+ fHWWindowRects.equal(rt->origin(), rt->getViewport(), windows)) {
+ return;
+
+ }
+
+ GrGLIRect glwindows[GrWindowRectangles::kMaxWindows];
+ const SkIRect* skwindows = windows.data();
+ for (int i = 0; i < windows.count(); ++i) {
+ glwindows[i].setRelativeTo(rt->getViewport(), skwindows[i], rt->origin());
+ }
+
+ GrGLenum glmode = (Mode::kExclusive == windows.mode()) ? GR_GL_EXCLUSIVE : GR_GL_INCLUSIVE;
+ GL_CALL(WindowRectangles(glmode, windows.count(), glwindows->asInts()));
+
+ fHWWindowRects.set(rt->origin(), rt->getViewport(), windows);
+}
+
+void GrGLGpu::disableWindowRectangles() {
+ if (!this->caps()->maxWindowRectangles() || fHWWindowRects.disabled()) {
+ return;
+ }
+ GL_CALL(WindowRectangles(GR_GL_EXCLUSIVE, 0, nullptr));
+ fHWWindowRects.setDisabled();
+}
+
void GrGLGpu::flushMinSampleShading(float minSampleShading) {
if (fHWMinSampleShading != minSampleShading) {
if (minSampleShading > 0.0) {
@@ -2042,6 +2074,7 @@ bool GrGLGpu::flushGLState(const GrPipeline& pipeline, const GrPrimitiveProcesso
GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
this->flushStencil(pipeline.getStencil());
this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin());
+ this->flushWindowRectangles(pipeline.getWindowRectangles(), glRT);
this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled());
// This must come after textures are flushed because a texture may need
@@ -2171,6 +2204,7 @@ void GrGLGpu::clear(const SkIRect& rect, GrColor color, GrRenderTarget* target)
GrScissorState scissorState;
scissorState.set(rect);
this->flushScissor(scissorState, glRT->getViewport(), glRT->origin());
+ this->disableWindowRectangles();
GrGLfloat r, g, b, a;
static const GrGLfloat scale255 = 1.f / 255.f;
@@ -2194,6 +2228,7 @@ void GrGLGpu::clearStencil(GrRenderTarget* target) {
this->flushRenderTarget(glRT, &SkIRect::EmptyIRect());
this->disableScissor();
+ this->disableWindowRectangles();
GL_CALL(StencilMask(0xffffffff));
GL_CALL(ClearStencil(0));
@@ -2233,6 +2268,7 @@ void GrGLGpu::clearStencilClip(const SkIRect& rect, bool insideClip, GrRenderTar
GrScissorState scissorState;
scissorState.set(rect);
this->flushScissor(scissorState, glRT->getViewport(), glRT->origin());
+ this->disableWindowRectangles();
GL_CALL(StencilMask((uint32_t) clipStencilMask));
GL_CALL(ClearStencil(value));
@@ -2603,6 +2639,7 @@ void GrGLGpu::finishDrawTarget() {
* it becomes safe to stop using this workaround once we start.
*/
this->disableScissor();
+ this->disableWindowRectangles();
// using PLS in the presence of MSAA results in GL_INVALID_OPERATION
this->flushHWAAState(nullptr, false, false);
SkASSERT(!fHWPLSEnabled);
@@ -2752,6 +2789,7 @@ void GrGLGpu::draw(const GrPipeline& pipeline,
GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE));
fHWPLSEnabled = false;
this->disableScissor();
+ this->disableWindowRectangles();
}
#if SWAP_PER_DRAW
@@ -2848,6 +2886,7 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) {
GrScissorState scissorState;
scissorState.set(dirtyRect);
this->flushScissor(scissorState, vp, rt->origin());
+ this->disableWindowRectangles();
GL_CALL(ResolveMultisampleFramebuffer());
} else {
GrGLIRect r;
@@ -2859,6 +2898,7 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) {
// BlitFrameBuffer respects the scissor, so disable it.
this->disableScissor();
+ this->disableWindowRectangles();
GL_CALL(BlitFramebuffer(r.fLeft, r.fBottom, right, top,
r.fLeft, r.fBottom, right, top,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
@@ -4091,6 +4131,7 @@ void GrGLGpu::drawDebugWireRect(GrRenderTarget* rt, const SkIRect& rect, GrColor
this->flushDrawFace(GrDrawFace::kBoth);
this->flushHWAAState(glRT, false, false);
this->disableScissor();
+ this->disableWindowRectangles();
GrStencilSettings stencil;
stencil.setDisabled();
this->flushStencil(stencil);
@@ -4179,6 +4220,7 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
this->flushDrawFace(GrDrawFace::kBoth);
this->flushHWAAState(nullptr, false, false);
this->disableScissor();
+ this->disableWindowRectangles();
GrStencilSettings stencil;
stencil.setDisabled();
this->flushStencil(stencil);
@@ -4263,6 +4305,7 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst,
// BlitFrameBuffer respects the scissor, so disable it.
this->disableScissor();
+ this->disableWindowRectangles();
GrGLint srcY0;
GrGLint srcY1;
@@ -4387,6 +4430,7 @@ bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) {
this->flushDrawFace(GrDrawFace::kBoth);
this->flushHWAAState(nullptr, false, false);
this->disableScissor();
+ this->disableWindowRectangles();
GrStencilSettings stencil;
stencil.setDisabled();
this->flushStencil(stencil);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 0356352529..26c9588fcc 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -314,6 +314,9 @@ private:
// disables the scissor
void disableScissor();
+ void flushWindowRectangles(const GrWindowRectangles&, const GrGLRenderTarget*);
+ void disableWindowRectangles();
+
void initFSAASupport();
// determines valid stencil formats
@@ -419,6 +422,42 @@ private:
}
} fHWScissorSettings;
+ class {
+ public:
+ bool valid() const { return kInvalidOrigin != fOrigin; }
+ void invalidate() { fOrigin = kInvalidOrigin; }
+
+ bool disabled() const {
+ return this->valid() && Mode::kExclusive == fWindows.mode() && !fWindows.count();
+ }
+ void setDisabled() { fOrigin = kDefault_GrSurfaceOrigin, fWindows.reset(); }
+
+ bool equal(GrSurfaceOrigin org, const GrGLIRect& viewp,
+ const GrWindowRectangles& windows) const {
+ if (!this->valid()) {
+ return false;
+ }
+ if (fWindows.count() && (fOrigin != org || fViewport != viewp)) {
+ return false;
+ }
+ return fWindows == windows;
+ }
+
+ void set(GrSurfaceOrigin org, const GrGLIRect& viewp, const GrWindowRectangles& windows) {
+ fOrigin = org;
+ fViewport = viewp;
+ fWindows = windows;
+ }
+
+ private:
+ typedef GrWindowRectangles::Mode Mode;
+ enum { kInvalidOrigin = -1 };
+
+ int fOrigin;
+ GrGLIRect fViewport;
+ GrWindowRectangles fWindows;
+ } fHWWindowRects;
+
GrGLIRect fHWViewport;
/**
diff --git a/src/gpu/gl/GrGLIRect.h b/src/gpu/gl/GrGLIRect.h
index 41ac13b753..a699ae36bd 100644
--- a/src/gpu/gl/GrGLIRect.h
+++ b/src/gpu/gl/GrGLIRect.h
@@ -23,6 +23,20 @@ struct GrGLIRect {
GrGLsizei fWidth;
GrGLsizei fHeight;
+ /**
+ * cast-safe way to treat the rect as an array of (4) ints.
+ */
+ const int* asInts() const {
+ return &fLeft;
+
+ GR_STATIC_ASSERT(0 == offsetof(GrGLIRect, fLeft));
+ GR_STATIC_ASSERT(4 == offsetof(GrGLIRect, fBottom));
+ GR_STATIC_ASSERT(8 == offsetof(GrGLIRect, fWidth));
+ GR_STATIC_ASSERT(12 == offsetof(GrGLIRect, fHeight));
+ GR_STATIC_ASSERT(16 == sizeof(GrGLIRect)); // For an array of GrGLIRect.
+ }
+ int* asInts() { return &fLeft; }
+
void pushToGLViewport(const GrGLInterface* gl) const {
GR_GL_CALL(gl, Viewport(fLeft, fBottom, fWidth, fHeight));
}
@@ -39,6 +53,11 @@ struct GrGLIRect {
// sometimes we have a SkIRect from the client that we
// want to simultaneously make relative to GL's viewport
// and (optionally) convert from top-down to bottom-up.
+ void setRelativeTo(const GrGLIRect& glViewport, const SkIRect& devRect, GrSurfaceOrigin org) {
+ this->setRelativeTo(glViewport, devRect.x(), devRect.y(), devRect.width(), devRect.height(),
+ org);
+ }
+
void setRelativeTo(const GrGLIRect& glRect,
int leftOffset,
int topOffset,
diff --git a/tests/WindowRectanglesTest.cpp b/tests/WindowRectanglesTest.cpp
new file mode 100644
index 0000000000..d569f1d7aa
--- /dev/null
+++ b/tests/WindowRectanglesTest.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrWindowRectangles.h"
+
+static SkIRect next_irect(SkRandom& r) {
+ return {r.nextS(), r.nextS(), r.nextS(), r.nextS()};
+}
+
+DEF_TEST(WindowRectangles, reporter) {
+ SkRandom r;
+
+ SkIRect windowData[GrWindowRectangles::kMaxWindows];
+ for (int i = 0; i < GrWindowRectangles::kMaxWindows; ++i) {
+ windowData[i] = next_irect(r);
+ }
+
+ GrWindowRectangles wr;
+ for (int i = 0; i < GrWindowRectangles::kMaxWindows - 1; ++i) {
+ REPORTER_ASSERT(reporter, wr.count() == i);
+ REPORTER_ASSERT(reporter, !memcmp(wr.data(), windowData, i * sizeof(SkIRect)));
+
+ GrWindowRectangles wr2(wr);
+ REPORTER_ASSERT(reporter, wr2 == wr);
+ REPORTER_ASSERT(reporter, wr2.mode() == wr.mode());
+ REPORTER_ASSERT(reporter, wr2.count() == wr.count());
+ REPORTER_ASSERT(reporter, !memcmp(wr2.data(), wr.data(), i * sizeof(SkIRect)));
+
+ wr.addWindow(windowData[i]);
+ }
+
+ SkASSERT(wr.count() == GrWindowRectangles::kMaxWindows - 1);
+ {
+ GrWindowRectangles A(wr), B(wr);
+ REPORTER_ASSERT(reporter, B == A);
+ REPORTER_ASSERT(reporter, B.data() == A.data()); // Should use copy-on-write.
+
+ A.addWindow(windowData[GrWindowRectangles::kMaxWindows - 1]);
+ REPORTER_ASSERT(reporter, B.data() != A.data());
+ REPORTER_ASSERT(reporter, B != A);
+
+ B.addWindow(SkIRect::MakeLargest());
+ REPORTER_ASSERT(reporter, B != A);
+
+ REPORTER_ASSERT(reporter, !memcmp(A.data(), windowData,
+ GrWindowRectangles::kMaxWindows * sizeof(SkIRect)));
+ REPORTER_ASSERT(reporter, !memcmp(B.data(), windowData,
+ (GrWindowRectangles::kMaxWindows - 1) * sizeof(SkIRect)));
+ REPORTER_ASSERT(reporter,
+ B.data()[GrWindowRectangles::kMaxWindows - 1] == SkIRect::MakeLargest());
+ }
+ {
+ GrWindowRectangles A(wr), B(wr);
+ REPORTER_ASSERT(reporter, B == A);
+ REPORTER_ASSERT(reporter, B.data() == A.data()); // Should use copy-on-write.
+
+ A.addWindow(windowData[GrWindowRectangles::kMaxWindows - 1]);
+ B.addWindow(windowData[GrWindowRectangles::kMaxWindows - 1]);
+ REPORTER_ASSERT(reporter, B == A);
+ REPORTER_ASSERT(reporter, B.data() != A.data());
+ REPORTER_ASSERT(reporter, !memcmp(B.data(), A.data(),
+ GrWindowRectangles::kMaxWindows * sizeof(SkIRect)));
+ REPORTER_ASSERT(reporter, !memcmp(A.data(), windowData,
+ GrWindowRectangles::kMaxWindows * sizeof(SkIRect)));
+ }
+
+ GrWindowRectangles wrI(GrWindowRectangles::Mode::kInclusive);
+ for (int i = 0; i < wr.count(); ++i) {
+ wrI.addWindow(windowData[i]);
+ }
+ REPORTER_ASSERT(reporter, wrI != wr);
+ REPORTER_ASSERT(reporter, wrI.mode() != wr.mode());
+ REPORTER_ASSERT(reporter, wrI.count() == wr.count());
+ REPORTER_ASSERT(reporter, !memcmp(wrI.data(), wr.data(), wr.count() * sizeof(SkIRect)));
+
+ wr.reset(GrWindowRectangles::Mode::kInclusive);
+ for (int i = 0; i < wrI.count(); ++i) {
+ wr.addWindow(windowData[i]);
+ }
+ REPORTER_ASSERT(reporter, wrI == wr);
+}
+
+#endif