diff options
author | 2016-08-17 10:00:21 -0700 | |
---|---|---|
committer | 2016-08-17 10:00:22 -0700 | |
commit | 28341fad8438b294ed7311edbc68d8cb34a990ab (patch) | |
tree | 7f4573e0cbf2c58c8e44496bf3b1e5136f6f3702 | |
parent | 8d3f92a92be713cedfee48e01987264bd4f3083f (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.gypi | 2 | ||||
-rw-r--r-- | include/gpu/GrClip.h | 47 | ||||
-rw-r--r-- | src/gpu/GrAppliedClip.h | 72 | ||||
-rw-r--r-- | src/gpu/GrCaps.cpp | 6 | ||||
-rw-r--r-- | src/gpu/GrClip.cpp | 1 | ||||
-rw-r--r-- | src/gpu/GrClipStackClip.cpp | 19 | ||||
-rw-r--r-- | src/gpu/GrDrawTarget.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrNonAtomicRef.h | 2 | ||||
-rw-r--r-- | src/gpu/GrPipeline.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrPipeline.h | 5 | ||||
-rw-r--r-- | src/gpu/GrWindowRectangles.h | 110 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 44 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 39 | ||||
-rw-r--r-- | src/gpu/gl/GrGLIRect.h | 19 | ||||
-rw-r--r-- | tests/WindowRectanglesTest.cpp | 92 |
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 |