14876efdaa4a3de2038086045ffad09a1d8c6a2d
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / DirectRenderingGLView.cs
1 using System;
2 using System.ComponentModel;
3 using System.Runtime.InteropServices;
4 using System.Collections.Generic;
5 using System.Collections.ObjectModel;
6 using System.Diagnostics.CodeAnalysis;
7
8 namespace Tizen.NUI.BaseComponents
9 {
10     /// <summary>
11     /// DirectRenderingGLView allows drawing with OpenGL. You can render to a Window directly.
12     /// DirectRenderingGLView creates a context.
13     /// </summary>
14     /// <since_tizen> 11 </since_tizen>
15     [EditorBrowsable(EditorBrowsableState.Never)]
16     public class DirectRenderingGLView : View
17     {
18         /// <summary>
19         /// The parameter of the RenderFrame Callback.
20         /// It has data to render directly.
21         /// </summary>
22         [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
23         public class RenderCallbackInput
24         {
25             Matrix mvp;
26             Matrix projection;
27             Size2D size;
28             Rectangle clippingBox;
29             ReadOnlyCollection<int> textureBindings;
30
31             public RenderCallbackInput(Matrix mvp, Matrix projection, Size2D size, Rectangle clippingBox, int[] textureBindings)
32             {
33                 this.mvp = mvp;
34                 this.projection = projection;
35                 this.size = size;
36                 this.clippingBox = clippingBox;
37                 this.textureBindings = new ReadOnlyCollection<int>(textureBindings);
38             }
39
40             /// <summary>
41             /// MVP matrix
42             /// </summary>
43             public Matrix Mvp
44             {
45                 get { return mvp; }
46             }
47
48             /// <summary>
49             /// Projection matrix
50             /// </summary>
51             public Matrix Projection
52             {
53                 get { return projection; }
54             }
55
56             /// <summary>
57             /// The size of the DirectRenderingGLView
58             /// </summary>
59             public Size2D Size
60             {
61                 get { return size; }
62             }
63
64             /// <summary>
65             /// The area of DirectRenderingGLView. You can use this for glScissor()
66             /// </summary>
67             public Rectangle ClippingBox
68             {
69                 get { return clippingBox; }
70             }
71
72             /// <summary>
73             /// Texture bindings
74             /// </summary>
75             public ReadOnlyCollection<int> TextureBindings
76             {
77                 get { return textureBindings; }
78             }
79         }
80
81         private GLInitializeDelegate glInitializeCallback;
82         private GLRenderFrameDelegate glRenderFrameCallback;
83         private GLTerminateDelegate glTerminateCallback;
84         private InternalGLRenderFrameDelegate internalRenderFrameCallback;
85
86         /// <summary>
87         /// Type of callback to initialize OpenGLES.
88         /// </summary>
89         public delegate void GLInitializeDelegate();
90
91         /// <summary>
92         /// Type of callback to render the frame with OpenGLES APIs.
93         /// If the return value of this callback is not 0, the eglSwapBuffers() will be called.
94         /// </summary>
95         /// <returns>The return value is not 0, the eglSwapBuffers() will be called.</returns>
96         public delegate int GLRenderFrameDelegate(in RenderCallbackInput input);
97
98         private delegate int InternalGLRenderFrameDelegate(global::System.IntPtr cPtr);
99
100         /// <summary>
101         /// Type of callback to clean up GL resource.
102         /// </summary>
103         public delegate void GLTerminateDelegate();
104
105         internal DirectRenderingGLView(global::System.IntPtr cPtr, bool cMemoryOwn) : base(cPtr, cMemoryOwn)
106         {
107         }
108
109         /// <summary>
110         /// Creates an initialized DirectRenderingGLView.
111         /// </summary>
112         /// <param name="colorFormat">The format of the color buffer</param>
113         public DirectRenderingGLView(ColorFormat colorFormat) : this(Interop.GLView.New(0, (int)colorFormat), true)
114         {
115             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
116         }
117
118         /// <summary>
119         /// Creates an initialized DirectRenderingGLView.
120         /// </summary>
121         /// <param name="colorFormat">The format of the color buffer</param>
122         /// <param name="backendMode">The backend mode</param>
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public DirectRenderingGLView(ColorFormat colorFormat, BackendMode backendMode) : this(Interop.GLView.New((int)backendMode, (int)colorFormat), true)
125         {
126             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
127         }
128
129         /// <summary>
130         /// Enumeration for the color format of the color buffer
131         /// </summary>
132         public enum ColorFormat
133         {
134             /// <summary>
135             /// 8 red bits, 8 green bits, 8 blue bits
136             /// </summary>
137             RGB888 = 0,
138
139             /// <summary>
140             /// 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits
141             /// </summary>
142             RGBA8888
143         }
144
145         /// <summary>
146         /// Enumeration for backend mode
147         /// </summary>
148         [EditorBrowsable(EditorBrowsableState.Never)]
149         public enum BackendMode
150         {
151             /// <summary>
152             /// DirectRendering mode executes GL code within DALi graphics
153             /// pipeline but creates isolated context hence it doesn't alter any
154             /// DALi rendering state. When Renderer is about to be drawn, the callback
155             /// will be executed and the custom code "injected" into the pipeline.
156             /// This allows rendering directly to the surface rather than offscreen.
157             /// </summary>
158             DirectRendering = 0,
159
160             /// <summary>
161             /// DirectRenderingThread mode executes GL code on separate thread
162             /// and then blits the result within DALi graphics commands stream.
163             /// The mode is logically compatible with the EglImageOffscreenRendering.
164             /// </summary>
165             DirectRenderingThread,
166
167             /// <summary>
168             /// EglImageOffscreenRendering mode executes GL code in own thread
169             /// and renders to the offscreen NativeImage (EGL) buffer. This backend
170             /// will render in parallel but has higher memory footprint and may suffer
171             /// performance issues due to using EGL image.
172             /// </summary>
173             EglImageOffscreenRendering,
174
175             /// <summary>
176             /// UnsafeDirectRendering mode executes GL code within DALi graphics
177             /// pipeline WITHOUT isolating the GL context so should be used with caution!
178             /// The custom rendering code is executed within current window context and
179             /// may alter the GL state. This mode is considered unsafe and should be used
180             /// only when drawing on main GL context is necessary!
181             ///
182             /// When Renderer is about to be drawn, the callback
183             /// will be executed and the custom code "injected" into the pipeline.
184             /// This allows rendering directly to the surface rather than offscreen.
185             /// </summary>
186             UnsafeDirectRendering
187         }
188
189         /// <summary>
190         /// Gets or sets the rendering mode of the DirectRenderingGLView.
191         /// </summary>
192         public GLRenderingMode RenderingMode
193         {
194             [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "SWIG boilerplate, no exceptions are expected")]
195             get
196             {
197                 GLRenderingMode ret = (GLRenderingMode)Interop.GLView.GlViewGetRenderingMode(SwigCPtr);
198                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
199                 return ret;
200             }
201             set
202             {
203                 Interop.GLView.GlViewSetRenderingMode(SwigCPtr, (int)value);
204                 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
205             }
206         }
207
208         /// <summary>
209         /// Registers GL callback functions to render with OpenGL ES
210         /// </summary>
211         /// <param name="glInit">The callback function for GL initialization</param>
212         /// <param name="glRenderFrame">The callback function to render the frame</param>
213         /// <param name="glTerminate">The callback function to clean up GL resources</param>
214         public void RegisterGLCallbacks(GLInitializeDelegate glInit, GLRenderFrameDelegate glRenderFrame, GLTerminateDelegate glTerminate)
215         {
216             glInitializeCallback = glInit;
217             HandleRef InitHandleRef = new HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(glInitializeCallback));
218
219             glRenderFrameCallback = glRenderFrame;
220             internalRenderFrameCallback = OnRenderFrame;
221             HandleRef RenderHandlerRef = new HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(internalRenderFrameCallback));
222
223             glTerminateCallback = glTerminate;
224             HandleRef TerminateHandlerRef = new HandleRef(this, Marshal.GetFunctionPointerForDelegate<Delegate>(glTerminateCallback));
225
226             Interop.GLView.GlViewRegisterGlCallbacks(SwigCPtr, InitHandleRef, RenderHandlerRef, TerminateHandlerRef);
227
228             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
229         }
230
231         /// <summary>
232         /// Binds textures to own context.
233         /// You can get the bind IDs in RenderCallbackInput in the glRenderFrame callback.
234         /// </summary>
235         /// <param name="textures">List of Textures</param>
236         /// <exception cref="OverflowException"> Thrown when length of textures list is overflow. </exception>
237         public void BindTextureResources(List<Texture> textures)
238         {
239             unsafe
240             {
241                 if (textures != null)
242                 {
243                     int count = textures.Count;
244                     if (count > 0)
245                     {
246                         IntPtr[] texturesArray = new IntPtr[count];
247                         for (int i = 0; i < count; i++)
248                         {
249                             texturesArray[i] = HandleRef.ToIntPtr(Texture.getCPtr(textures[i]));
250                         }
251                         IntPtr unmanagedPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)) * count);
252                         Marshal.Copy(texturesArray, 0, unmanagedPointer, count);
253
254                         Interop.GLView.GlViewBindTextureResources(SwigCPtr, unmanagedPointer, count);
255                         Marshal.FreeHGlobal(unmanagedPointer);
256                     }
257                 }
258             }
259         }
260
261         /// <summary>
262         /// Sets graphics configuration for the DirectRenderingGLView
263         /// </summary>
264         /// <param name="depth">The flag of depth buffer. When the value is true, 24bit depth buffer is enabled.</param>
265         /// <param name="stencil">The flag of stencil. When the value is true, 8bit stencil buffer is enabled.</param>
266         /// <param name="msaa">The bit of MSAA</param>
267         /// <param name="version">The GLES version</param>
268         /// <returns>True if the config was successfully set, false otherwise.</returns>
269         public bool SetGraphicsConfig(bool depth, bool stencil, int msaa, GLESVersion version)
270         {
271             bool ret = Interop.GLView.GlViewSetGraphicsConfig(SwigCPtr, depth, stencil, msaa, (int)version);
272             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
273             return ret;
274         }
275
276         /// <summary>
277         /// Renders once more, even when paused.
278         /// </summary>
279         public void RenderOnce()
280         {
281             Interop.GLView.GlViewRenderOnce(SwigCPtr);
282             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
283         }
284
285         private int OnRenderFrame(global::System.IntPtr cPtr)
286         {
287             if (glRenderFrameCallback != null)
288             {
289                 Matrix mvp = Matrix.GetMatrixFromPtr(Interop.GLView.GlViewGetRednerCallbackInputMvp(cPtr));
290                 Matrix projection = Matrix.GetMatrixFromPtr(Interop.GLView.GlViewGetRednerCallbackInputProjection(cPtr));
291                 Size2D size = Size2D.GetSize2DFromPtr(Interop.GLView.GlViewGetRednerCallbackInputSize(cPtr));
292                 Rectangle clippingBox = Rectangle.GetRectangleFromPtr(Interop.GLView.GlViewGetRednerCallbackInputClipplingBox(cPtr));
293                 int[] textureBindings = GetTextureBindings(cPtr);
294
295                 RenderCallbackInput input = new RenderCallbackInput(mvp, projection, size, clippingBox, textureBindings);
296
297                 return glRenderFrameCallback(input);
298             }
299             return 0;
300         }
301
302         private static int[] GetTextureBindings(global::System.IntPtr cPtr)
303         {
304             int bindingSize = 0;
305             global::System.IntPtr arrayPtr = Interop.GLView.GlViewGetRednerCallbackInputTextureBindings(cPtr, ref bindingSize);
306             if (bindingSize != 0)
307             {
308                 int[] result = new int[bindingSize];
309                 System.Runtime.InteropServices.Marshal.Copy(arrayPtr, result, 0, bindingSize);
310                 return result;
311             }
312             else
313             {
314                 return Array.Empty<int>();
315             }
316         }
317     }
318 }