<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591;1587;1570;1572;1573;1574</NoWarn>
- <DefineConstants>DESIGN_MODE</DefineConstants>
+ <DefineConstants>DESIGN_MODE;_MEASURE_TIME</DefineConstants>
<EnableDefaultItems>false</EnableDefaultItems>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<AppConfig>App.config</AppConfig>
--- /dev/null
+// Copyright (c) 2013-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Diagnostics;
+
+namespace Crow
+{
+ public class PerformanceMeasure : IValueChange {
+ #region IValueChange implementation
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
+ public virtual void NotifyValueChanged(string MemberName, object _value)
+ {
+ if (ValueChanged != null)
+ ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value));
+ }
+ #endregion
+ public enum Kind
+ {
+ Update,
+ Clipping,
+ Layouting,
+ Drawing
+ }
+ public static PerformanceMeasure[] Measures;
+
+ [Conditional("MEASURE_TIME")]
+ public static void InitMeasures () {
+ Measures = new PerformanceMeasure[4];
+ Measures[(int)Kind.Update] = new PerformanceMeasure (Kind.Update, 1);
+ Measures[(int)Kind.Clipping] = new PerformanceMeasure (Kind.Clipping, 1);
+ Measures[(int)Kind.Layouting] = new PerformanceMeasure (Kind.Layouting, 1);
+ Measures[(int)Kind.Drawing] = new PerformanceMeasure (Kind.Drawing, 1);
+ }
+ [Conditional ("MEASURE_TIME")]
+ public static void Notify () {
+ for (int i = 0; i < 4; i++)
+ Measures[i].NotifyChanges ();
+ }
+ [Conditional ("MEASURE_TIME")]
+ public static void Begin (Kind kind) {
+ Measures[(int)kind].StartCycle ();
+ }
+ [Conditional ("MEASURE_TIME")]
+ public static void End (Kind kind) {
+ Measures[(int)kind].StopCycle ();
+ }
+
+
+ public Stopwatch timer = new Stopwatch ();
+ public readonly Kind MeasureKind;
+ public long current, minimum, maximum, total, cptMeasures;
+ public long cancelLimit;
+ public string Name => MeasureKind.ToString ();
+
+ public PerformanceMeasure (Kind measureKind, long _cancelLimit = 0){
+ MeasureKind = measureKind;
+ cancelLimit = _cancelLimit;
+ ResetStats ();
+ }
+
+ public void StartCycle(){
+ timer.Restart();
+ }
+ public void StopCycle(){
+ timer.Stop();
+ computeStats ();
+ }
+ public void NotifyChanges(){
+ lock(this){
+ if (cptMeasures == 0)
+ return;
+ NotifyValueChanged("minimum", minimum);
+ NotifyValueChanged("maximum", maximum);
+ NotifyValueChanged("current", current);
+ // NotifyValueChanged("total", total);
+ // NotifyValueChanged("cptMeasures", cptMeasures);
+ NotifyValueChanged("mean", total / cptMeasures);
+ }
+ }
+
+ void computeStats(){
+ current = timer.ElapsedMilliseconds;
+ if (current < cancelLimit)
+ return;
+ cptMeasures++;
+ total += timer.ElapsedMilliseconds;
+ if (timer.ElapsedMilliseconds < minimum)
+ minimum = timer.ElapsedMilliseconds;
+ if (timer.ElapsedMilliseconds > maximum)
+ maximum = timer.ElapsedMilliseconds;
+ }
+ void ResetStats(){
+ Debug.WriteLine("reset measure cpt:{0}",cptMeasures);
+ cptMeasures = total = current = maximum = 0;
+ minimum = long.MaxValue;
+ }
+ void onResetClick(object sender, MouseButtonEventArgs e){
+ lock(this)
+ ResetStats();
+ }
+ }
+}
+
};
t.Start ();
}
+
+ PerformanceMeasure.InitMeasures ();
}
#endregion
+#if MEASURE_TIME
+ public PerformanceMeasure[] PerfMeasures => PerformanceMeasure.Measures;
+#endif
/** GLFW callback may return a custom pointer, this list makes the link between the GLFW window pointer and the
manage VkWindow instance. */
static Dictionary<IntPtr, Interface> windows = new Dictionary<IntPtr, Interface> ();
if (!Monitor.TryEnter (UpdateMutex))
return;
-
+
DbgLogger.StartEvent (DbgEvtType.Update);
+ PerformanceMeasure.Begin (PerformanceMeasure.Kind.Update);
processLayouting ();
}else
processDrawing (ctx);
+ PerformanceMeasure.End (PerformanceMeasure.Kind.Update);
DbgLogger.EndEvent (DbgEvtType.Update, true);
Monitor.Exit (UpdateMutex);
+
+ PerformanceMeasure.Notify ();
}
/// <summary>Layouting loop, this is the first step of the udpate and process registered
/// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which
/// trigger an enqueue for the next Update Cycle</summary>
protected virtual void processLayouting(){
if (Monitor.TryEnter (LayoutMutex)) {
-
+ if (LayoutingQueue.Count == 0) {
+ Monitor.Exit (LayoutMutex);
+ return;
+ }
DbgLogger.StartEvent (DbgEvtType.Layouting);
+ PerformanceMeasure.Begin (PerformanceMeasure.Kind.Layouting);
DiscardQueue = new Queue<LayoutingQueueItem> ();
//Debug.WriteLine ("======= Layouting queue start =======");
}
LayoutingQueue = DiscardQueue;
+ PerformanceMeasure.End (PerformanceMeasure.Kind.Layouting);
DbgLogger.EndEvent (DbgEvtType.Layouting, true);
Monitor.Exit (LayoutMutex);
/// Clipping rectangles are added at each level of the tree from leef to root, that's the way for the painting
/// operation to known if it should go down in the tree for further graphic updates and repaints</summary>
void clippingRegistration(){
+ if (ClippingQueue.Count == 0)
+ return;
DbgLogger.StartEvent (DbgEvtType.Clipping);
+ PerformanceMeasure.Begin (PerformanceMeasure.Kind.Clipping);
Widget g = null;
while (ClippingQueue.Count > 0) {
g.ClippingRegistration ();
}
+ PerformanceMeasure.End (PerformanceMeasure.Kind.Clipping);
DbgLogger.EndEvent (DbgEvtType.Clipping, true);
}
/// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
if (DragImage != null)
clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight));
- if (!clipping.IsEmpty) {
- IsDirty = true;
- ctx.PushGroup ();
+ if (!clipping.IsEmpty) {
+ PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing);
+ IsDirty = true;
+
+ ctx.PushGroup ();
- for (int i = GraphicTree.Count -1; i >= 0 ; i--){
- Widget p = GraphicTree[i];
- if (!p.Visible)
- continue;
- if (clipping.Contains (p.Slot) == RegionOverlap.Out)
- continue;
+ for (int i = GraphicTree.Count -1; i >= 0 ; i--){
+ Widget p = GraphicTree[i];
+ if (!p.Visible)
+ continue;
+ if (clipping.Contains (p.Slot) == RegionOverlap.Out)
+ continue;
+ ctx.Save ();
+ p.Paint (ref ctx);
+ ctx.Restore ();
+ }
+
+ if (DragAndDropOperation != null) {
+ if (DragImage != null) {
+ DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight);
+ DragImageX = MousePosition.X - DragImageWidth / 2;
+ DragImageY = MousePosition.Y - DragImageHeight / 2;
ctx.Save ();
- p.Paint (ref ctx);
+ ctx.ResetClip ();
+ ctx.SetSource (DragImage, DragImageX, DragImageY);
+ ctx.PaintWithAlpha (0.8);
ctx.Restore ();
+ DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight);
+ IsDirty = true;
+ //System.Diagnostics.Debug.WriteLine ("dragimage drawn: {0},{1}", DragImageX, DragImageY);
}
-
- if (DragAndDropOperation != null) {
- if (DragImage != null) {
- DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight);
- DragImageX = MousePosition.X - DragImageWidth / 2;
- DragImageY = MousePosition.Y - DragImageHeight / 2;
- ctx.Save ();
- ctx.ResetClip ();
- ctx.SetSource (DragImage, DragImageX, DragImageY);
- ctx.PaintWithAlpha (0.8);
- ctx.Restore ();
- DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight);
- IsDirty = true;
- //System.Diagnostics.Debug.WriteLine ("dragimage drawn: {0},{1}", DragImageX, DragImageY);
- }
- }
+ }
#if DEBUG_CLIP_RECTANGLE
- ctx.LineWidth = 1;
- ctx.SetSourceColor(Color.Magenta.AdjustAlpha (0.5));
- for (int i = 0; i < clipping.NumRectangles; i++)
- ctx.Rectangle(clipping.GetRectangle(i));
- ctx.Stroke ();
+ ctx.LineWidth = 1;
+ ctx.SetSourceColor(Color.Magenta.AdjustAlpha (0.5));
+ for (int i = 0; i < clipping.NumRectangles; i++)
+ ctx.Rectangle(clipping.GetRectangle(i));
+ ctx.Stroke ();
#endif
- ctx.PopGroupToSource ();
+ ctx.PopGroupToSource ();
- for (int i = 0; i < clipping.NumRectangles; i++)
- ctx.Rectangle (clipping.GetRectangle (i));
+ for (int i = 0; i < clipping.NumRectangles; i++)
+ ctx.Rectangle (clipping.GetRectangle (i));
- ctx.ClipPreserve ();
- ctx.Operator = Operator.Clear;
- ctx.Fill ();
- ctx.Operator = Operator.Over;
+ ctx.ClipPreserve ();
+ ctx.Operator = Operator.Clear;
+ ctx.Fill ();
+ ctx.Operator = Operator.Over;
- ctx.Paint ();
+ ctx.Paint ();
- surf.Flush ();
+ surf.Flush ();
- clipping.Dispose ();
- clipping = new Region ();
- }
+ clipping.Dispose ();
+ clipping = new Region ();
+
+ PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing);
+ }
DbgLogger.EndEvent (DbgEvtType.Drawing, true);
}
+++ /dev/null
-//
-// PerformanceMeasure.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-using System;
-using System.Diagnostics;
-
-namespace Crow
-{
- public class PerformanceMeasure : IValueChange {
- #region IValueChange implementation
- public event EventHandler<ValueChangeEventArgs> ValueChanged;
- public virtual void NotifyValueChanged(string MemberName, object _value)
- {
- if (ValueChanged != null)
- ValueChanged.Invoke(this, new ValueChangeEventArgs(MemberName, _value));
- }
- #endregion
-
- public Stopwatch timer = new Stopwatch ();
- public string Name;
- public long current, minimum, maximum, total, cptMeasures;
- public long cancelLimit;
-
- public PerformanceMeasure(string name = "unamed", long _cancelLimit = 0){
- Name = name;
- cancelLimit = _cancelLimit;
- ResetStats ();
- }
-
- public void StartCycle(){
- timer.Restart();
- }
- public void StopCycle(){
- timer.Stop();
- computeStats ();
- }
- public void NotifyChanges(){
- lock(this){
- if (cptMeasures == 0)
- return;
- NotifyValueChanged("minimum", minimum);
- NotifyValueChanged("maximum", maximum);
- NotifyValueChanged("current", current);
- // NotifyValueChanged("total", total);
- // NotifyValueChanged("cptMeasures", cptMeasures);
- NotifyValueChanged("mean", total / cptMeasures);
- }
- }
-
- void computeStats(){
- current = timer.ElapsedMilliseconds;
- if (current < cancelLimit)
- return;
- cptMeasures++;
- total += timer.ElapsedMilliseconds;
- if (timer.ElapsedMilliseconds < minimum)
- minimum = timer.ElapsedMilliseconds;
- if (timer.ElapsedMilliseconds > maximum)
- maximum = timer.ElapsedMilliseconds;
- }
- void ResetStats(){
- Debug.WriteLine("reset measure cpt:{0}",cptMeasures);
- cptMeasures = total = current = maximum = 0;
- minimum = long.MaxValue;
- }
- void onResetClick(object sender, MouseButtonEventArgs e){
- lock(this)
- ResetStats();
- }
- }
-}
-
ClearInterface ();
if (resetStylesAndTemplates) {
- this.Styling.Clear ();
- this.StylingConstants.Clear ();
+ //this.Styling.Clear ();
+ //this.StylingConstants.Clear ();
this.Instantiators.Clear ();
this.Templates.Clear ();
this.DefaultTemplates.Clear ();