From edab002cc796c23ce9046d751ec3aaf3ebfa593e Mon Sep 17 00:00:00 2001 From: John Cooper Date: Thu, 13 Jun 2024 10:54:33 -0700 Subject: [PATCH] optimization to improve the cases where we can get opengl to render a single textured quad if there's a single rectangle cutout of an image that needs repainting --- .../native/juce_RenderingHelpers.h | 20 +++++++++++ .../opengl/juce_OpenGLGraphicsContext.cpp | 35 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/modules/juce_graphics/native/juce_RenderingHelpers.h b/modules/juce_graphics/native/juce_RenderingHelpers.h index a38c53934af2..b6ba099d47c7 100644 --- a/modules/juce_graphics/native/juce_RenderingHelpers.h +++ b/modules/juce_graphics/native/juce_RenderingHelpers.h @@ -1553,6 +1553,12 @@ namespace ClipRegions virtual Ptr clipToImageAlpha (const Image&, const AffineTransform&, Graphics::ResamplingQuality) = 0; virtual void translate (Point delta) = 0; + // Check whether the supplied rectangle can be drawn clipped inside a single + // rectangle. + // Pessimistic check; only used for optimization - returning false is always + // a correct choice, though it might lead to a slower path in the rasterizer. + virtual bool trimRectangularClip(Rectangle requestedDrawRect, Rectangle& trimmedDrawRect) const = 0; + virtual bool clipRegionIntersects (Rectangle) const = 0; virtual Rectangle getClipBounds() const = 0; @@ -1669,6 +1675,11 @@ namespace ClipRegions edgeTable.translate ((float) delta.x, delta.y); } + bool trimRectangularClip(Rectangle, Rectangle&) const override + { + return false; + } + bool clipRegionIntersects (Rectangle r) const override { return edgeTable.getMaximumBounds().intersects (r); @@ -1793,6 +1804,15 @@ namespace ClipRegions bool clipRegionIntersects (Rectangle r) const override { return clip.intersects (r); } Rectangle getClipBounds() const override { return clip.getBounds(); } + bool trimRectangularClip(Rectangle requestedDrawRect, Rectangle& trimmedDrawRect) const override + { + if (clip.getNumRectangles() != 1) return false; + + Rectangle rect = clip.getRectangle(0); + trimmedDrawRect = rect.getIntersection(requestedDrawRect); + return !trimmedDrawRect.isEmpty(); + } + void fillRectWithColour (SavedStateType& state, Rectangle area, PixelARGB colour, bool replaceContents) const override { SubRectangleIterator iter (clip, area); diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp index a55bdd592f8b..d0858b2404d9 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp @@ -1713,6 +1713,41 @@ struct SavedState final : public RenderingHelpers::SavedStateBase previousTarget (createCopyIfNotNull (other.previousTarget.get())) {} + void drawImage (const Image& sourceImage, const AffineTransform& trans) + { + auto t = transform.getTransformWith (trans); + auto alpha = fillType.colour.getAlpha(); + + // If we're only translating, and if the target image can be drawn with a + // clip that can be reduced to a single rectangle, we can just add a single + // quad to the queue and dispatch a draw call. + if (isOnlyTranslationAllowingError (t, 0.002f)) + { + auto targetRect = Rectangle{ + (int)t.getTranslationX(), + (int)t.getTranslationY(), + sourceImage.getWidth(), + sourceImage.getHeight(), + }; + Rectangle trimmedTargetRect; + + if (clip->trimRectangularClip(targetRect, trimmedTargetRect)) + { + state->shaderQuadQueue.flush(); + state->setShaderForTiledImageFill (state->cachedImageList->getTextureFor (sourceImage), t, 0, nullptr, false); + + state->shaderQuadQueue.add (trimmedTargetRect, PixelARGB ((uint8) alpha, (uint8) alpha, (uint8) alpha, (uint8) alpha)); + state->shaderQuadQueue.flush(); + + state->currentShader.clearShader (state->shaderQuadQueue); + + return; + } + } + + BaseClass::drawImage(sourceImage, trans); + } + SavedState* beginTransparencyLayer (float opacity) { auto* s = new SavedState (*this);