1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00
JUCE/modules/juce_graphics/native/juce_Direct2DImage_windows.h
Oli bf940ae42a Direct2D: Do image cloning on GPU when possible
Co-authored-by: Matt Gonzalez <matt@echoaudio.com>
2025-04-24 13:58:23 +01:00

267 lines
11 KiB
C++

/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
/* A set of pages that together represent a full virtual bitmap.
All pages in the set always share the same resource context.
Additionally, stores a reference to a software-backed bitmap, the content of which will
be copied to the pages when necessary in order to ensure that the software- and hardware-backed
bitmaps match.
*/
class Direct2DPixelDataPages
{
public:
using Page = Direct2DPixelDataPage;
enum class State
{
unsuitableToRead, // Image data is outdated
suitableToRead, // Image data is up-to-date with the backing data
cleared, // Implies suitableToRead
};
/* Creates a single page containing the provided bitmap and main-memory storage, marking the
hardware data as up-to-date.
*/
Direct2DPixelDataPages (ImagePixelDataBackupExtensions*, ComSmartPtr<ID2D1Bitmap1>, ImagePixelData::Ptr);
/* Allocates hardware storage for the provided software bitmap.
Depending on the initial state, will:
- mark the GPU images as needing to be copied from main memory before they are next accessed, or
- mark the GPU images as up-to-date, or
- clear the GPU images, then mark them as up-to-date
*/
Direct2DPixelDataPages (ImagePixelDataBackupExtensions*, ComSmartPtr<ID2D1Device1>, ImagePixelData::Ptr, State);
/* Returns all pages included in this set.
This will be called before reading from the pages (e.g. when drawing them).
Therefore, this function will check whether the hardware data is out-of-date and
copy from the software image if necessary before returning.
*/
Span<const Page> getPages();
/** Returns all pages without first syncing from main memory. */
Span<const Page> getPagesWithoutSync() const;
/* Marks this set as needing to be updated from the software image.
We don't actually do the copy until the next time that we need to read the hardware pages.
This is to avoid redundant copies in the common case that pages are only drawn on a single
device at a time.
*/
void markOutdated()
{
upToDate = false;
}
bool isUpToDate() const
{
return upToDate;
}
std::optional<Direct2DPixelDataPage> getPageContainingPoint (Point<int> pt) const;
private:
ImagePixelDataBackupExtensions* parentBackupExtensions = nullptr;
ImagePixelData::Ptr backingData;
std::vector<Direct2DPixelDataPage> pages;
bool upToDate = false;
};
/* Pixel data type providing accelerated access to cached Direct2D textures.
Direct2D bitmaps are device-dependent resources, but frequently a computer will
have multiple devices, e.g. if there are several GPUs available which is common for laptops.
In order to support a fast image type that can be drawn by any one of the available devices,
we store a software bitmap which acts as the source-of-truth, and cache per-device hardware
bitmaps alongside it. The caching mechanism tries to minimise the amount of redundant work.
When attempting to access hardware bitmaps, we first check the cache to see whether we've
previously allocated bitmaps for the requested device, and only create bitmaps if none already
exist.
We only copy from the software backup to hardware memory immediately before accessing the
bitmaps for a particular device, and then only if that hardware bitmap is outdated. All
hardware bitmaps are marked as outdated when a writeable BitmapData is created for the current
PixelData. When creating a low-level graphics context, all hardware bitmaps other than the
render target are marked as outdated.
*/
class Direct2DPixelData : public ImagePixelData,
private DxgiAdapterListener,
private ImagePixelDataBackupExtensions
{
public:
using Ptr = ReferenceCountedObjectPtr<Direct2DPixelData>;
using Page = Direct2DPixelDataPage;
using Pages = Direct2DPixelDataPages;
/* Creates image storage, taking ownership of the provided bitmap.
This will immediately copy the content of the image to the software backup, so that the
image can still be drawn if original device goes away.
*/
Direct2DPixelData (ComSmartPtr<ID2D1Device1>, ComSmartPtr<ID2D1Bitmap1>);
/* Creates software image storage of the requested size. */
Direct2DPixelData (Image::PixelFormat, int, int, bool);
~Direct2DPixelData() override;
/* Creates new image storage with content matching the content of this image. */
ImagePixelData::Ptr clone() override;
std::unique_ptr<ImageType> createType() const override
{
return std::make_unique<NativeImageType>();
}
/* Creates a graphics context that will use the default device to draw into hardware bitmaps
for that device. When the context is destroyed, the rendered hardware bitmap will be copied
back to software storage.
This PixelData may hold device resources for devices other than the default device. In that
case, the other device resources will be marked as outdated, to ensure that they are updated
from the software backup before they are next accessed.
*/
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override;
/* Provides access to the software image storage.
If the bitmap data provides write access, then all device resources will be marked as
outdated, to ensure that they are updated from the software backup before they are next
accessed.
*/
void initialiseBitmapData (Image::BitmapData&, int, int, Image::BitmapData::ReadWriteMode) override;
void applyGaussianBlurEffectInArea (Rectangle<int>, float) override;
void applySingleChannelBoxBlurEffectInArea (Rectangle<int>, int) override;
void multiplyAllAlphasInArea (Rectangle<int>, float) override;
void desaturateInArea (Rectangle<int>) override;
/* This returns image data that is suitable for use when drawing with the provided context.
This image data should be treated as a read-only view - making modifications directly
through the Direct2D API will have unpredictable results.
If you want to render into this image using D2D, call createLowLevelContext.
*/
Span<const Page> getPagesForDevice (ComSmartPtr<ID2D1Device1>);
/* Utility function that just returns a pointer to the bitmap for the first page returned from
getPagesForContext.
*/
ComSmartPtr<ID2D1Bitmap1> getFirstPageForDevice (ComSmartPtr<ID2D1Device1> device)
{
const auto pages = getPagesForDevice (device);
return ! pages.empty() ? pages.front().bitmap : nullptr;
}
BackupExtensions* getBackupExtensions() override { return this; }
const BackupExtensions* getBackupExtensions() const override { return this; }
ImagePixelDataNativeExtensions getNativeExtensions() override;
private:
enum class State
{
initiallyUndefined,
initiallyCleared,
drawing,
drawn,
outdated,
};
Direct2DPixelData (ImagePixelData::Ptr, State);
auto getIteratorForDevice (ComSmartPtr<ID2D1Device1>);
Direct2DPixelDataPages& getPagesStructForDevice (ComSmartPtr<ID2D1Device1>);
/* Attempts to copy the content of the corresponding texture in graphics storage into
persistent software storage.
The argument specifies the device holding the texture that should be backed up.
Passing null will instead search through all devices to find which device has the most
recent copy of the image data.
In most cases it is unnecessary to call this function directly.
Returns true on success, i.e. the backup is already up-to-date or the backup was updated
successfully.
Returns false on failure. The backup process may fail if the graphics storage became
unavailable for some reason, such as an external GPU being disconnected, or a remote desktop
session ending. If this happens, the image content is *irrevocably lost* and will need to
be recreated.
*/
bool createPersistentBackup (ComSmartPtr<ID2D1Device1> deviceHint);
void moveValidatedImageSection (Point<int> destTopLeft, Rectangle<int> sourceRect) override;
struct Context;
std::unique_ptr<Context> createNativeContext();
template <typename Fn>
bool applyEffectInArea (Rectangle<int>, Fn&&);
void setBackupEnabled (bool) override;
bool isBackupEnabled() const override;
bool backupNow() override;
bool needsBackup() const override;
bool canBackup() const override;
static void copyPages (ComSmartPtr<ID2D1Device1>,
Direct2DPixelData&,
Direct2DPixelData&,
Point<int>,
Rectangle<int>);
void adapterCreated (DxgiAdapter::Ptr) override {}
void adapterRemoved (DxgiAdapter::Ptr adapter) override
{
if (adapter != nullptr)
pagesForDevice.erase (adapter->direct2DDevice);
if (mostRecentDevice == adapter->direct2DDevice)
mostRecentDevice = nullptr;
}
ComSmartPtr<ID2D1Device1> getMostRelevantDevice();
SharedResourcePointer<DirectX> directX;
ImagePixelData::Ptr backingData;
ComSmartPtr<ID2D1Device1> mostRecentDevice;
std::map<ComSmartPtr<ID2D1Device1>, Pages> pagesForDevice;
State state;
bool sync = true;
JUCE_LEAK_DETECTOR (Direct2DPixelData)
};
} // namespace juce