1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-09 04:30:09 +00:00

Direct2D: Move bitmap helpers to shared DirectX header

This commit is contained in:
reuk 2024-08-12 18:03:07 +01:00
parent f0f77db261
commit f3a74896fc
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
3 changed files with 92 additions and 90 deletions

View file

@ -351,7 +351,7 @@ public:
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
return Direct2DBitmap::fromImage (fillType.image, deviceResources.deviceContext.context, Image::ARGB);
return Direct2DBitmap::toBitmap (fillType.image, deviceResources.deviceContext.context, Image::ARGB);
}();
if (d2d1Bitmap != nullptr)
@ -1188,7 +1188,7 @@ void Direct2DGraphicsContext::clipToImageAlpha (const Image& sourceImage, const
if (! d2d1Bitmap)
{
// Convert sourceImage to single-channel alpha-only maskImage
d2d1Bitmap = Direct2DBitmap::fromImage (sourceImage, deviceContext, Image::SingleChannel);
d2d1Bitmap = Direct2DBitmap::toBitmap (sourceImage, deviceContext, Image::SingleChannel);
}
if (d2d1Bitmap)
@ -1474,7 +1474,7 @@ void Direct2DGraphicsContext::drawImage (const Image& image, const AffineTransfo
{
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
d2d1Bitmap = Direct2DBitmap::fromImage (image, deviceContext, Image::ARGB);
d2d1Bitmap = Direct2DBitmap::toBitmap (image, deviceContext, Image::ARGB);
imageClipArea = image.getBounds();
}

View file

@ -74,93 +74,6 @@ struct Direct2DDeviceContext
ComSmartPtr<ID2D1DeviceContext1> context;
};
class Direct2DBitmap final
{
public:
static ComSmartPtr<ID2D1Bitmap1> fromImage (const Image& image,
ComSmartPtr<ID2D1DeviceContext1> deviceContext,
Image::PixelFormat outputFormat)
{
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
jassert (outputFormat == Image::ARGB || outputFormat == Image::SingleChannel);
JUCE_TRACE_LOG_D2D_PAINT_CALL (etw::createDirect2DBitmapFromImage, etw::graphicsKeyword);
// Calling Image::convertedToFormat could cause unchecked recursion since convertedToFormat
// calls Graphics::drawImageAt which calls Direct2DGraphicsContext::drawImage which calls this function...
//
// Use a software image for the conversion instead so the Graphics::drawImageAt call doesn't go
// through the Direct2D renderer
//
// Be sure to explicitly set the DPI to 96.0 for the image; otherwise it will default to the screen DPI
// and may be scaled incorrectly
const auto convertedImage = SoftwareImageType{}.convert (image).convertedToFormat (outputFormat);
if (! convertedImage.isValid())
return {};
Image::BitmapData bitmapData { convertedImage, Image::BitmapData::readWrite };
D2D1_BITMAP_PROPERTIES1 bitmapProperties{};
bitmapProperties.pixelFormat.format = outputFormat == Image::SingleChannel
? DXGI_FORMAT_A8_UNORM
: DXGI_FORMAT_B8G8R8A8_UNORM;
bitmapProperties.pixelFormat.alphaMode = outputFormat == Image::RGB
? D2D1_ALPHA_MODE_IGNORE
: D2D1_ALPHA_MODE_PREMULTIPLIED;
bitmapProperties.dpiX = USER_DEFAULT_SCREEN_DPI;
bitmapProperties.dpiY = USER_DEFAULT_SCREEN_DPI;
const D2D1_SIZE_U size { (UINT32) image.getWidth(), (UINT32) image.getHeight() };
ComSmartPtr<ID2D1Bitmap1> bitmap;
deviceContext->CreateBitmap (size,
bitmapData.data,
(UINT32) bitmapData.lineStride,
bitmapProperties,
bitmap.resetAndGetPointerAddress());
return bitmap;
}
static ComSmartPtr<ID2D1Bitmap1> createBitmap (ComSmartPtr<ID2D1DeviceContext1> deviceContext,
Image::PixelFormat format,
D2D_SIZE_U size,
D2D1_BITMAP_OPTIONS options)
{
JUCE_TRACE_LOG_D2D_PAINT_CALL (etw::createDirect2DBitmap, etw::graphicsKeyword);
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
#if JUCE_DEBUG
// Verify that the GPU can handle a bitmap of this size
//
// If you need a bitmap larger than this, you'll need to either split it up into multiple bitmaps
// or use a software image (see SoftwareImageType).
auto maxBitmapSize = deviceContext->GetMaximumBitmapSize();
jassert (size.width <= maxBitmapSize && size.height <= maxBitmapSize);
#endif
const auto pixelFormat = D2D1::PixelFormat (format == Image::SingleChannel
? DXGI_FORMAT_A8_UNORM
: DXGI_FORMAT_B8G8R8A8_UNORM,
format == Image::RGB
? D2D1_ALPHA_MODE_IGNORE
: D2D1_ALPHA_MODE_PREMULTIPLIED);
const auto bitmapProperties = D2D1::BitmapProperties1 (options, pixelFormat);
ComSmartPtr<ID2D1Bitmap1> bitmap;
deviceContext->CreateBitmap (size,
{},
{},
bitmapProperties,
bitmap.resetAndGetPointerAddress());
return bitmap;
}
Direct2DBitmap() = delete;
};
static ComSmartPtr<ID2D1GradientStopCollection> makeGradientStopCollection (const ColourGradient& gradient,
ComSmartPtr<ID2D1DeviceContext1> deviceContext,
[[maybe_unused]] Direct2DMetrics* metrics) noexcept

View file

@ -327,4 +327,93 @@ struct D2DUtilities
}
};
//==============================================================================
struct Direct2DBitmap
{
Direct2DBitmap() = delete;
static ComSmartPtr<ID2D1Bitmap1> toBitmap (const Image& image,
ComSmartPtr<ID2D1DeviceContext1> deviceContext,
Image::PixelFormat outputFormat)
{
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
jassert (outputFormat == Image::ARGB || outputFormat == Image::SingleChannel);
JUCE_TRACE_LOG_D2D_PAINT_CALL (etw::createDirect2DBitmapFromImage, etw::graphicsKeyword);
// Calling Image::convertedToFormat could cause unchecked recursion since convertedToFormat
// calls Graphics::drawImageAt which calls Direct2DGraphicsContext::drawImage which calls this function...
//
// Use a software image for the conversion instead so the Graphics::drawImageAt call doesn't go
// through the Direct2D renderer
//
// Be sure to explicitly set the DPI to 96.0 for the image; otherwise it will default to the screen DPI
// and may be scaled incorrectly
const auto convertedImage = SoftwareImageType{}.convert (image).convertedToFormat (outputFormat);
if (! convertedImage.isValid())
return {};
Image::BitmapData bitmapData { convertedImage, Image::BitmapData::readWrite };
D2D1_BITMAP_PROPERTIES1 bitmapProperties{};
bitmapProperties.pixelFormat.format = outputFormat == Image::SingleChannel
? DXGI_FORMAT_A8_UNORM
: DXGI_FORMAT_B8G8R8A8_UNORM;
bitmapProperties.pixelFormat.alphaMode = outputFormat == Image::RGB
? D2D1_ALPHA_MODE_IGNORE
: D2D1_ALPHA_MODE_PREMULTIPLIED;
bitmapProperties.dpiX = USER_DEFAULT_SCREEN_DPI;
bitmapProperties.dpiY = USER_DEFAULT_SCREEN_DPI;
const D2D1_SIZE_U size { (UINT32) image.getWidth(), (UINT32) image.getHeight() };
ComSmartPtr<ID2D1Bitmap1> bitmap;
deviceContext->CreateBitmap (size,
bitmapData.data,
(UINT32) bitmapData.lineStride,
bitmapProperties,
bitmap.resetAndGetPointerAddress());
return bitmap;
}
static ComSmartPtr<ID2D1Bitmap1> createBitmap (ComSmartPtr<ID2D1DeviceContext1> deviceContext,
Image::PixelFormat format,
D2D_SIZE_U size,
D2D1_BITMAP_OPTIONS options)
{
JUCE_TRACE_LOG_D2D_PAINT_CALL (etw::createDirect2DBitmap, etw::graphicsKeyword);
JUCE_D2DMETRICS_SCOPED_ELAPSED_TIME (Direct2DMetricsHub::getInstance()->imageContextMetrics, createBitmapTime);
#if JUCE_DEBUG
// Verify that the GPU can handle a bitmap of this size
//
// If you need a bitmap larger than this, you'll need to either split it up into multiple bitmaps
// or use a software image (see SoftwareImageType).
auto maxBitmapSize = deviceContext->GetMaximumBitmapSize();
jassert (size.width <= maxBitmapSize && size.height <= maxBitmapSize);
#endif
const auto pixelFormat = D2D1::PixelFormat (format == Image::SingleChannel
? DXGI_FORMAT_A8_UNORM
: DXGI_FORMAT_B8G8R8A8_UNORM,
format == Image::RGB
? D2D1_ALPHA_MODE_IGNORE
: D2D1_ALPHA_MODE_PREMULTIPLIED);
const auto bitmapProperties = D2D1::BitmapProperties1 (options, pixelFormat);
ComSmartPtr<ID2D1Bitmap1> bitmap;
const auto hr = deviceContext->CreateBitmap (size,
{},
{},
bitmapProperties,
bitmap.resetAndGetPointerAddress());
jassertquiet (SUCCEEDED (hr) && bitmap != nullptr);
return bitmap;
}
};
} // namespace juce