Вопрос по c#, windows-runtime, uwp, angle, marshalling – Выделение EGLRenderResolutionScaleProperty в ANGLE из C # с использованием P / Invoke

1

Я пытаюсь заставить ANGLE работать в C #, используя P / Invoke. По сути, я создаю простую 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

Оригинальная проблема ANGLE:https://github.com/Microsoft/angle/issues/89

РЕДАКТИРОВАТЬ

После дальнейшего расследования я обнаружил, что по какой-то причинеPropertyValue в C # отличается от того же типа в 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;
}

Этот метод создалPropertySet в C ++, а затем возвращает это в C #. Это работает отлично, и мой сессия ANGLE все хорошо.

Теперь, если я изменю код, чтобы вернутьPropertyValue::CreateSingle(scale) напрямую, это снова не удается. Если я передамPropertyValue.CreateSingle(scale) из C # в этот метод 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 и установил его как ответ.

Получить дисбаланс стека довольно сложно объяснить. Вы не должны использовать PropertySet в программе на C #, так как это помощник по языковой проекции, специфичный для C ++. C # проекция - это словарь. Еще немного об этом вэта почтав том числе "не делай этого!" объяснение. Также довольно трудно догадаться, почему вы думаете, что Skia будет использоваться, он работает правильно, тогда вы получите вызовы DirectX. Таким образом, вы могли бы также пропустить весь ужасный клей. Hans Passant
Спасибо за ответ, но у меня возникла проблема с сортировкойPropertySet/PropertyValue, После дальнейших исследований, кажется, есть разница между управляемыми версиями C ++ и C # одного типа. Я создал Runtime Component, но все по-прежнему не работает - смотрите мои изменения Matthew
Я вижу, что есть близкая просьба :( это не совсем то же самое, что и другая проблема. Это связано с сортировкойPropertyValue, а не непосредственно УГОЛ больше. Все остальное вроде работает нормально. Matthew

Ваш Ответ

2   ответа
1

Но проверенный альтернативный способ - создать проект оболочки WindowsRuntime Component C ++, иначе говоря, использовать 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 #.

Я отмечаю это как ответ, так как это то, что я должен был сделать. Если когда-нибудь найдется лучший способ, то мы всегда сможем вернуться. Благодарю. Matthew
Спасибо за это. Я в конечном итоге объявление, чтобы сделать компонент WinRT. Я создал C API, чтобы я мог P / Invoke (который мне нужен). Я пытался использовать COM напрямую, но столкнулся с проблемой, так какIPropertyValue уже существует в управляемой области. Однако это не работает так же. При сортировке результата отPropertyValue::CreateSingle, он превращает его вfloatи, таким образом, теряет фактическую идентичность и несколько членов, таких какget_Type метод, который требует ANGLE. Matthew
В основном в C ++ результатCreateSingle являетсяValueScalar<float>, но в C # это простоfloat по какой-то причине. Matthew
0

это - создать компонент среды выполнения Windows.

Поскольку я не мог иметь «жесткую» ссылку на компонент - эта библиотека должна работать без наличия ANGLE. Я выбрал небольшой компонент с C API, чтобы я мог просто P / Invoke, когда мне это нужно. Это был мой метод в 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);
}

Похожие вопросы