2016-09-11 4 views
1

P/Invoke를 사용하여 C#에서 ANGLE이 작동하도록하려고합니다. 기본적으로, 나는 단순한 2D 표면을 생성하고,이를 SkiaSharp를 사용하여 skia로 전달합니다. 모든 것이 작동하지만 모든 것이 관리되지 않는 코드에 PropertySet을 마샬링하는 데 문제가 있습니다.P/Invoke를 사용하여 C#에서 "EGLRenderResolutionScaleProperty"를 ANGLE로 마킹

이 비트는 잘 작동 :

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

문제는 내가 고해상도 화면 내 배율을 설정하려고 할 때 제공됩니다. 이것은 "해야"작동합니다 :

이 기능은 C++을 사용할 때는 작동하지만 C#에서는 작동하지 않습니다. 나는 실제 값이 올바르게 정렬되지 않았다는 사실을 알고있다.

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

런타임 예외는 다음과 같습니다 : ANGLE 코드에서 디버깅 할 때, 그것은 여기에 사망하기 때문이다

런타임 검사 실패 # 0 - ESP의 값이되었다 함수 호출을 통해 제대로 저장되지 않습니다. 이것은 대개 다른 호출 규칙으로 선언 된 함수 포인터로 하나의 호출 규칙으로 선언 된 함수를 호출 한 결과입니다.

팁이나 해결책이 있습니까? 여기

은 참조를 위해 내 모든 코드입니다 https://gist.github.com/mattleibow/eacb9c9e87f306b218d99c713c532a82

원래 ANGLE 문제 : 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#으로 구성 개체에 대한이를 얻을 디버거 지역 주민에

: 개체가 C++ 구성되어있는 경우

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

,이 얻을 :

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

개체가 있어야하지 않나요 그들은 같은 유형이기 때문에 동일합니까?더 무서운 것은 경계를 가로 질러이 값을 전달하면 유형이 변경된다는 것입니다.

수정 2를 제거하고 대답으로 설정하십시오.

+0

스택 불균형을 얻는 것은 설명하기가 어렵습니다. PropertySet은 C++에 고유 한 언어 프로젝션 도우미이므로 C# 프로그램에서 PropertySet을 사용하지 않아야합니다. C# 예측은 사전입니다. 이것에 대한 자세한 내용은 [이 게시물] (http://stackoverflow.com/a/39154410/17034)에서 "do not do this!" 설명. skia가 사용될 것이라고 생각하는 이유를 추측하기도 꽤 어렵습니다. 제대로 작동하면 DirectX 호출을받을 것입니다. 그래서 모든 무시 무시한 접착제를 건너 뛸 수도 있습니다. –

+0

답장을 보내 주셔서 감사합니다.하지만 'PropertySet' /'PropertyValue'를 마샬링하는 데 문제가 있습니다. 추가 조사가 끝나면 같은 유형의 관리되는 C++ 버전과 C# 버전간에 차이가있는 것으로 보입니다. 런타임 구성 요소를 만들었고 여전히 문제가 발생했습니다. 내 편집 참조 – Matthew

+0

가까운 요청이 있습니다. (이것은 다른 문제와 완전히 같지 않습니다.이 문제는 더 이상 직접 ANGLE이 아닌 'PropertyValue'를 마샬링하는 것과 관련이 있습니다. 다른 모든 것들이 잘 작동하는 것 같아요. – 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); 
} 
1

귀하의 질문에 직접 대답하지 않습니다.

입증 된 작업 대안은 interop을 수행하기 위해 C++ WindowsRuntime Component 래퍼 프로젝트 (일명 CXX 또는 CXX)를 사용하는 것입니다.

다음과 같은 메소드를 노출하고 필요에 따라 API를 노출 할 수 있습니다.

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

또는, 당신은 미세한 단위를 아래의 C++ WinRT 구성 요소에서 같은 것을 선언 할 경우,이 작은 트릭은 C#을 마샬링의 문제를 해결받을 수있게된다

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

및 나는 그것이 작동하도록 검증했다.

그리고 C# interop 접근법을 계속 조사 할 것입니다.

+0

나는 WinRT 구성 요소를 만들기 위해 결국 광고합니다 .P/Invoke (필요한) 수 있도록 C API를 만들었습니다. 직접 COM 사용하려고했지만 이 문제는'IPropertyValue'가 이미 관리 영역에 존재하기 때문에 발생합니다. 그러나 이것은 동일하지 않습니다 .' PropertyValue :: CreateSingle'의 결과를 마샬링 할 때'float'으로 변환하여 실제 ID와 멤버들, 예를 들어 ANGLE이 필요로하는'get_Type' 메소드 – Matthew

+0

기본적으로 C++에서'CreateSingle'의 결과는'ValueScalar '입니다. 그러나 C#에서는 어떤 이유에서든 보통'float'이됩니다 – Matthew

+0

이것이 내가해야 할 일이기 때문에 나는 이것을 대답으로 표시하고있다. 더 나은 방법이 있다면 항상 돌아올 수 있습니다. 감사. – Matthew