From 243d3756fcf70ca574b996a01ccfcefc2007f6a9 Mon Sep 17 00:00:00 2001 From: reuk Date: Thu, 17 Apr 2025 15:01:16 +0100 Subject: [PATCH] Direct2D: Hide implementation of RectangleListSpriteBatch::fillRectangles --- .../native/juce_DirectX_windows.cpp | 102 ++++++++++++++++ .../native/juce_DirectX_windows.h | 110 +++--------------- 2 files changed, 120 insertions(+), 92 deletions(-) diff --git a/modules/juce_graphics/native/juce_DirectX_windows.cpp b/modules/juce_graphics/native/juce_DirectX_windows.cpp index 8961ad4333..e8f507947f 100644 --- a/modules/juce_graphics/native/juce_DirectX_windows.cpp +++ b/modules/juce_graphics/native/juce_DirectX_windows.cpp @@ -496,6 +496,108 @@ ComSmartPtr RectangleListSpriteBatch::getSpriteBatch (ID2D1Dev }); } +bool RectangleListSpriteBatch::fillRectanglesImpl (ComSmartPtr deviceContext, + const RectangleList& rectangles, + const Colour colour, + const TransformCallback& transformRectangle, + [[maybe_unused]] Direct2DMetrics* metrics) +{ + if (rectangles.isEmpty()) + return true; + + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, spriteBatchTime) + + auto numRectanglesPainted = 0; + while (numRectanglesPainted < rectangles.getNumRectangles()) + { + auto numRectanglesRemaining = rectangles.getNumRectangles() - numRectanglesPainted; + auto spriteBatchSize = isPowerOfTwo (numRectanglesRemaining) ? numRectanglesRemaining : (nextPowerOfTwo (numRectanglesRemaining) >> 1); + + { + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, spriteBatchSetupTime); + + if (destinationsCapacity < (size_t) spriteBatchSize) + { + destinations.calloc (spriteBatchSize); + destinationsCapacity = (size_t) spriteBatchSize; + } + + auto destination = destinations.getData(); + + for (int i = numRectanglesPainted; i < numRectanglesPainted + spriteBatchSize; ++i) + { + auto r = rectangles.getRectangle (i); + r = transformRectangle.transform (r); + + if (r.getWidth() < 1.0f || r.getHeight() < 1.0f) + return false; + + *destination = D2DUtilities::toRECT_F (r); + ++destination; + } + } + + if (! whiteRectangle) + { + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, createSpriteSourceTime); + + auto hr = deviceContext->CreateCompatibleRenderTarget (D2D1_SIZE_F { (float) rectangleSize, (float) rectangleSize }, + D2D1_SIZE_U { rectangleSize, rectangleSize }, + D2D1_PIXEL_FORMAT { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED }, + whiteRectangle.resetAndGetPointerAddress()); + if (FAILED (hr)) + return false; + + whiteRectangle->BeginDraw(); + whiteRectangle->Clear (D2D1_COLOR_F { 1.0f, 1.0f, 1.0f, 1.0f }); + whiteRectangle->EndDraw(); + } + + ComSmartPtr bitmap; + + if (auto hr = whiteRectangle->GetBitmap (bitmap.resetAndGetPointerAddress()); SUCCEEDED (hr)) + { + ComSmartPtr deviceContext3; + + if (hr = deviceContext->QueryInterface (deviceContext3.resetAndGetPointerAddress()); SUCCEEDED (hr)) + { + auto d2dColour = D2DUtilities::toCOLOR_F (colour); + auto spriteBatch = getSpriteBatch (*deviceContext3, (uint32) spriteBatchSize); + + if (spriteBatch == nullptr) + return false; + + auto setCount = jmin ((uint32) spriteBatchSize, spriteBatch->GetSpriteCount()); + auto addCount = (uint32) spriteBatchSize > setCount ? (uint32) spriteBatchSize - setCount : 0; + + if (setCount != 0) + { + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, setSpritesTime); + + spriteBatch->SetSprites (0, setCount, destinations.getData(), nullptr, &d2dColour, nullptr, sizeof (D2D1_RECT_F), 0, 0, 0); + } + + if (addCount != 0) + { + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, addSpritesTime); + + spriteBatch->AddSprites (addCount, destinations.getData() + setCount, nullptr, &d2dColour, nullptr, sizeof (D2D1_RECT_F), 0, 0, 0); + } + + JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, drawSpritesTime); + + deviceContext3->SetAntialiasMode (D2D1_ANTIALIAS_MODE_ALIASED); + deviceContext3->DrawSpriteBatch (spriteBatch, bitmap); + deviceContext3->SetAntialiasMode (D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + } + } + + numRectanglesPainted += spriteBatchSize; + } + + return true; +} + //============================================================================== DxgiAdapter::Ptr Direct2DDeviceResources::findAdapter (const DxgiAdapters& adapters, ID2D1Bitmap1* bitmap) diff --git a/modules/juce_graphics/native/juce_DirectX_windows.h b/modules/juce_graphics/native/juce_DirectX_windows.h index b3828ac92c..c7c35847fd 100644 --- a/modules/juce_graphics/native/juce_DirectX_windows.h +++ b/modules/juce_graphics/native/juce_DirectX_windows.h @@ -268,6 +268,11 @@ private: class RectangleListSpriteBatch { + struct TransformCallback + { + virtual Rectangle transform (Rectangle) const = 0; + }; + public: RectangleListSpriteBatch() = default; @@ -282,105 +287,26 @@ public: TransformRectangle&& transformRectangle, [[maybe_unused]] Direct2DMetrics* metrics) { - if (rectangles.isEmpty()) - return true; - - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, spriteBatchTime) - - auto numRectanglesPainted = 0; - while (numRectanglesPainted < rectangles.getNumRectangles()) + struct Callback : public TransformCallback { - auto numRectanglesRemaining = rectangles.getNumRectangles() - numRectanglesPainted; - auto spriteBatchSize = isPowerOfTwo (numRectanglesRemaining) ? numRectanglesRemaining : (nextPowerOfTwo (numRectanglesRemaining) >> 1); + explicit Callback (TransformRectangle&& x) : fn (x) {} + Rectangle transform (Rectangle x) const override { return fn (x); } + TransformRectangle fn; + }; - { - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, spriteBatchSetupTime); - - if (destinationsCapacity < (size_t) spriteBatchSize) - { - destinations.calloc (spriteBatchSize); - destinationsCapacity = (size_t) spriteBatchSize; - } - - auto destination = destinations.getData(); - - for (int i = numRectanglesPainted; i < numRectanglesPainted + spriteBatchSize; ++i) - { - auto r = rectangles.getRectangle (i); - r = transformRectangle (r); - - if (r.getWidth() < 1.0f || r.getHeight() < 1.0f) - return false; - - *destination = D2DUtilities::toRECT_F (r); - ++destination; - } - } - - if (! whiteRectangle) - { - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, createSpriteSourceTime); - - auto hr = deviceContext->CreateCompatibleRenderTarget (D2D1_SIZE_F { (float) rectangleSize, (float) rectangleSize }, - D2D1_SIZE_U { rectangleSize, rectangleSize }, - D2D1_PIXEL_FORMAT { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED }, - whiteRectangle.resetAndGetPointerAddress()); - if (FAILED (hr)) - return false; - - whiteRectangle->BeginDraw(); - whiteRectangle->Clear (D2D1_COLOR_F { 1.0f, 1.0f, 1.0f, 1.0f }); - whiteRectangle->EndDraw(); - } - - ComSmartPtr bitmap; - - if (auto hr = whiteRectangle->GetBitmap (bitmap.resetAndGetPointerAddress()); SUCCEEDED (hr)) - { - ComSmartPtr deviceContext3; - - if (hr = deviceContext->QueryInterface (deviceContext3.resetAndGetPointerAddress()); SUCCEEDED (hr)) - { - auto d2dColour = D2DUtilities::toCOLOR_F (colour); - auto spriteBatch = getSpriteBatch (*deviceContext3, (uint32) spriteBatchSize); - - if (spriteBatch == nullptr) - return false; - - auto setCount = jmin ((uint32) spriteBatchSize, spriteBatch->GetSpriteCount()); - auto addCount = (uint32) spriteBatchSize > setCount ? (uint32) spriteBatchSize - setCount : 0; - - if (setCount != 0) - { - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, setSpritesTime); - - spriteBatch->SetSprites (0, setCount, destinations.getData(), nullptr, &d2dColour, nullptr, sizeof (D2D1_RECT_F), 0, 0, 0); - } - - if (addCount != 0) - { - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, addSpritesTime); - - spriteBatch->AddSprites (addCount, destinations.getData() + setCount, nullptr, &d2dColour, nullptr, sizeof (D2D1_RECT_F), 0, 0, 0); - } - - JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (metrics, drawSpritesTime); - - deviceContext3->SetAntialiasMode (D2D1_ANTIALIAS_MODE_ALIASED); - deviceContext3->DrawSpriteBatch (spriteBatch, bitmap); - deviceContext3->SetAntialiasMode (D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); - } - } - - numRectanglesPainted += spriteBatchSize; - } - - return true; + const Callback callback { std::forward (transformRectangle) }; + return fillRectanglesImpl (deviceContext, rectangles, colour, callback, metrics); } private: ComSmartPtr getSpriteBatch (ID2D1DeviceContext3& dc, uint32 key); + bool fillRectanglesImpl (ComSmartPtr deviceContext, + const RectangleList& rectangles, + Colour colour, + const TransformCallback& transformRectangle, + [[maybe_unused]] Direct2DMetrics* metrics); + static constexpr uint32 rectangleSize = 32; ComSmartPtr whiteRectangle; HeapBlock destinations;