From c5d7f03194daf5ad0931dcc13a90fd0ab564434f Mon Sep 17 00:00:00 2001 From: jpbruyere Date: Tue, 1 Mar 2016 12:54:52 +0100 Subject: [PATCH] first tests with Interface update in a separate thread --- Crow.csproj | 1 + OTKCrow/OpenTKGameWindow.cs | 78 +++++++++++++++++------------ Tests/GOLIBTestsOTK.cs | 11 ++-- src/GraphicObjects/GraphicObject.cs | 27 +++++----- src/Interface.cs | 70 +++++++++++++++++++------- 5 files changed, 121 insertions(+), 66 deletions(-) diff --git a/Crow.csproj b/Crow.csproj index 735426e5..59b4228c 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -23,6 +23,7 @@ 2.0 v4.5 AnyCPU + 0.4 true diff --git a/OTKCrow/OpenTKGameWindow.cs b/OTKCrow/OpenTKGameWindow.cs index c3240b99..df1c4261 100644 --- a/OTKCrow/OpenTKGameWindow.cs +++ b/OTKCrow/OpenTKGameWindow.cs @@ -37,7 +37,8 @@ namespace Crow public event EventHandler ValueChanged; public virtual void NotifyValueChanged(string MemberName, object _value) { - ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + if (ValueChanged != null) + ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value)); } #endregion @@ -101,12 +102,27 @@ namespace Crow 3,3,OpenTK.Graphics.GraphicsContextFlags.Debug) // public OpenTKGameWindow(int _width, int _height, string _title="golib") // : base(_width, _height, new OpenTK.Graphics.GraphicsMode(32, 24, 0, 8), _title) + { + Thread t = new Thread (interfaceThread); + t.IsBackground = true; + t.Start (); + +// interfaceThread (); + } + #endregion + + void interfaceThread() { CrowInterface = new Interface (); + Interface.CurrentInterface = CrowInterface; CrowInterface.Quit += Quit; CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged; + + while (true) { + CrowInterface.Update (); + Thread.Sleep (1); + } } - #endregion public void Quit (object sender, EventArgs e) { @@ -176,21 +192,21 @@ namespace Crow GL.Viewport (0, 0, ClientRectangle.Width, ClientRectangle.Height); shader.Enable (); - - if (CrowInterface.IsDirty) { - byte[] tmp = new byte[4 * CrowInterface.DirtyRect.Width * CrowInterface.DirtyRect.Height]; - for (int y = 0; y < CrowInterface.DirtyRect.Height; y++) { - Array.Copy(CrowInterface.bmp, - ((CrowInterface.DirtyRect.Top + y) * ClientRectangle.Width * 4) + CrowInterface.DirtyRect.Left * 4, - tmp, y * CrowInterface.DirtyRect.Width * 4, CrowInterface.DirtyRect.Width *4); + lock (CrowInterface.RenderMutex) { + if (CrowInterface.IsDirty) { + byte[] tmp = new byte[4 * CrowInterface.DirtyRect.Width * CrowInterface.DirtyRect.Height]; + for (int y = 0; y < CrowInterface.DirtyRect.Height; y++) { + Array.Copy (CrowInterface.bmp, + ((CrowInterface.DirtyRect.Top + y) * ClientRectangle.Width * 4) + CrowInterface.DirtyRect.Left * 4, + tmp, y * CrowInterface.DirtyRect.Width * 4, CrowInterface.DirtyRect.Width * 4); + } + GL.TexSubImage2D (TextureTarget.Texture2D, 0, + CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top, + CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, + OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, tmp); + CrowInterface.IsDirty = false; } - GL.TexSubImage2D (TextureTarget.Texture2D, 0, - CrowInterface.DirtyRect.Left, CrowInterface.DirtyRect.Top, - CrowInterface.DirtyRect.Width, CrowInterface.DirtyRect.Height, - OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, tmp); - CrowInterface.IsDirty = false; } - uiQuad.Render (PrimitiveType.TriangleStrip); GL.BindTexture(TextureTarget.Texture2D, 0); @@ -232,18 +248,18 @@ namespace Crow protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); - fps = (int)RenderFrequency; - - - if (frameCpt > 50) { - resetFps (); - frameCpt = 0; - GC.Collect(); - GC.WaitForPendingFinalizers(); - NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); - } - frameCpt++; - CrowInterface.Update (); +// fps = (int)RenderFrequency; +// +// +// if (frameCpt > 50) { +// resetFps (); +// frameCpt = 0; +// GC.Collect(); +// GC.WaitForPendingFinalizers(); +// NotifyValueChanged("memory", GC.GetTotalMemory (false).ToString()); +// } +// frameCpt++; + //CrowInterface.Update (); } protected override void OnRenderFrame(FrameEventArgs e) { @@ -260,7 +276,7 @@ namespace Crow protected override void OnResize(EventArgs e) { base.OnResize (e); - CrowInterface.ProcessResize( + CrowInterface.ResizeDelegate.Invoke( new Rectangle( this.ClientRectangle.X, this.ClientRectangle.Y, @@ -270,7 +286,7 @@ namespace Crow } #endregion - #region Mouse Handling + #region Mouse Handling void update_mouseButtonStates(ref MouseState e, OpenTK.Input.MouseState otk_e){ for (int i = 0; i < MouseState.MaxButtons; i++) { if (otk_e.IsButtonDown ((OpenTK.Input.MouseButton)i)) @@ -295,10 +311,10 @@ namespace Crow } #endregion - #region keyboard Handling + #region keyboard Handling KeyboardState Keyboad = new KeyboardState (); void Keyboard_KeyDown(object sender, OpenTK.Input.KeyboardKeyEventArgs otk_e) - { + { // if (_focusedWidget == null) { KeyboardKeyDown.Raise (this, otk_e); // return; diff --git a/Tests/GOLIBTestsOTK.cs b/Tests/GOLIBTestsOTK.cs index 4256120b..a9416c20 100644 --- a/Tests/GOLIBTestsOTK.cs +++ b/Tests/GOLIBTestsOTK.cs @@ -77,7 +77,7 @@ namespace testOTK }; - public int intValue = 25; + volatile public int intValue = 25; public int IntValue { get { @@ -99,7 +99,7 @@ namespace testOTK return; NotifyValueChanged ("alignment", Enum.Parse(typeof(Alignment), rb.Caption)); } - public IList List2 = new List(new string[] + volatile public IList List2 = new List(new string[] { "string1", "string2", @@ -117,7 +117,7 @@ namespace testOTK "string9" } ); - IList testList = Color.ColorDic.ToList(); + volatile IList testList = Color.ColorDic.ToList(); public IList TestList { set{ testList = value; @@ -135,8 +135,9 @@ namespace testOTK //this.AddWidget(new test4()); KeyboardKeyDown += GOLIBTests_KeyboardKeyDown1;; - GraphicObject obj = CrowInterface.LoadInterface("Interfaces/" + testFiles[idx]); - obj.DataSource = this; + CrowInterface.LoadInterfaceDelegate.Invoke ("Interfaces/" + testFiles [idx]); + //GraphicObject obj = CrowInterface.LoadInterface("Interfaces/" + testFiles[idx]); + //obj.DataSource = this; } void GOLIBTests_KeyboardKeyDown1 (object sender, OpenTK.Input.KeyboardKeyEventArgs e) diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index b9fc6c3e..2bce3349 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -646,7 +646,8 @@ namespace Crow return; if (Interface.CurrentInterface == null) return; - Interface.CurrentInterface.gobjsToRedraw.Add (this); + lock(Interface.CurrentInterface.RenderMutex) + Interface.CurrentInterface.gobjsToRedraw.Add (this); IsQueuedForRedraw = true; } @@ -690,17 +691,19 @@ namespace Crow Debug.WriteLine ("REGLayout => {1}->{0}", layoutType, this.ToString()); #endif - //enqueue LQI LayoutingTypes separately - if (layoutType.HasFlag (LayoutingType.Width)) - Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this)); - if (layoutType.HasFlag (LayoutingType.Height)) - Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Height, this)); - if (layoutType.HasFlag (LayoutingType.X)) - Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.X, this)); - if (layoutType.HasFlag (LayoutingType.Y)) - Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Y, this)); - if (layoutType.HasFlag (LayoutingType.ArrangeChildren)) - Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this)); + lock (Interface.LayoutingQueue) { + //enqueue LQI LayoutingTypes separately + if (layoutType.HasFlag (LayoutingType.Width)) + Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this)); + if (layoutType.HasFlag (LayoutingType.Height)) + Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Height, this)); + if (layoutType.HasFlag (LayoutingType.X)) + Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.X, this)); + if (layoutType.HasFlag (LayoutingType.Y)) + Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Y, this)); + if (layoutType.HasFlag (LayoutingType.ArrangeChildren)) + Interface.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this)); + } } /// trigger dependant sizing component update diff --git a/src/Interface.cs b/src/Interface.cs index aacca09a..d82516b0 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -37,10 +37,21 @@ namespace Crow { public class Interface : ILayoutable { + public delegate void ResizeDelegatePrototype(Rectangle bounds); + public delegate void LoaderDelegatePrototype (string path); + public ResizeDelegatePrototype ResizeDelegate; + public LoaderDelegatePrototype LoadInterfaceDelegate; + #region CTOR - static Interface(){ + static Interface(){ Interface.LoadCursors (); } + public Interface(){ + Interface.CurrentInterface = this; + + LoadInterfaceDelegate = new LoaderDelegatePrototype(InterfaceLoad); + ResizeDelegate = new ResizeDelegatePrototype (ProcessResize); + } #endregion #region Static and constants @@ -187,6 +198,11 @@ namespace Crow return result; } + public void InterfaceLoad(string path){ + GraphicObject tmp = Interface.Load (path, this); + AddWidget (tmp); + } + public GraphicObject LoadInterface (string path) { GraphicObject tmp = Interface.Load (path, this); @@ -214,9 +230,10 @@ namespace Crow Context ctx; Surface surf; - public byte[] bmp; + volatile public byte[] bmp; public bool IsDirty = false; public Rectangle DirtyRect; + public object RenderMutex = new object(); #region focus GraphicObject _activeWidget; //button is pressed on widget @@ -283,12 +300,21 @@ namespace Crow layoutTime.Start (); #endif //Debug.WriteLine ("======= Layouting queue start ======="); - - while (Interface.LayoutingQueue.Count > 0) { - LayoutingQueueItem lqi = Interface.LayoutingQueue.Dequeue (); + int queueCount = 0; + LayoutingQueueItem lqi = null; + + lock (Interface.LayoutingQueue) + queueCount = Interface.LayoutingQueue.Count; + + while (queueCount > 0) { + lock (Interface.LayoutingQueue) + lqi = Interface.LayoutingQueue.Dequeue (); lqi.ProcessLayouting (); + lock (Interface.LayoutingQueue) + queueCount = Interface.LayoutingQueue.Count; } + #if MEASURE_TIME layoutTime.Stop (); #endif @@ -296,9 +322,12 @@ namespace Crow //Debug.WriteLine ("otd:" + gobjsToRedraw.Count.ToString () + "-"); //final redraw clips should be added only when layout is completed among parents, //that's why it take place in a second pass - GraphicObject[] gotr = new GraphicObject[gobjsToRedraw.Count]; - gobjsToRedraw.CopyTo (gotr); - gobjsToRedraw.Clear (); + GraphicObject[] gotr = null; + lock (Interface.CurrentInterface.RenderMutex) { + gotr = new GraphicObject[gobjsToRedraw.Count]; + gobjsToRedraw.CopyTo (gotr); + gobjsToRedraw.Clear (); + } foreach (GraphicObject p in gotr) { try { p.IsQueuedForRedraw = false; @@ -339,16 +368,18 @@ namespace Crow clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); #endif - if (IsDirty) - DirtyRect += clipping.Bounds; - else - DirtyRect = clipping.Bounds; - IsDirty = true; - - DirtyRect.Left = Math.Max (0, DirtyRect.Left); - DirtyRect.Top = Math.Max (0, DirtyRect.Top); - DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); - DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); + lock (RenderMutex) { + if (IsDirty) + DirtyRect += clipping.Bounds; + else + DirtyRect = clipping.Bounds; + IsDirty = true; + + DirtyRect.Left = Math.Max (0, DirtyRect.Left); + DirtyRect.Top = Math.Max (0, DirtyRect.Top); + DirtyRect.Width = Math.Min (ClientRectangle.Width - DirtyRect.Left, DirtyRect.Width); + DirtyRect.Height = Math.Min (ClientRectangle.Height - DirtyRect.Top, DirtyRect.Height); + } clipping.Reset (); } @@ -429,6 +460,9 @@ namespace Crow } return null; } + + + public void ProcessResize(Rectangle bounds){ clientRectangle = bounds; -- 2.47.3