From e89c7198cfd8b1543a30c966091724ac4eff9101 Mon Sep 17 00:00:00 2001 From: scheffle Date: Mon, 23 Oct 2023 16:56:42 +0200 Subject: [PATCH] fix offscreen rendering on Windows (cherry picked from commit 834ec875c9b8b7c7d1c9dd508bdb46730bbf2d64) --- .../win32/direct2d/d2dgraphicscontext.cpp | 106 +++++++++++++++--- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp index c4f17a7db..67e0093d1 100644 --- a/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp +++ b/vstgui/lib/platform/win32/direct2d/d2dgraphicscontext.cpp @@ -37,6 +37,94 @@ struct TransformGuard ID2D1DeviceContext* context; }; +//------------------------------------------------------------------------ +struct D2DBitmapDeviceContext : D2DGraphicsDeviceContext +{ + static PlatformGraphicsDeviceContextPtr make (const D2DGraphicsDevice& device, + ID2D1DeviceContext* deviceContext, + const SharedPointer& bitmap) + { + D2D1_BITMAP_PROPERTIES1 props = D2D1::BitmapProperties1 ( + D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + + COM::Ptr bitmapTarget; + deviceContext->CreateBitmapFromWicBitmap (bitmap->getSource (), &props, + bitmapTarget.adoptPtr ()); + if (!bitmapTarget) + return nullptr; + + deviceContext->SetTarget (bitmapTarget.get ()); + + TransformMatrix tm; + tm.scale (bitmap->getScaleFactor (), bitmap->getScaleFactor ()); + deviceContext->SetTransform (convert (tm)); + return std::make_shared (device, bitmap, deviceContext, + TransformMatrix {}); + } + + D2DBitmapDeviceContext (const D2DGraphicsDevice& device, const SharedPointer& bitmap, + ID2D1DeviceContext* deviceContext, const TransformMatrix& tm) + : D2DGraphicsDeviceContext (device, deviceContext, tm), bitmap (bitmap) + { + } + + bool endDraw () const + { + if (D2DGraphicsDeviceContext::endDraw ()) + { + COM::Ptr image; + getID2D1DeviceContext ()->GetTarget (image.adoptPtr ()); + if (!image) + return false; + COM::Ptr bitmapTarget; + if (FAILED (image->QueryInterface (bitmapTarget.adoptPtr ()))) + return false; + auto pa = bitmap->lockPixels (true); + if (!pa) + return false; + auto size = bitmap->getSize (); + D2D1_BITMAP_PROPERTIES1 props = D2D1::BitmapProperties1 ( + D2D1_BITMAP_OPTIONS_CPU_READ | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, + D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); + COM::Ptr cpuBitmap; + auto hr = getID2D1DeviceContext ()->CreateBitmap ( + D2D1_SIZE_U {static_cast (size.x), static_cast (size.y)}, nullptr, + pa->getBytesPerRow (), props, cpuBitmap.adoptPtr ()); + if (FAILED (hr)) + return false; + D2D1_POINT_2U dp {}; + D2D1_RECT_U dstRect {0, 0, static_cast (size.x), static_cast (size.y)}; + hr = cpuBitmap->CopyFromBitmap (&dp, bitmapTarget.get (), &dstRect); + if (FAILED (hr)) + return false; + D2D1_MAPPED_RECT mappedRect {}; + hr = cpuBitmap->Map (D2D1_MAP_OPTIONS_READ, &mappedRect); + if (FAILED (hr)) + return false; + auto height = static_cast (size.y); + if (pa->getBytesPerRow () == mappedRect.pitch) + { + memcpy (pa->getAddress (), mappedRect.bits, mappedRect.pitch * height); + } + else + { + auto src = mappedRect.bits; + for (auto row = 0u; row < height; ++row, src += mappedRect.pitch) + { + auto dst = pa->getAddress () + pa->getBytesPerRow () * row; + memcpy (dst, src, pa->getBytesPerRow ()); + } + } + cpuBitmap->Unmap (); + return true; + } + return false; + } + + SharedPointer bitmap; +}; + //------------------------------------------------------------------------ } // anonymous namespace @@ -117,23 +205,7 @@ PlatformGraphicsDeviceContextPtr D2DBitmapCache::removeBitmap (d2dBitmap); - D2D1_BITMAP_PROPERTIES1 props = D2D1::BitmapProperties1 ( - D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, - D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)); - - COM::Ptr bitmapTarget; - deviceContext->CreateBitmapFromWicBitmap (d2dBitmap->getSource (), &props, bitmapTarget.adoptPtr ()); - if (!bitmapTarget) - return nullptr; - - deviceContext->SetTarget (bitmapTarget.get ()); - - TransformMatrix tm; - tm.scale (d2dBitmap->getScaleFactor (), d2dBitmap->getScaleFactor ()); - deviceContext->SetTransform (convert (tm)); - - return std::make_shared (*this, deviceContext.get (), - TransformMatrix {}); + return D2DBitmapDeviceContext::make (*this, deviceContext.get (), d2dBitmap); } return nullptr; }