Skip to content

Expose bindings to access the ResourceManager cache #910

@Sergio0694

Description

@Sergio0694

Note: follow up to #888 and #894.

With the work done in the two previous issues, Win2D now exposes a set of APIs to allow developers to implement custom effects. This works very well, and it's already being leveraged by ComputeSharp, which is used in the Microsoft Store to power several custom graphics components in its UI. While the new APIs cover most scenarios, there is one that is unfortunately not supported just yet, and that is retrieving WinRT wrappers for D2D images. While this is a more niche scenario, it would be nice for custom effects to benefit ffrom the same level of support of built-in Win2D effects (this has been the goal for all other features as well).

Consider this example:

  • You have some Win2D effect (either built-in, or custom)
  • You get the ID2D1Image (which is an ID2D1Effect) from it
  • You create an instance of a custom effect
  • You also get the ID2D1Image from that
  • You manually set this image as input for the previous effect
  • You then ask that first Win2D effect for the WinRT wrapper for that input

Win2D will see that the effect is realized, so it will use the native D2D effect as source of truth. It will call ID2D1Effect::GetInput, and then invoke the resource manage to get a WinRT wrapper. Since the GUID of this D2D image is not one that's recognized by Win2D (it's just some custom effect), it will then fail to resolve a wrapper, and throw an exception:

API proposal

To solve this, we should add two new APIs to allow custom effects to interact with Win2D's ResourceManager. Since that type is already accessible to resolve WinRT wrappers through the GetOrCreate API, we could add the two new APIs on that same activation factory. This would also make sense given these operations are related to WinRT wrappers in general, not just COM interop.

class __declspec(uuid("695C440D-04B3-4EDD-BFD9-63E51E9F7202"))
ICanvasFactoryNative : public IInspectable
{
public:
    IFACEMETHOD(Add)(IUnknown* resource, IInspectable* wrapper) = 0;
    IFACEMETHOD(Remove)(IUnknown* resource) = 0;
};

And accompanying C++/CX helpers (just like for GetOrCreate):

template<class WRAPPER>
bool Add(IUnknown* resource, WRAPPER^ wrapper);

bool Remove(IUnknown* resource);

Note: the ICanvasFactoryNative interface already exists, the proposal is just to add these two new methods to it.

Custom effects would use these two APIs in the same way as Win2D already uses the ResourceManager class. That is, every time they realize an effect they'd call Add, and every time they unrealize an effect they'd call Remove. This would ensure that each D2D effect would be registered in the cache, so that Win2D would be able to resolve WinRT wrappers even when the effects are directly set via the D2D layer and without touching any WinRT wrappers. This would make the scenario mentioned above work correctly.

While not part of the API signature, callers of Add are required to also have the passed IInspectable object (ie. the custom effect) to implement IWeakReferenceSource as well. This matches what Win2D already does, and prevents memory leaks due to a reference cycle between the underlying D2D resource and its wrapping WinRT object.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions