1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Direct2D: Hide implementation of RectangleListSpriteBatch::fillRectangles

This commit is contained in:
reuk 2025-04-17 15:01:16 +01:00 committed by Oli
parent 49948d5dd4
commit 243d3756fc
2 changed files with 120 additions and 92 deletions

View file

@ -496,6 +496,108 @@ ComSmartPtr<ID2D1SpriteBatch> RectangleListSpriteBatch::getSpriteBatch (ID2D1Dev
});
}
bool RectangleListSpriteBatch::fillRectanglesImpl (ComSmartPtr<ID2D1DeviceContext1> deviceContext,
const RectangleList<float>& 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<ID2D1Bitmap> bitmap;
if (auto hr = whiteRectangle->GetBitmap (bitmap.resetAndGetPointerAddress()); SUCCEEDED (hr))
{
ComSmartPtr<ID2D1DeviceContext3> deviceContext3;
if (hr = deviceContext->QueryInterface<ID2D1DeviceContext3> (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)

View file

@ -268,6 +268,11 @@ private:
class RectangleListSpriteBatch
{
struct TransformCallback
{
virtual Rectangle<float> transform (Rectangle<float>) 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<float> transform (Rectangle<float> 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<ID2D1Bitmap> bitmap;
if (auto hr = whiteRectangle->GetBitmap (bitmap.resetAndGetPointerAddress()); SUCCEEDED (hr))
{
ComSmartPtr<ID2D1DeviceContext3> deviceContext3;
if (hr = deviceContext->QueryInterface<ID2D1DeviceContext3> (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> (transformRectangle) };
return fillRectanglesImpl (deviceContext, rectangles, colour, callback, metrics);
}
private:
ComSmartPtr<ID2D1SpriteBatch> getSpriteBatch (ID2D1DeviceContext3& dc, uint32 key);
bool fillRectanglesImpl (ComSmartPtr<ID2D1DeviceContext1> deviceContext,
const RectangleList<float>& rectangles,
Colour colour,
const TransformCallback& transformRectangle,
[[maybe_unused]] Direct2DMetrics* metrics);
static constexpr uint32 rectangleSize = 32;
ComSmartPtr<ID2D1BitmapRenderTarget> whiteRectangle;
HeapBlock<D2D1_RECT_F> destinations;