From f3a74896fca8f7322d2fc3b3a14097c3ce3c67b1 Mon Sep 17 00:00:00 2001 From: reuk Date: Mon, 12 Aug 2024 18:03:07 +0100 Subject: [PATCH] Direct2D: Move bitmap helpers to shared DirectX header --- .../juce_Direct2DGraphicsContext_windows.cpp | 6 +- .../native/juce_Direct2DResources_windows.cpp | 87 ------------------ .../native/juce_DirectX_windows.h | 89 +++++++++++++++++++ 3 files changed, 92 insertions(+), 90 deletions(-) diff --git a/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp index 600dcc1427..f787c3bb29 100644 --- a/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp +++ b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp @@ -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(); } diff --git a/modules/juce_graphics/native/juce_Direct2DResources_windows.cpp b/modules/juce_graphics/native/juce_Direct2DResources_windows.cpp index 0196ec52e9..776bb8d19f 100644 --- a/modules/juce_graphics/native/juce_Direct2DResources_windows.cpp +++ b/modules/juce_graphics/native/juce_Direct2DResources_windows.cpp @@ -74,93 +74,6 @@ struct Direct2DDeviceContext ComSmartPtr context; }; -class Direct2DBitmap final -{ -public: - static ComSmartPtr fromImage (const Image& image, - ComSmartPtr 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 bitmap; - deviceContext->CreateBitmap (size, - bitmapData.data, - (UINT32) bitmapData.lineStride, - bitmapProperties, - bitmap.resetAndGetPointerAddress()); - return bitmap; - } - - static ComSmartPtr createBitmap (ComSmartPtr 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 bitmap; - deviceContext->CreateBitmap (size, - {}, - {}, - bitmapProperties, - bitmap.resetAndGetPointerAddress()); - return bitmap; - } - - Direct2DBitmap() = delete; -}; - static ComSmartPtr makeGradientStopCollection (const ColourGradient& gradient, ComSmartPtr deviceContext, [[maybe_unused]] Direct2DMetrics* metrics) noexcept diff --git a/modules/juce_graphics/native/juce_DirectX_windows.h b/modules/juce_graphics/native/juce_DirectX_windows.h index 6e422459ef..3f1cfd2584 100644 --- a/modules/juce_graphics/native/juce_DirectX_windows.h +++ b/modules/juce_graphics/native/juce_DirectX_windows.h @@ -327,4 +327,93 @@ struct D2DUtilities } }; +//============================================================================== +struct Direct2DBitmap +{ + Direct2DBitmap() = delete; + + static ComSmartPtr toBitmap (const Image& image, + ComSmartPtr 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 bitmap; + deviceContext->CreateBitmap (size, + bitmapData.data, + (UINT32) bitmapData.lineStride, + bitmapProperties, + bitmap.resetAndGetPointerAddress()); + return bitmap; + } + + static ComSmartPtr createBitmap (ComSmartPtr 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 bitmap; + const auto hr = deviceContext->CreateBitmap (size, + {}, + {}, + bitmapProperties, + bitmap.resetAndGetPointerAddress()); + + jassertquiet (SUCCEEDED (hr) && bitmap != nullptr); + return bitmap; + } +}; + } // namespace juce