簡體   English   中英

使用 P/Invoke 從 C# 將“EGLRenderResolutionScaleProperty”編組到 ANGLE

[英]Marshalling "EGLRenderResolutionScaleProperty" to ANGLE from C# using P/Invoke

我正在嘗試使用 P/Invoke 使 ANGLE 在 C# 中工作。 基本上,我正在創建一個簡單的 2D 表面,然后將其傳遞給 Skia(使用 SkiaSharp)。 一切正常,但我在將PropertySet編組到非托管代碼時遇到問題。

這一點工作正常:

// the properties
var props = new PropertySet();
props.Add("EGLNativeWindowTypeProperty", swapChainPanel);
// the surface attributes
int[] surfaceAttrs = {
    EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER, EGL_TRUE,
    EGL_NONE
};

// create the surface
surface = eglCreateWindowSurface(eglDisplay, eglConfig, props, surfaceAttrs);

我的導入看起來像這樣:

[DllImport("libEGL.dll")]
public static extern IntPtr eglCreateWindowSurface(
    IntPtr dpy, 
    IntPtr config, 
    [MarshalAs(UnmanagedType.IInspectable)] object win, 
    int[] attrib_list);

當我嘗試為高分辨率屏幕設置縮放比例時,問題就出現了。 這“應該”工作:

var scale = PropertyValue.CreateSingle(2);
props.Add("EGLRenderResolutionScaleProperty", scale);

它在使用 C++ 時有效,但在 C# 中無效。 我想我已經把它歸結為實際值沒有被正確編組的事實。 這是因為在 ANGLE 代碼中調試時,它會死在這里:

ComPtr<ABI::Windows::Foundation::IPropertyValue> propertyValue;
ABI::Windows::Foundation::PropertyType propertyType;
// ... 
result = propertyValue->get_Type(&propertyType);

https://github.com/Microsoft/angle/blob/54b1fd01f7fddcd7011d5a04e9259edace8a13da/src/libANGLE/renderer/d3d/d3d11/winrt/InspectableNativeWindow.cpp#L242

運行時異常是:

運行時檢查失敗 #0 - ESP 的值未在函數調用中正確保存。 這通常是調用一個用一個調用約定聲明的函數和一個用不同調用約定聲明的函數指針的結果。

有什么提示或解決方案嗎?

這是我所有的代碼供參考: https : //gist.github.com/mattleibow/eacb9c9e87f306b218d99c713c532a82

原始角度問題: https : //github.com/Microsoft/angle/issues/89

編輯

經過進一步調查,我發現由於某種原因,C# 中的PropertyValue與 C++ 中的相同類型不同(通過 Windows 運行時組件)。

我試過這個:

static PropertySet^ CreateSurface(SwapChainPanel^ panel, float scale)
{
    PropertySet^ surfaceCreationProperties = ref new PropertySet();
    surfaceCreationProperties->Insert(L"EGLNativeWindowTypeProperty", panel);
    Object^ scaleVal = PropertyValue::CreateSingle(scale);
    surfaceCreationProperties->Insert(L"EGLRenderResolutionScaleProperty", scaleVal);
    return surfaceCreationProperties;
}

此方法在 C++ 中創建了一個PropertySet ,然后將其返回給 C#。 這很好用,我的 ANGLE 會話也很好。

現在,如果我更改代碼以直接返回PropertyValue::CreateSingle(scale) ,這將再次失敗。 如果我將 C# 中的PropertyValue.CreateSingle(scale)傳遞到這個 C++ 方法中,我發現這些對象並不相似。

在調試器本地人中,我為在 C# 中構造的對象得到了這個:

0x09f10ba4 <Information not available, no symbols loaded for coreclr.dll>
Platform::Object ^

如果對象是用 C++ 構造的,我會得到這個:

0x019162e8 2.00000000
Platform::Object ^ {WinTypes.dll!Windows::Foundation::Value<Windows::Foundation::ValueScalar<float> >}

對象不應該是相同的,因為它們是相同的類型嗎? 更可怕的是,如果我越過邊界傳遞這個值,類型就會改變。

刪除了編輯 2 並將其設置為答案。

我不是直接回答你的問題。

但一個行之有效的替代方法是創建一個 C++ WindowsRuntime 組件包裝器項目,也就是使用 C++/CLI(或 CXX,我應該說?)來執行互操作。

您可以公開如下方法,根據您的需要公開 API。

void InitializeEGL(Windows::UI::Core::CoreWindow^ window);
void InitializeEGL(Windows::UI::Xaml::Controls::SwapChainPanel ^ window);

或者,如果您想要更精細的粒度,請在 C++ WinRT 組件中聲明如下內容,

void EglCreateWindowSurface(Platform::IntPtr display, Platform::IntPtr config, Windows::Foundation::Collections::PropertySet^ propertySet);

這個小技巧將使您能夠解決 C# 封送處理問題,我已經驗證它可以工作。

我將繼續研究 C# 互操作方法。

在做了一些搜索之后,我發現最好的(也是唯一的)方法是創建一個 Windows 運行時組件。

由於我無法對組件進行“硬”引用 - 該庫必須在沒有 ANGLE 的情況下工作。 我選擇了一個帶有 C API 的小組件,這樣我就可以在需要時直接調用它。 這是我在 C++ 中的方法:

void PropertySetInterop_AddSingle(ABI::Windows::Foundation::Collections::IPropertySet* propertySet, HSTRING key, float scale)
{
    using namespace Microsoft::WRL;
    using namespace Microsoft::WRL::Wrappers;
    using namespace ABI::Windows::Foundation;
    using namespace ABI::Windows::Foundation::Collections;

    ComPtr<IPropertySet> propSet = propertySet;
    ComPtr<IMap<HSTRING, IInspectable*>> map;
    propSet.As(&map);

    ComPtr<IPropertyValueStatics> propValueFactory;
    GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &propValueFactory);

    ComPtr<IInspectable> valueInspectable;
    propValueFactory->CreateSingle(scale, &valueInspectable);

    boolean replaced;
    map->Insert(key, valueInspectable.Get(), &replaced);
}

我在這里使用 COM,以便我可以在 C/C++ 代碼中使用它。 我的 P/Invoke 代碼是這樣的:

internal static class PropertySetInterop
{
    public static void AddSingle(PropertySet properties, string key, float value)
    {
        PropertySetInterop_AddSingle(properties, key, value);
    }

    public static void AddSize(PropertySet properties, string key, float width, float height)
    {
        PropertySetInterop_AddSize(properties, key, width, height);
    }

    private const string libInterop = "SkiaSharp.Views.Interop.UWP.dll";

    [DllImport(libInterop)]
    private static extern void PropertySetInterop_AddSingle(
        [MarshalAs(UnmanagedType.IInspectable)] object properties,
        [MarshalAs(UnmanagedType.HString)] string key,
        float value);

    [DllImport(libInterop)]
    private static extern void PropertySetInterop_AddSize(
        [MarshalAs(UnmanagedType.IInspectable)] object properties,
        [MarshalAs(UnmanagedType.HString)] string key,
        float width, float height);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM