编组"EGLRenderResolutionScaleProperty"使用 P/Invoke 从 C# 到 ANGLE [英] Marshalling "EGLRenderResolutionScaleProperty" to ANGLE from C# using P/Invoke

查看:20
本文介绍了编组"EGLRenderResolutionScaleProperty"使用 P/Invoke 从 C# 到 ANGLE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 P/Invoke 使 ANGLE 在 C# 中工作.基本上,我正在创建一个简单的 2D 表面,然后将其传递给 Skia(使用 SkiaSharp).一切正常,但我在将 PropertySet 编组到非托管代码时遇到问题.

I am trying to get ANGLE working in C# using P/Invoke. Basically, I am creating a simple 2D surface, and then passing that off to skia (using SkiaSharp). Everything is working and all that, but I am having a problem marshalling PropertySet to the unmanaged code.

这一点工作正常:

// 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);

我的导入看起来像这样:

My import looks like this:

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

当我尝试为高分辨率屏幕设置缩放比例时,问题就出现了.这应该"有效:

The problem comes in when I am trying to set my scaling for high resolution screens. This "should" work:

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

它在使用 C++ 时有效,但在 C# 中无效.我想我已经把它归结为实际值没有被正确编组的事实.这是因为在 ANGLE 代码中调试时,它死在这里:

It works when using C++, but not in C#. I think I have got it down to the fact that the actual value is not being marshalled correctly. This is because when debugging in ANGLE code, it dies over here:

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

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

运行时异常是:

运行时检查失败 #0 - ESP 的值未在函数调用中正确保存.这通常是由于使用一种调用约定声明的函数与使用不同调用约定声明的函数指针调用的结果.

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

是否有任何提示或解决方案?

Are there any tips, or solutions?

这里是我所有的代码供参考:https://gist.github.com/mattleibow/eacb9c9e87f320c3c/a>

Here is all my code for reference: https://gist.github.com/mattleibow/eacb9c9e87f306b218d99c713c532a82

原始角度问题:https://github.com/Microsoft/angle/issues/89

编辑

经过进一步调查,我发现由于某种原因,C# 中的 PropertyValue 与 C++ 中的相同类型不同(通过 Windows 运行时组件).

After further investigation, I found that for some reason PropertyValue in C# is different to the same type in C++ (via Windows Runtime Component).

我试过了:

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 会话也很好.

This method created a PropertySet in C++ and then returns that to C#. This works fine and my ANGLE session is all good.

现在,如果我更改代码以直接返回 PropertyValue::CreateSingle(scale),这将再次失败.如果我将 C# 中的 PropertyValue.CreateSingle(scale) 传递给这个 C++ 方法,我发现对象并不相似.

Now, if I change the code to return the PropertyValue::CreateSingle(scale) directly, this fails again. If I pass the PropertyValue.CreateSingle(scale) from C# into this C++ method, I find that the objects are not similar.

在本地调试器中,我为用 C# 构造的对象得到了这个:

In the debugger locals I get this for the object constructed in C#:

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

如果对象是用 C++ 构造的,我会得到这个:

If the object is constructed in C++, I get this:

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

对象不应该是相同的,因为它们是相同的类型吗?更可怕的是,如果我越界传递这个值,类型就会改变.

Shouldn't the object be the same, since they are the same type? What is more scary is that if I pass this value across the boundary, the type changes.

删除编辑 2 并将其设置为答案.

推荐答案

经过一番搜索,我发现最好(也是唯一)的方法是创建一个 Windows 运行时组件.

After doing a bit of searching, I found the best (and only) way to do this was to create a Windows Runtime Component.

因为我无法对组件进行硬"引用 - 该库必须在没有 ANGLE 的情况下工作.我选择了一个带有 C API 的小组件,这样我就可以在需要时直接调用它.这是我在 C++ 中的方法:

As I could not have a "hard" reference to the component - this library must work without ANGLE present. I opted for a small component with a C API so that I could just P/Invoke it when I needed it. This was my method in 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 代码是这样的:

I am using COM here so that I can use this in C/C++ code. My P/Invoke code is this:

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);
}

这篇关于编组&quot;EGLRenderResolutionScaleProperty&quot;使用 P/Invoke 从 C# 到 ANGLE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆