visual studio programación programacion lenguaje guía comandos codigos basicos avanzada c# .net opengl c++-cli interop

studio - programacion avanzada c#



Intentando convertir C++ en C#con interoperabilidad (2)

Tengo un programa que llama a EGL en C ++. Quiero hacer la misma llamada en C #, pero no parece haber un concepto equivalente en C #.

Recibo un error de acceso de lectura / escritura cuando el contexto de ejecución ingresa el código C ++ EGL.

Este es el código en el programa C ++ que intento convertir a C #:

PropertySet^ surfaceCreationProperties = ref new PropertySet(); surfaceCreationProperties->Insert(ref new String(EGLNativeWindowTypeProperty), somethingOtherThanAWindow); mEglSurface = eglCreateWindowSurface(mEglDisplay, config, reinterpret_cast<IInspectable*>(surfaceCreationProperties), surfaceAttributes));

Tengo una clase C # que convierte llamadas C # EGL en llamadas C ++. Creo que el C ++ no está administrado, aunque no sabría decírtelo con certeza.

La clase C # se ve así:

public static IntPtr CreateWindowSurface(IntPtr dpy, IntPtr config, IntPtr win, int[] attrib_list) { IntPtr retValue; unsafe { fixed (int* p_attrib_list = attrib_list) { retValue = Delegates.peglCreateWindowSurface(dpy, config, win, p_attrib_list); } } return (retValue); }

Se puede ver más de ese código aquí: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/Egl.VERSION_1_0.cs#L751

Puede observar que este método tiene una IntPtr win ; aquí es donde paso el PropertySet . Por lo general, creo que esto sería un System.Windows.Forms.Control , pero se realiza alguna comprobación en el código C ++ EGL para ver si lo está, o si se trata de un PropertySet .

El método de C ++ que se está llamando es este:

EGLSurface EGLAPIENTRY CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)

Se puede ver más aquí: https://github.com/Microsoft/angle/blob/ms-holographic-experimental/src/libGLESv2/entry_points_egl.cpp#L241

Como puede ver, el método C ++ espera un EGLNativeWindowType. No estoy exactamente seguro de cuál es la relación con eso entre un IInspectable y un PropertSet. Parece extraño que se pueda descifrar.

EGLNativeWindowType tiene la siguiente definición de tipo:

typedef HWND EGLNativeWindowType;

Lo que implica que tiene que ser una especie de identificador de ventana. No entiendo cómo un PropertySet podría ser un identificador de ventana.

Sospecho que el principal problema está en elegir el tipo correcto de objeto para pasar a la implementación C # EGL. PropertySet parece que podría ser la elección correcta, pero el reinterpret_cast realmente me está echando.

¿Alguien puede guiarme a través de esto?


Creo que el tipo de parámetro es definitivamente incorrecto.

Para obtener un ejemplo completo, debe leer la implementación de DeviceContext en https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/NativeDeviceContext.cs . También debería ver dónde se llama este código, para obtener la secuencia de llamadas real necesaria para inicializar EGL: - método de fábrica: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/ DeviceContextFactory.cs - control de integración: https://github.com/luca-piccioni/OpenGL.Net/blob/master/OpenGL.Net/GlControl.cs

Como puede ver, el identificador es la propiedad Control.Handle. Probablemente, el valor real que se debe aprobar depende del sistema operativo actual que implementa EGL, pero debe ser un identificador de la ventana (o control) que aloja los resultados del dibujo.

Alternativamente, puede verificar la implementación del método EGL real y seguir el uso de parámetros hasta la llamada real de DirectX, solo lo hice en ese momento.


Por lo general, creo que esto sería un System.Windows.Forms.Control ...

Es una suposición dolorosamente errónea. Darle sentido a la escritura requiere escribir tres libros, bastante difícil de hacer en una respuesta SO. Si tiene la intención de hacer esto desde una aplicación de Winforms entonces deténgase ahora mismo, eso nunca funcionará.

OpenGL usa tipados muy sueltos, los argumentos para sus funciones api son nada más que void* , un puntero sin formato. Lo que lo hace muy flexible, pero es realmente importante a lo que apunta el puntero. Si el programa del cliente y la interfaz del adaptador de video no están de acuerdo con eso de la manera más leve , entonces su programa se compilará bien, pero se bloqueará y se quemará de manera completamente no diagnosticable en el tiempo de ejecución. Una razón importante por la cual Microsoft abandonó OpenGL y decidió crear la suya propia, DirectX fue el resultado.

Lo cual también utiliza punteros pero son del tipo más inteligente, admiten el descubrimiento de tipo en tiempo de ejecución. Son punteros IUnknown , su método QueryInterface () permite descubrir si un objeto admite una interfaz esperada específica. El sabor que ve que se usa aquí es exactamente el mismo tipo de puntero, IInspectable es una versión un poco más inteligente que IUnknown y la interfaz base implementada por todas las clases de WinRT. Realmente tiene que pasar un IInspectable * ya que eso es lo que espera el puerto ANGLE.

En general, esperaría que pudiera pasar un puntero de interfaz de ICoreWindow y terminar con eso, esa es la interfaz de WinRT para una ventana. Sin embargo, el procesador requiere más información que solo la ventana principal. No estoy seguro de por qué, creo que tiene algo que ver con la resolución Independence en WinRT. También necesita conocer el tamaño de la superficie y el factor de escala.

El problema es que OpenGL no tiene forma de pasar esa información. Entonces, el programador de Microsoft usó un truco de hokey, en lugar de agregar una función para pasar esta información, si usó la capacidad de pasar cualquier tipo de IInspectable *, pasa un IMap<String^, IInspectable*> . Básicamente, una bolsa de propiedades, CoreWindowNativeWindow.cpp en el puerto ANGLE extrae las propiedades de la bolsa de nuevo en su función CoreWindowNativeWindow :: initialize ().

PropertySet es una clase concreta en la proyección del lenguaje C ++ que implementa IMap<K, V> . Tenga en cuenta que es específico de C ++, en C # usaría un Dictionary<string, IntPtr> lugar. La proyección del lenguaje integrada en el CLR asigna automáticamente un diccionario administrado a la interfaz IMap nativa.

Oh alegría, más IntPtrs. IInspectable * está completamente oculto en la proyección de idioma que usa en C #, eso no lo hace fácil. Estoy 98% seguro de que puedes usar Marshal.GetIUnknownForObject () para obtener un puntero que funcione, aunque tenga un sabor incorrecto. Dado que el código de C ++ hace lo correcto y utiliza QueryInterface :) Debe llamar a Marshal.Release () para limpiar después, no hacerlo provoca una pérdida de memoria.

Tenga en cuenta que hay fuertes matices de que está haciendo lo incorrecto. Creo que lo es, Microsoft proporcionó este tenedor ANGLE solo por una razón. Intentaron facilitar a las empresas el portar su juego de iOS a WinRT / UWP. Algo necesario para llenar la tienda con el tipo de juegos que les gusta a los clientes. El puerto ANGLE solo fue pensado para ser fácil de usar desde el código que se inició en ObjectiveC o C ++, el tipo de lenguaje utilizado para escribir estos juegos.

Podrían haber hecho mucho más fácil utilizar la biblioteca de idiomas como Javascript o C #, no lo hicieron porque no era necesario. Si tiene que traducir una milla de métrica de código C ++ que usa OpenGL a C #, entonces es bastante probable que esté mucho mejor cuando use DirectX. Espere más de este tipo de problemas de mapeo con otras funciones y esté cansado de un puerto HoloLens experimental.