]> O.S.I.I.S - jp/crow.git/commitdiff
drm double buffered, but disposing not ok
authorjpbruyere <jp.bruyere@hotmail.com>
Sun, 21 May 2017 16:24:35 +0000 (18:24 +0200)
committerjpbruyere <jp.bruyere@hotmail.com>
Sun, 21 May 2017 16:24:35 +0000 (18:24 +0200)
17 files changed:
CrowIDE/CrowIDE.csproj
src/PerformanceMeasure.cs
testDrm/Main.cs
testDrm/src/Application.cs
testDrm/src/Egl/Context.cs
testDrm/src/Linux/DRI.cs [deleted file]
testDrm/src/Linux/DRI/DRIControler.cs [new file with mode: 0644]
testDrm/src/Linux/DRI/Plane.cs
testDrm/src/Linux/DRI/PlaneResources.cs [new file with mode: 0644]
testDrm/src/Linux/GBM/BufferObject.cs
testDrm/src/Linux/GBM/Surface.cs
testDrm/testDrm.csproj
testDrm/ui/0.crow
testDrm/ui/2.crow
testDrm/ui/menu.crow
testDrm/ui/perfMeasures.crow [new file with mode: 0755]
testDrm/ui/perfMsr.crow [new file with mode: 0755]

index 1773f75051c5f06d455463c40555f5c16ce12e16..90cd929099bb714860cb76b8d6eadec7fba5c374 100644 (file)
@@ -45,9 +45,6 @@
     <Reference Include="System.Data" />
     <Reference Include="System.Xml" />
     <Reference Include="System.Drawing" />
-    <Reference Include="cairo-sharp">
-      <Package>gtk-sharp-3.0</Package>
-    </Reference>
     <Reference Include="OpenTK">
       <HintPath>$(SolutionDir)packages\OpenTK.2.0.0\lib\net20\OpenTK.dll</HintPath>
       <Package>opentk</Package>
index 1db29e30484630a9e0f9fd2519fbb76259cc7e29..f5c39e35890dac6225f47755848c5ffe7572830b 100644 (file)
@@ -70,8 +70,8 @@ namespace Crow
 
                void computeStats(){                    
                        current = timer.ElapsedTicks;
-                       if (current < cancelLimit)
-                               return;
+//                     if (current < cancelLimit)
+//                             return;
                        cptMeasures++;
                        total += timer.ElapsedTicks;
                        if (timer.ElapsedTicks < minimum)
index 528a8e958b304743c1ba7f0b18e56df2834ee6ca..d13108bfc7e884c17008e024746fafc5cd7f8aff 100644 (file)
@@ -62,9 +62,27 @@ namespace testDrm
                #endregion
 
 
+               #if MEASURE_TIME
+               public List<PerformanceMeasure> PerfMeasures;
+               public PerformanceMeasure glDrawMeasure = new PerformanceMeasure("OpenGL Draw", 10);
+               public Command CMDViewPerf, CMDViewCfg, CMDViewTest0;
+               #endif
 
                public TestApp () : base () {
-
+                       #if MEASURE_TIME
+                       PerfMeasures = new List<PerformanceMeasure> (
+                               new PerformanceMeasure[] {
+                               this.CrowInterface.updateMeasure,
+                               this.CrowInterface.layoutingMeasure,
+                               this.CrowInterface.clippingMeasure,
+                               this.CrowInterface.drawingMeasure,
+                               this.glDrawMeasure
+                               }
+                       );
+                       CMDViewPerf = new Command(new Action(() => Load ("#testDrm.ui.perfMeasures.crow").DataSource = this)) { Caption = "Performances"};
+                       CMDViewCfg = new Command(new Action(() => Load ("#testDrm.ui.2.crow").DataSource = this)) { Caption = "Configuration"};
+                       CMDViewTest0 = new Command(new Action(() => Load ("#testDrm.ui.0.crow").DataSource = this)) { Caption = "Test view 0"};
+                       #endif
                }
 
                public int frameTime = 0;
@@ -141,15 +159,38 @@ namespace testDrm
 
                #endregion
 
+               public int InterfaceSleep {
+                       get { return ifaceSleep; }
+                       set {
+                               if (ifaceSleep == value)
+                                       return;
+                               ifaceSleep = value;
+                               NotifyValueChanged ("InterfaceSleep", ifaceSleep);
+                       }
+               }
+               public int FlipPollSleep {
+                       get { return gpu.FlipPollingSleep; }
+                       set {
+                               if (gpu.FlipPollingSleep == value)
+                                       return;
+                               gpu.FlipPollingSleep = value;
+                               NotifyValueChanged ("FlipPollSleep", gpu.FlipPollingSleep);
+                       }
+               }
+               public int UpdateSleep {
+                       get { return updateSleep; }
+                       set {
+                               if (updateSleep == value)
+                                       return;
+                               updateSleep = value;
+                               NotifyValueChanged ("UpdateSleep", updateSleep);
+                       }
+               }
+
+
                public override void Run ()
                {                       
                        Stopwatch frame = new Stopwatch ();
-//                     Load ("#testDrm.ui.menu.crow").DataSource = this;
-//                     Load ("#testDrm.ui.0.crow").DataSource = this;
-//                     Load ("#testDrm.ui.0.crow").DataSource = this;
-//                     Load ("#testDrm.ui.0.crow").DataSource = this;
-
-                       System.Threading.Thread.Sleep (50);
                        Load ("#testDrm.ui.menu.crow").DataSource = this;
                        int i = 0;
                        while(Running){
@@ -158,7 +199,7 @@ namespace testDrm
                                        i++;
 
                                        base.Run ();
-
+                                       
                                        frame.Stop();
                                        frameTime = (int)frame.ElapsedTicks;
                                        NotifyValueChanged("frameTime", frameTime);
@@ -170,7 +211,10 @@ namespace testDrm
                                                frameMin = frameTime;
                                                NotifyValueChanged("frameMin", frameMin);       
                                        }
-
+                                       #if MEASURE_TIME
+                                       foreach (PerformanceMeasure m in PerfMeasures)
+                                               m.NotifyChanges();
+                                       #endif
                                } catch (Exception ex) {
                                        Console.WriteLine (ex.ToString());
                                }
@@ -180,14 +224,6 @@ namespace testDrm
                {
                        Running = false;
                }
-               void onLoadClick(object send, Crow.MouseButtonEventArgs e)
-               {
-                       Console.WriteLine ("********** LOADING ui item ******************");
-                       GraphicObject go = Load ("#testDrm.ui.2.crow");
-                       Console.WriteLine ("********** SETTING DATASOURCE ON ITEM ******************");
-                       go.DataSource = this;
-                       Console.WriteLine ("********** LOADING FINISHED ******************");
-               }
        }
 }
 
index a1fc45f16f6db674ee0febeb72f5ea7f3ac0e76a..7d5c1d5f1286cfb55def20c17eb173bda197ed32 100644 (file)
@@ -42,12 +42,14 @@ namespace Crow
        public class Application : IDisposable
        {
                public bool Running = true;
-               DRI.GPUControler gpu;
+               protected DRI.DRIControler gpu;
                Cairo.GLSurface cairoSurf;
 
-               public Interface CrowInterface;
+               protected Interface CrowInterface;
 
-               public bool mouseIsInInterface = false;
+               protected bool mouseIsInInterface = false;
+
+               protected volatile int ifaceSleep = 1, updateSleep = 0;
 
                void interfaceThread()
                {
@@ -56,7 +58,7 @@ namespace Crow
 
                        while (true) {
                                CrowInterface.Update ();
-                               Thread.Sleep (1);
+                               Thread.Sleep (ifaceSleep);
                        }
                }
 //
@@ -80,7 +82,7 @@ namespace Crow
                                }
                        }
 
-                       gpu = new DRI.GPUControler();
+                       gpu = new DRI.DRIControler();
                        cairoSurf = gpu.CairoSurf;
 
                        CrowInterface = new Interface ();
@@ -93,34 +95,33 @@ namespace Crow
                        initInput ();
 
                        CrowInterface.ProcessResize (new Size (gpu.Width, gpu.Height));
-                       cursor = Crow.XCursorFile.Load("#Crow.Images.Icons.Cursors.arrow").Cursors[0];
-                       gpu.updateCursor (cursor);
-                       //CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged;
+
+                       gpu.updateCursor (XCursor.Default);
+                       MouseX = gpu.Width / 2;
+                       MouseY = gpu.Height / 2;
+                       gpu.moveCursor ((uint)MouseX - 8, (uint)MouseY - 4);
+                       CrowInterface.MouseCursorChanged += CrowInterface_MouseCursorChanged;
                }
                void switch_request_handle (Signal s){
-                       Console.WriteLine ("switch request catched: " + s.ToString());
-                       using (VT.VTControler master = new VT.VTControler ()) {
-                               Libc.write (master.fd, Encoding.ASCII.GetBytes ("this is a test string"));
-                               master.AcknoledgeSwitchRequest ();
-                       }                       
+//                     Console.WriteLine ("switch request catched: " + s.ToString());
+//                     using (VT.VTControler master = new VT.VTControler ()) {
+//                             Libc.write (master.fd, Encoding.ASCII.GetBytes ("this is a test string"));
+//                             master.AcknoledgeSwitchRequest ();
+//                     }                       
                }
                void sigint_handler (Signal s){
                        Console.WriteLine ("{0}: SIGINT catched");
                        Running = false;
                }
-//             void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e)
-//             {
-//                     gpu.updateCursor (e.NewCursor);
-//             }
+               void CrowInterface_MouseCursorChanged (object sender, MouseCursorChangedEventArgs e)
+               {
+                       gpu.updateCursor (e.NewCursor);
+               }
 
                public GraphicObject Load (string path){
                        return CrowInterface.LoadInterface (path);
                }
                public virtual void Run (){
-                       updateCrow ();
-               }
-
-               public void updateCrow (){
                        bool update = false;
 
                        if (updateMousePos) {
@@ -130,17 +131,6 @@ namespace Crow
                                }
                        }
 
-//                     using (Cairo.Context ctx = new Cairo.Context (cairoSurf)) {
-//                             ctx.Rectangle (0, 0, gpu.Width, gpu.Height);
-//                             ctx.SetSourceRGB (0, 0, 1);
-//                             ctx.Fill ();
-//                             ctx.Rectangle (5, 5, 50, 50);
-//                             ctx.SetSourceRGB (1, 0, 0);
-//                             ctx.Fill ();
-//                             ctx.Rectangle (1550, 850, 50, 50);
-//                             ctx.SetSourceRGB (0, 1, 0);
-//                             ctx.Fill ();
-//                     }
                        if (Monitor.TryEnter (CrowInterface.RenderMutex)) {
                                if (CrowInterface.IsDirty) {
                                        CrowInterface.IsDirty = false;
@@ -157,20 +147,18 @@ namespace Crow
                                }
                                Monitor.Exit (CrowInterface.RenderMutex);
                        }
-//
-//                     if (!update)
-//                             return;
-//                     update = false;
+
+                       if (!update)
+                               return;
+                       update = false;
 
                        cairoSurf.Flush ();
                        cairoSurf.SwapBuffers ();
 
-                       gpu.Update ();
-                       //Thread.Sleep (1);
-                       //gpu.MarkFBDirty ();
+                       gpu.UpdateWithPageFlip ();
+                       Thread.Sleep (updateSleep);
                }
-
-
+                       
                #region INPUT
                Thread input_thread;
                long exit;
index b8efecc800a677014e53654aba7821c1165a1f0a..92a974378c1bb493c7e4a56e6fe75a8c1098ef7c 100644 (file)
@@ -409,6 +409,20 @@ namespace EGL
                        BlueSize,
                        AlphaSize
                }
+               public void ResetMakeCurrent (){
+                       if (!Context.MakeCurrent (dpy, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
+                               Console.WriteLine ("egl clear current ctx failed");
+               }
+               public void DestroyContext (){
+                       try {
+                               if (ctx != IntPtr.Zero)
+                                       DestroyContext (dpy, ctx);
+                       } catch (Exception ex) {
+                               Console.WriteLine ("error disposing egl context: {0}", ex.ToString ());
+                       }finally {
+                               ctx = IntPtr.Zero;
+                       }
+               }
 
                #region IDisposable implementation
                ~Context(){
@@ -420,15 +434,8 @@ namespace EGL
                        GC.SuppressFinalize (this);
                }
                protected virtual void Dispose (bool disposing){
-                       if (GetCurrentContext () == ctx) {
-                               Console.WriteLine ("destroying context");
-                               DestroyContext (dpy, ctx);
-                       }else
-                               Console.WriteLine ("not current");
-                       
                        if (dpy != IntPtr.Zero)
                                Terminate (dpy);
-                       dpy = IntPtr.Zero;
                }
                #endregion
 
diff --git a/testDrm/src/Linux/DRI.cs b/testDrm/src/Linux/DRI.cs
deleted file mode 100644 (file)
index b39044f..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-//
-// DRM.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.Runtime.InteropServices;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading;
-
-namespace Linux.DRI {
-       [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-       public delegate void VBlankCallback(int fd, int sequence, int tv_sec, int tv_usec, IntPtr user_data);
-       [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-       public delegate void PageFlipCallback(int fd, int sequence, int tv_sec, int tv_usec, ref int user_data);
-
-       public enum EncoderType : uint
-       {
-               NONE=0,
-               DAC=1,
-               TMDS=2,
-               LVDS=3,
-               TVDAC=4,
-               VIRTUAL=5,
-               DSI=6,
-               DPMST=7,
-               DPI=8,
-       }
-       public enum PlaneType {
-               Overlay = 0,
-               Primary = 1,
-               Cursor = 2
-       }
-
-       [Flags]public enum PageFlipFlags
-       {
-               FlipEvent = 0x01,
-               FlipAsync = 0x02,
-               FlipFlags = FlipEvent | FlipAsync
-       }
-       /// <summary>Video mode flags, bit compatible with the xorg definitions. </summary>
-       [Flags]public enum VideoMode
-       {
-               PHSYNC = 0x01,
-               NHSYNC = 0x02,
-               PVSYNC = 0x04,
-               NVSYNC = 0x08,
-               INTERLACE = 0x10,
-               DBLSCAN = 0x20,
-               CSYNC = 0x40,
-               PCSYNC = 0x80,
-               NCSYNC = 0x10,
-               HSKEW = 0x0200,
-               BCAST = 0x0400,
-               PIXMUX = 0x0800,
-               DBLCLK = 0x1000,
-               CLKDIV2 = 0x2000,
-               //              FLAG_3D_MASK                    (0x1f<<14)
-               //              FLAG_3D_NONE = 0x0;
-               //              FLAG_3D_FRAME_PACKING = 0x4000,
-               //              FLAG_3D_FIELD_ALTERNATIVE = 0x8000,
-               //              FLAG_3D_LINE_ALTERNATIVE        (3<<14)
-               //              FLAG_3D_SIDE_BY_SIDE_FULL       (4<<14)
-               //              FLAG_3D_L_DEPTH         (5<<14)
-               //              FLAG_3D_L_DEPTH_GFX_GFX_DEPTH   (6<<14)
-               //              FLAG_3D_TOP_AND_BOTTOM  (7<<14)
-               //              FLAG_3D_SIDE_BY_SIDE_HALF       (8<<14)         
-       }
-
-       [StructLayout(LayoutKind.Sequential)]
-       public struct EventContext
-       {
-               public int version;
-               public IntPtr vblank_handler;
-               public IntPtr page_flip_handler;
-               public static readonly int Version = 2;
-       }
-       [StructLayout(LayoutKind.Sequential)]
-       unsafe public struct drmFrameBuffer {
-               public uint fb_id;
-               public uint width, height;
-               public uint pitch;
-               public uint bpp;
-               public uint depth;
-               /* driver specific handle */
-               public uint handle;
-       }
-       [StructLayout(LayoutKind.Sequential)]
-       unsafe internal struct drmPlaneRes {
-               public uint count_planes;
-               public uint *planes;
-       }
-
-       public class GPUControler : IDisposable {
-               int fd_gpu = -1;
-               GBM.Device gbmDev;
-               GBM.Surface gbmSurf;
-               EGL.Context eglctx;
-               EGL.Surface eglSurf;
-
-               Cairo.EGLDevice cairoDev;
-               public Cairo.GLSurface CairoSurf;
-
-               Resources resources = null;
-               Connector connector = null;
-               Crtc currentCrtc = null;
-               ModeInfo currentMode, originalMode;
-               uint originalFB;
-
-               public GPUControler(string gpu_path = "/dev/dri/card0"){
-                       fd_gpu = Libc.open(gpu_path, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
-                       if (fd_gpu < 0)
-                               throw new NotSupportedException("[DRI] Failed to open gpu");
-                       
-                       resources = new Resources (fd_gpu);
-                       gbmDev = new GBM.Device (fd_gpu);
-                       eglctx = new EGL.Context (gbmDev);
-
-                       try {
-                               if (defaultConfiguration ())
-                                       Console.WriteLine ("default config ok");                                
-                       } catch (Exception ex) {
-                               Console.WriteLine (ex.ToString());
-                       }
-               }
-
-               byte bpp = 32;
-               byte depth = 24;
-
-               public int Width { get { return (int)currentMode.hdisplay; }}
-               public int Height { get { return (int)currentMode.vdisplay; }}
-
-               ModeInfo getNewMode(){
-                       ModeInfo mode = currentCrtc.CurrentMode;
-                       mode.clock = 118250;
-                       mode.hdisplay = 1600;
-                       mode.hsync_start = 1696;
-                       mode.hsync_end = 1856;
-                       mode.htotal = 2112;
-                       mode.vdisplay = 900;
-                       mode.vsync_start = 903;
-                       mode.vsync_end = 908;
-                       mode.vtotal = 934;
-                       mode.flags |= (uint)VideoMode.NHSYNC;
-                       mode.flags |= (uint)VideoMode.PVSYNC;
-                       return mode;
-               }
-               unsafe void setNewMode(){
-                       
-                       //currentCrtc.handle->mode = currentMode;
-//                     ModeInfo* mode = (ModeInfo*)Marshal.AllocHGlobal (sizeof(ModeInfo));// pConnector->modes;
-//                     *mode = currentMode;
-
-                       uint fb;
-                       GBM.gbm_bo* bo = GBM.BufferObject.gbm_bo_create (gbmDev.handle, (uint)Width, (uint)Height, GBM.SurfaceFormat.ARGB8888, GBM.SurfaceFlags.Scanout);
-                       int ret = drmModeAddFB (fd_gpu, (uint)Width, (uint)Height, (byte)depth, (byte)bpp, bo->Stride, (uint)bo->Handle32, out fb);
-                       if (ret != 0)
-                               Console.WriteLine ("addFb failed: {0}", ret);
-                       bo->SetUserData ((IntPtr)fb, handleDestroyFB);
-
-                       uint connId = connector.Id;
-                       ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, fb, 0, 0, &connId, 1, ref currentMode);
-                       if (ret != 0)
-                               Console.WriteLine ("set new mode setCrtc failed: {0}", ret);
-                       //GBM.BufferObject.gbm_bo_destroy (bo);
-
-                       //Console.WriteLine ("new mode set to {0} x {1}", Width, Height);
-               }
-               bool defaultConfiguration (){
-                       //select the first connected connector
-                       foreach (Connector c in resources.Connectors) {
-                               if (c.State == ConnectionStatus.Connected) {
-                                       connector = c;
-                                       break;
-                               }                               
-                       }
-                       if (connector == null)
-                               return false;
-                       
-                       currentCrtc = connector.CurrentEncoder.CurrentCrtc;
-                       originalMode = currentCrtc.CurrentMode;
-                       originalFB = currentCrtc.CurrentFbId;
-                       currentMode = getNewMode();
-
-
-                       //configure a rendering stack
-                       gbmSurf = new GBM.Surface (gbmDev, Width, Height,
-                               GBM.SurfaceFlags.Rendering | GBM.SurfaceFlags.Scanout);
-
-                       //setNewMode ();
-
-                       eglSurf = new EGL.Surface (eglctx, gbmSurf);
-                       eglSurf.MakeCurrent ();
-
-                       cairoDev = new Cairo.EGLDevice (eglctx.dpy, eglctx.ctx);
-
-                       CairoSurf = new Cairo.GLSurface (cairoDev, eglSurf.handle, Width, Height);
-                       //cairoSurf = new Cairo.EGLSurface (cairoDev, egl_surface, 1600, 900);
-
-                       cairoDev.SetThreadAware (false);
-
-                       if (cairoDev.Acquire () != Cairo.Status.Success)
-                               Console.WriteLine ("[Cairo]: Failed to acquire egl device.");
-
-//                     using (Cairo.Context ctx = new Cairo.Context (CairoSurf)) {
-//                             ctx.Rectangle (0, 0, Width, Height);
-//                             ctx.SetSourceRGB (0, 0, 1);
-//                             ctx.Fill ();
-//                     }
-//                     CairoSurf.Flush ();
-//                     CairoSurf.SwapBuffers ();
-//                     Update ();
-
-                       //Thread.Sleep (1);
-                       return true;
-               }
-               void handleDestroyFB(ref GBM.gbm_bo bo, IntPtr data)
-               {
-                       int fb = data.ToInt32();
-
-                       if (fb != 0) {
-                               try {
-                                       if (drmModeRmFB (fd_gpu, fb) != 0)
-                                               Console.WriteLine ("DestroyFB failed");
-                                       else
-                                               Console.WriteLine ("DestroyFB ok fd={0}", fd_gpu);                                      
-                               } catch (Exception ex) {
-                                       Console.WriteLine ("DestroyFB error:" + ex.ToString());
-                               }
-                       }
-               }
-
-
-
-               unsafe public void Update(){
-                       GBM.gbm_bo* bo; 
-                       uint fb;
-
-                       if (!gbmSurf.HasFreeBuffers)
-                               throw new NotSupportedException("[GBM] Out of free buffer");
-                               
-                       bo = gbmSurf.Lock ();
-
-                       int ret = drmModeAddFB (fd_gpu, currentMode.hdisplay, currentMode.vdisplay, (byte)depth, (byte)bpp, bo->Stride, (uint)bo->Handle32, out fb);
-                       if (ret != 0)
-                               Console.WriteLine ("addFb failed: {0}", ret);
-                       bo->SetUserData ((IntPtr)fb, handleDestroyFB);
-
-                       uint connId = connector.Id;
-                       ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, fb, 0, 0, &connId, 1, ref currentMode);
-                       if (ret != 0)
-                               Console.WriteLine ("setCrtc failed: {0}", ret);
-
-                       gbmSurf.Release (bo);
-               }
-               [StructLayout(LayoutKind.Sequential)]
-               struct drmClip {
-                       public ushort x1;
-                       public ushort y1;
-                       public ushort x2;
-                       public ushort y2;
-               }
-               unsafe public void MarkFBDirty(){
-                       IntPtr pClip = Marshal.AllocHGlobal (sizeof(drmClip));
-                       drmClip dc = new drmClip () { x1 = 0, y1 = 0, x2 = 500, y2 = 500 };
-                       Marshal.StructureToPtr (dc, pClip,false);
-                       int ret = drmModeDirtyFB (fd_gpu, currentCrtc.CurrentFbId, IntPtr.Zero, 0);
-                       if (ret < 0)
-                               Console.WriteLine ("set FB dirty failed: {0}", ret);
-               }
-               #region cursor
-               GBM.BufferObject boMouseCursor;
-
-               internal void updateCursor (Crow.XCursor cursor) {
-                       uint width = 64, height = 64;
-                       if (cursor.Width > width || cursor.Height > height){
-                               Debug.Print("[DRM] Cursor size {0}x{1} unsupported. Maximum is 64x64.",
-                                       cursor.Width, cursor.Height);
-                               return;
-                       }
-                       boMouseCursor = new GBM.BufferObject (gbmDev, width, height, GBM.SurfaceFormat.ARGB8888,
-                               GBM.SurfaceFlags.Cursor64x64 | GBM.SurfaceFlags.Write);
-                       
-                       // Copy cursor.Data into a new buffer of the correct size
-                       byte[] cursor_data = new byte[width * height * 4];
-                       for (uint y = 0; y < cursor.Height; y++)
-                       {
-                               uint dst_offset = y * width * 4;
-                               uint src_offset = y * cursor.Width * 4;
-                               uint src_length = cursor.Width * 4;
-                               Array.Copy(
-                                       cursor.data, src_offset,
-                                       cursor_data, dst_offset,
-                                       src_length);
-                       }
-
-                       boMouseCursor.Data = cursor_data;
-                       uint crtcid = currentCrtc.Id;
-
-                       unsafe {
-                               drmModeSetCursor2 (fd_gpu, crtcid,
-                                       (uint)boMouseCursor.handle->Handle32, width, height, (int)cursor.Xhot, (int)cursor.Yhot);
-                               drmModeMoveCursor (fd_gpu, crtcid, 0, 0);
-                       }
-               }
-               internal void moveCursor (uint x, uint y){
-                       drmModeMoveCursor (fd_gpu, currentCrtc.Id, x, y);
-               }
-               #endregion
-
-//             unsafe public drmPlane GetPlane (uint id) {
-//                     drmPlane p = new drmPlane();
-//                     drmPlane* pPlane = ModeGetPlane (fd_gpu, id);
-//                     if (pPlane != null) {
-//                             p = *pPlane;
-//                             ModeFreePlane (pPlane);
-//                     }
-//                     return p;
-//             }
-//             public void SetPlane (drmPlane p, uint flags, uint crtc_w, uint crtc_h, uint src_w, uint src_h) {
-//                     ModeSetPlane (fd_gpu, p.plane_id, p.crtc_id, p.fb_id, flags,
-//                             (int)p.crtc_x, (int)p.crtc_y,
-//                             crtc_w, crtc_h,
-//                             p.x, p.y,
-//                             src_w, src_h);
-//
-//                             
-//             }
-
-               #region IDisposable implementation
-               ~GPUControler(){
-                       Dispose (false);
-               }
-               public void Dispose ()
-               {
-                       Dispose (true);
-                       GC.SuppressFinalize (this);
-               }
-               protected virtual void Dispose (bool disposing){
-                       if (cairoDev != null) {
-                               cairoDev.Release ();
-                               CairoSurf.Dispose ();
-                               cairoDev.Dispose ();
-                               cairoDev = null;
-                               CairoSurf = null;
-                       }
-
-                       uint connId = connector.Id;
-                       unsafe{
-                               int ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, originalFB, 0, 0, &connId, 1, ref originalMode);
-                               if (ret != 0)
-                                       Console.WriteLine ("restore Crtc failed: {0}", ret);
-                       }
-
-                       if (boMouseCursor != null)
-                               boMouseCursor.Dispose ();
-                       boMouseCursor = null;
-                       if (eglctx != null)
-                               eglctx.Dispose ();
-                       eglctx = null;
-
-                       if (gbmSurf != null)
-                               gbmSurf.Dispose ();
-                       if (gbmDev != null)
-                               gbmDev.Dispose ();                      
-                       if (currentCrtc != null)
-                               currentCrtc.Dispose ();                 
-                       if (connector != null)
-                               connector.Dispose ();                   
-                       if (resources != null)
-                               resources.Dispose ();
-                       resources = null;
-                       if (fd_gpu > 0)
-                               Libc.close (fd_gpu);
-                       fd_gpu = -1;
-                       Console.WriteLine ("disposing ok");
-               }
-               #endregion
-
-               #region dllimports
-               const string lib = "libdrm";
-               [DllImport(lib, EntryPoint = "drmHandleEvent", CallingConvention = CallingConvention.Cdecl)]
-               public static extern int HandleEvent(int fd, ref EventContext evctx);
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               public static extern int drmModeAddFB(int fd, uint width, uint height, byte depth,
-                       byte bpp, uint stride, uint bo_handle, out uint buf_id);
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               public static extern int drmModeRmFB(int fd, int bufferId);
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               public static extern int drmModeDirtyFB(int fd, uint bufferId, IntPtr clips, uint num_clips);
-
-               [DllImport(lib, EntryPoint = "drmModeGetFB", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern drmFrameBuffer* ModeGetFB(int fd, uint fb_id);
-               [DllImport(lib, EntryPoint = "drmModeGetPlaneResources", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern drmPlaneRes* ModeGetPlaneResources(int fd);
-
-               [DllImport(lib, EntryPoint = "drmModeFreeFB", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern void ModeFreeFB(drmFrameBuffer* ptr);
-               [DllImport(lib, EntryPoint = "drmModeFreePlaneResources", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern void ModeFreePlaneResources(drmPlaneRes* ptr);
-
-               [DllImport(lib, EntryPoint = "drmModeSetPlane", CallingConvention = CallingConvention.Cdecl)]
-               unsafe static extern int ModeSetPlane(int fd, uint plane_id, uint crtc_id,
-                       uint fb_id, uint flags,
-                       int crtc_x, int crtc_y,
-                       uint crtc_w, uint crtc_h,
-                       uint src_x, uint src_y,
-                       uint src_w, uint src_h);
-
-               [DllImport(lib, EntryPoint = "drmModePageFlip", CallingConvention = CallingConvention.Cdecl)]
-               static extern int ModePageFlip(int fd, int crtc_id, int fb_id,
-                       PageFlipFlags flags, ref int user_data);
-
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               unsafe static extern int drmModeSetCrtc(int fd, uint crtcId, uint bufferId,     uint x, uint y, uint* connectors, int count, ref ModeInfo mode);
-
-               [DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)]
-               unsafe static extern int ModeSetCrtc(int fd, uint crtcId, uint bufferId,        uint x, uint y, uint* connectors, int count, ModeInfo* mode);
-
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               internal static extern int drmModeSetCursor2(int fd, uint crtcId, uint bo_handle, uint width, uint height, int hot_x, int hot_y);
-
-               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
-               internal static extern int drmModeMoveCursor(int fd, uint crtcId, uint x, uint y);
-               #endregion
-
-
-//             unsafe static bool paint(gbm_bo * bo)
-//             {
-//                     uint w = (uint)bo->Width;
-//                     uint h = (uint)bo->Height;
-//                     uint stride = (uint)bo->Stride;
-//
-//                     Console.WriteLine ("trying to map bo: {0}x{1} stride:{2}", w, h, stride);
-//                     bool success = false;
-//                     try {
-//                             unsafe {
-//                                     IntPtr map_data = IntPtr.Zero;
-//                                     IntPtr addr = Gbm.Map (bo, 0, 0, w, h, TransferFlags.Write, ref stride, out map_data);
-//                                     if (addr == IntPtr.Zero || map_data == IntPtr.Zero) {
-//                                             Console.WriteLine ("failed to mmap gbm bo");
-//                                             return false;
-//                                     }
-//                                     Console.WriteLine ("addr = {0}", addr.ToString());
-//                                     byte* b = (byte*)addr;
-//                                     for (int y = 0; y < h; y++) {
-//                                             for (int x = 0; x < w; x++) {                                                   
-//                                                     *(b + x + y * stride) = 0xff;
-//                                             }
-//                                     }
-//                                     Gbm.Unmap (bo, map_data);
-//                                     success = true;
-//                             }
-//                     } catch (Exception ex) {
-//                             Console.WriteLine (ex.ToString ());
-//                     }
-//                     return success;
-//             }
-       }
-}
\ No newline at end of file
diff --git a/testDrm/src/Linux/DRI/DRIControler.cs b/testDrm/src/Linux/DRI/DRIControler.cs
new file mode 100644 (file)
index 0000000..a336309
--- /dev/null
@@ -0,0 +1,555 @@
+//
+// DRM.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.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Linux.DRI {
+       #region DRM callback signatures
+       [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+       public delegate void VBlankCallback(int fd, int sequence, int tv_sec, int tv_usec, IntPtr user_data);
+       [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+       public delegate void PageFlipCallback(int fd, int sequence, int tv_sec, int tv_usec, ref int user_data);
+       #endregion
+
+       #region DRM enums
+       public enum EncoderType : uint
+       {
+               NONE=0,
+               DAC=1,
+               TMDS=2,
+               LVDS=3,
+               TVDAC=4,
+               VIRTUAL=5,
+               DSI=6,
+               DPMST=7,
+               DPI=8,
+       }
+       [Flags]public enum PageFlipFlags : uint
+       {
+               FlipEvent = 0x01,
+               FlipAsync = 0x02,
+               FlipFlags = FlipEvent | FlipAsync
+       }
+       /// <summary>Video mode flags, bit compatible with the xorg definitions. </summary>
+       [Flags]public enum VideoMode
+       {
+               PHSYNC = 0x01,
+               NHSYNC = 0x02,
+               PVSYNC = 0x04,
+               NVSYNC = 0x08,
+               INTERLACE = 0x10,
+               DBLSCAN = 0x20,
+               CSYNC = 0x40,
+               PCSYNC = 0x80,
+               NCSYNC = 0x10,
+               HSKEW = 0x0200,
+               BCAST = 0x0400,
+               PIXMUX = 0x0800,
+               DBLCLK = 0x1000,
+               CLKDIV2 = 0x2000,
+               //              FLAG_3D_MASK                    (0x1f<<14)
+               //              FLAG_3D_NONE = 0x0;
+               //              FLAG_3D_FRAME_PACKING = 0x4000,
+               //              FLAG_3D_FIELD_ALTERNATIVE = 0x8000,
+               //              FLAG_3D_LINE_ALTERNATIVE        (3<<14)
+               //              FLAG_3D_SIDE_BY_SIDE_FULL       (4<<14)
+               //              FLAG_3D_L_DEPTH         (5<<14)
+               //              FLAG_3D_L_DEPTH_GFX_GFX_DEPTH   (6<<14)
+               //              FLAG_3D_TOP_AND_BOTTOM  (7<<14)
+               //              FLAG_3D_SIDE_BY_SIDE_HALF       (8<<14)         
+       }
+       #endregion
+
+       #region DRM structs
+       [StructLayout(LayoutKind.Sequential)]
+       public struct EventContext
+       {
+               public int version;
+               public IntPtr vblank_handler;
+               public IntPtr page_flip_handler;
+               public static readonly int Version = 2;
+       }
+       [StructLayout(LayoutKind.Sequential)]
+       unsafe public struct drmFrameBuffer {
+               public uint fb_id;
+               public uint width, height;
+               public uint pitch;
+               public uint bpp;
+               public uint depth;
+               /* driver specific handle */
+               public uint handle;
+       }
+       [StructLayout(LayoutKind.Sequential)]
+       struct drmClip {
+               public ushort x1;
+               public ushort y1;
+               public ushort x2;
+               public ushort y2;
+       }
+       #endregion
+
+       public class DRIControler : IDisposable {
+               #region PINVOKE
+               const string lib = "libdrm";
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmHandleEvent(int fd, ref EventContext evctx);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmModeAddFB(int fd, uint width, uint height, byte depth, byte bpp,
+                       uint stride, uint bo_handle, out uint buf_id);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmModeRmFB(int fd, uint bufferId);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmModeDirtyFB(int fd, uint bufferId, IntPtr clips, uint num_clips);
+               [DllImport(lib,CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern drmFrameBuffer* drmModeGetFB(int fd, uint fb_id);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern void drmModeFreeFB(drmFrameBuffer* ptr);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               static extern int drmModePageFlip(int fd, uint crtc_id, uint fb_id, PageFlipFlags flags, ref int user_data);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               unsafe static extern int drmModeSetCrtc(int fd, uint crtcId, uint bufferId,     uint x, uint y, uint* connectors, int count, ref ModeInfo mode);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmModeSetCursor2(int fd, uint crtcId, uint bo_handle, uint width, uint height, int hot_x, int hot_y);
+               [DllImport(lib, CallingConvention = CallingConvention.Cdecl)]
+               internal static extern int drmModeMoveCursor(int fd, uint crtcId, uint x, uint y);
+               #endregion
+
+               int fd_gpu = -1;
+               GBM.Device gbmDev;
+               GBM.Surface gbmSurf;
+               EGL.Context eglctx;
+               EGL.Surface eglSurf;
+
+               Cairo.EGLDevice cairoDev;
+               public Cairo.GLSurface CairoSurf;
+
+               Resources resources = null;
+               Connector connector = null;
+               Crtc currentCrtc = null;
+               ModeInfo currentMode, originalMode;
+               uint originalFB;
+
+               byte bpp = 32;
+               byte depth = 24;
+
+               public volatile int FlipPollingSleep = 1;
+
+               #region CTOR
+               public DRIControler(string gpu_path = "/dev/dri/card0"){
+                       fd_gpu = Libc.open(gpu_path, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
+                       if (fd_gpu < 0)
+                               throw new NotSupportedException("[DRI] Failed to open gpu");
+                       
+                       resources = new Resources (fd_gpu);
+                       gbmDev = new GBM.Device (fd_gpu);
+                       eglctx = new EGL.Context (gbmDev);
+
+                       try {
+                               if (defaultConfiguration ())
+                                       Console.WriteLine ("default config ok");                                
+                       } catch (Exception ex) {
+                               Console.WriteLine (ex.ToString());
+                       }
+               }
+               #endregion
+
+               public int Width { get { return (int)currentMode.hdisplay; }}
+               public int Height { get { return (int)currentMode.vdisplay; }}
+
+               bool defaultConfiguration (){
+                       //select the first connected connector
+                       foreach (Connector c in resources.Connectors) {
+                               if (c.State == ConnectionStatus.Connected) {
+                                       connector = c;
+                                       break;
+                               }                               
+                       }
+                       if (connector == null)
+                               return false;
+                       
+                       currentCrtc = connector.CurrentEncoder.CurrentCrtc;
+                       originalMode = currentCrtc.CurrentMode;
+                       originalFB = currentCrtc.CurrentFbId;
+                       //currentMode = originalMode;
+                       currentMode = getNewMode();
+
+                       //setScanOutRegion();
+
+                       //configure a rendering stack
+                       gbmSurf = new GBM.Surface (gbmDev, Width, Height,
+                               GBM.SurfaceFlags.Rendering | GBM.SurfaceFlags.Scanout);
+
+                       eglSurf = new EGL.Surface (eglctx, gbmSurf);
+                       eglSurf.MakeCurrent ();
+
+                       cairoDev = new Cairo.EGLDevice (eglctx.dpy, eglctx.ctx);
+
+                       CairoSurf = new Cairo.GLSurface (cairoDev, eglSurf.handle, Width, Height);
+                       //cairoSurf = new Cairo.EGLSurface (cairoDev, egl_surface, 1600, 900);
+
+                       cairoDev.SetThreadAware (false);
+
+                       if (cairoDev.Acquire () != Cairo.Status.Success)
+                               Console.WriteLine ("[Cairo]: Failed to acquire egl device.");
+
+//                     using (Cairo.Context ctx = new Cairo.Context (CairoSurf)) {
+//                             ctx.Rectangle (0, 0, Width, Height);
+//                             ctx.SetSourceRGB (0, 0, 1);
+//                             ctx.Fill ();
+//                     }
+                       //CairoSurf.Flush ();
+                       //CairoSurf.SwapBuffers ();
+                       //Update ();
+                       //setScanOutRegion();
+                       //Thread.Sleep (100);
+
+                       initPageFlipUpdate ();
+                       return true;
+               }
+
+               void handleDestroyFB(ref GBM.gbm_bo bo, ref uint data)
+               {
+                       uint fb = data;
+
+                       if (fb != 0) {
+                               if (drmModeRmFB (fd_gpu, fb) != 0)
+                                       Console.WriteLine ("DestroyFB failed");
+
+                               data = 0;
+                       }
+               }
+
+
+
+                       
+               unsafe public void Update(){
+                       GBM.gbm_bo* bo; 
+                       uint fb;
+
+                       if (!gbmSurf.HasFreeBuffers)
+                               throw new NotSupportedException("[GBM] Out of free buffer");
+                               
+                       bo = gbmSurf.Lock ();
+
+                       int ret = drmModeAddFB (fd_gpu, currentMode.hdisplay, currentMode.vdisplay, (byte)depth, (byte)bpp, bo->Stride, (uint)bo->Handle32, out fb);
+                       if (ret != 0)
+                               Console.WriteLine ("addFb failed: {0}", ret);
+                       bo->SetUserData (ref fb, handleDestroyFB);
+
+                       uint connId = connector.Id;
+                       ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, fb, 0, 0, &connId, 1, ref currentMode);
+                       if (ret != 0)
+                               Console.WriteLine ("setCrtc failed: {0}", ret);
+
+                       gbmSurf.Release (bo);
+               }
+
+               static void HandlePageFlip(int fd,      int sequence, int tv_sec, int tv_usec, ref int user_data)
+               {
+                       user_data = 0;
+               }
+
+               PollFD fds;
+               EventContext evctx;
+               static IntPtr PageFlipPtr = Marshal.GetFunctionPointerForDelegate((PageFlipCallback)HandlePageFlip);
+               public void initPageFlipUpdate (){
+                       fds = new PollFD();
+                       fds.fd = fd_gpu;
+                       fds.events = PollFlags.In;
+
+                       evctx = new EventContext();
+                       evctx.version = EventContext.Version;
+                       evctx.page_flip_handler = Marshal.GetFunctionPointerForDelegate((PageFlipCallback)HandlePageFlip);
+               }
+               unsafe GBM.gbm_bo* bo;  
+               unsafe public void UpdateWithPageFlip(){
+                       GBM.gbm_bo* next_bo;    
+                       uint fb;
+//                     fds = new PollFD();
+//                     fds.fd = fd_gpu;
+//                     fds.events = PollFlags.In;
+
+//                     evctx = new EventContext();
+//                     evctx.version = EventContext.Version;
+//                     evctx.page_flip_handler = PageFlipPtr;
+
+                       int timeout = -1;//block ? -1 : 0;
+
+                       if (!gbmSurf.HasFreeBuffers)
+                               throw new NotSupportedException("[GBM] Out of free buffer");
+
+                       next_bo = gbmSurf.Lock ();
+
+                       int ret = drmModeAddFB (fd_gpu, currentMode.hdisplay, currentMode.vdisplay, (byte)depth, (byte)bpp, next_bo->Stride, (uint)next_bo->Handle32, out fb);
+                       if (ret != 0)
+                               Console.WriteLine ("addFb failed: {0}", ret);
+                       next_bo->SetUserData (ref fb, handleDestroyFB);
+
+                       if (bo == null) {                               
+                               uint connId = connector.Id;
+                               ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, fb, 0, 0, &connId, 1, ref currentMode);
+                               if (ret != 0)
+                                       Console.WriteLine ("setCrtc failed: {0}", ret);
+                               bo = next_bo;
+                       } else {
+
+                               int is_flip_queued = 1;
+
+                               while (drmModePageFlip (fd_gpu, currentCrtc.Id, fb, PageFlipFlags.FlipEvent, ref is_flip_queued) < 0) {
+                                       //Console.WriteLine ("[DRM] Failed to enqueue framebuffer flip.");
+                                       Thread.Sleep (1);
+                               }
+
+                               while (is_flip_queued != 0) {
+                                       fds.revents = 0;
+                                       if (Libc.poll (ref fds, 1, timeout) < 0)
+                                               break;                                          
+                                       if ((fds.revents & (PollFlags.Hup | PollFlags.Error)) != 0)
+                                               break;
+                                       if ((fds.revents & PollFlags.In) != 0)
+                                               drmHandleEvent (fd_gpu, ref evctx);
+                                       else
+                                               break;
+                                       Thread.Sleep (FlipPollingSleep);
+                               }
+                               if (is_flip_queued != 0)
+                                       Console.WriteLine ("flip canceled");
+
+                               gbmSurf.Release (bo);
+                               bo = next_bo;
+                       }
+               }
+
+               #region cursor
+               GBM.BufferObject boMouseCursor;
+
+               internal void updateCursor (Crow.XCursor cursor) {
+                       uint width = 64, height = 64;
+                       if (cursor.Width > width || cursor.Height > height){
+                               Debug.Print("[DRM] Cursor size {0}x{1} unsupported. Maximum is 64x64.",
+                                       cursor.Width, cursor.Height);
+                               return;
+                       }
+                       boMouseCursor = new GBM.BufferObject (gbmDev, width, height, GBM.SurfaceFormat.ARGB8888,
+                               GBM.SurfaceFlags.Cursor64x64 | GBM.SurfaceFlags.Write);
+                       
+                       // Copy cursor.Data into a new buffer of the correct size
+                       byte[] cursor_data = new byte[width * height * 4];
+                       for (uint y = 0; y < cursor.Height; y++)
+                       {
+                               uint dst_offset = y * width * 4;
+                               uint src_offset = y * cursor.Width * 4;
+                               uint src_length = cursor.Width * 4;
+                               Array.Copy(
+                                       cursor.data, src_offset,
+                                       cursor_data, dst_offset,
+                                       src_length);
+                       }
+
+                       boMouseCursor.Data = cursor_data;
+                       uint crtcid = currentCrtc.Id;
+
+                       unsafe {
+                               drmModeSetCursor2 (fd_gpu, crtcid,
+                                       (uint)boMouseCursor.handle->Handle32, width, height, (int)cursor.Xhot, (int)cursor.Yhot);
+                               //drmModeMoveCursor (fd_gpu, crtcid, 0, 0);
+                       }
+               }
+               internal void moveCursor (uint x, uint y){
+                       drmModeMoveCursor (fd_gpu, currentCrtc.Id, x, y);
+               }
+               #endregion
+
+               ModeInfo getNewMode(){
+                       ModeInfo mode = currentCrtc.CurrentMode;
+                       mode.clock = 118250;
+                       mode.hdisplay = 1600;
+                       mode.hsync_start = 1696;
+                       mode.hsync_end = 1856;
+                       mode.htotal = 2112;
+                       mode.vdisplay = 900;
+                       mode.vsync_start = 903;
+                       mode.vsync_end = 908;
+                       mode.vtotal = 934;
+                       mode.flags |= (uint)VideoMode.NHSYNC;
+                       mode.flags |= (uint)VideoMode.PVSYNC;
+                       return mode;
+               }
+               unsafe void setScanOutRegion(){
+
+                       //currentCrtc.handle->mode = currentMode;
+                       //                      ModeInfo* mode = (ModeInfo*)Marshal.AllocHGlobal (sizeof(ModeInfo));// pConnector->modes;
+                       //                      *mode = currentMode;
+
+                       uint fb;
+                       GBM.gbm_bo* bo = GBM.BufferObject.gbm_bo_create (gbmDev.handle, (uint)Width, (uint)Height, GBM.SurfaceFormat.ARGB8888, GBM.SurfaceFlags.Rendering);
+                       int ret = drmModeAddFB (fd_gpu, (uint)Width, (uint)Height, (byte)depth, (byte)bpp, bo->Stride, (uint)bo->Handle32, out fb);
+                       if (ret != 0)
+                               Console.WriteLine ("addFb failed: {0}", ret);
+                       bo->SetUserData (ref fb, handleDestroyFB);
+
+                       uint connId = connector.Id;
+                       ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, currentCrtc.CurrentFbId, 0, 0, &connId, 1, ref currentMode);
+                       if (ret != 0)
+                               Console.WriteLine ("set new mode setCrtc failed: {0}", ret);
+                       //GBM.BufferObject.gbm_bo_destroy (bo);
+
+                       Console.WriteLine ("new mode set to {0} x {1} fbid:{2}", Width, Height, currentCrtc.CurrentFbId);
+               }
+
+//             unsafe public drmPlane GetPlane (uint id) {
+//                     drmPlane p = new drmPlane();
+//                     drmPlane* pPlane = ModeGetPlane (fd_gpu, id);
+//                     if (pPlane != null) {
+//                             p = *pPlane;
+//                             ModeFreePlane (pPlane);
+//                     }
+//                     return p;
+//             }
+//             public void SetPlane (drmPlane p, uint flags, uint crtc_w, uint crtc_h, uint src_w, uint src_h) {
+//                     ModeSetPlane (fd_gpu, p.plane_id, p.crtc_id, p.fb_id, flags,
+//                             (int)p.crtc_x, (int)p.crtc_y,
+//                             crtc_w, crtc_h,
+//                             p.x, p.y,
+//                             src_w, src_h);
+//
+//                             
+//             }
+
+               #region IDisposable implementation
+               ~DRIControler(){
+                       Dispose (false);
+               }
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+               protected virtual void Dispose (bool disposing){
+                       unsafe{
+                               if (bo != null)
+                                       gbmSurf.Release (bo);                           
+                       }
+                       Thread.Sleep (10);
+                       if (cairoDev != null) {
+                               cairoDev.Release ();
+                               CairoSurf.Dispose ();
+                               cairoDev.Dispose ();
+                               cairoDev = null;
+                               CairoSurf = null;
+                       }
+
+                       if (boMouseCursor != null) {
+                               drmModeSetCursor2 (fd_gpu, currentCrtc.Id, 0u, 0, 0, 0, 0);
+                               boMouseCursor.Dispose ();
+                       }
+                       boMouseCursor = null;
+                       if (connector != null) {
+                               uint connId = connector.Id;
+                               unsafe {
+                                       int ret = drmModeSetCrtc (fd_gpu, currentCrtc.Id, originalFB, 0, 0, &connId, 1, ref originalMode);
+                                       if (ret != 0)
+                                               Console.WriteLine ("restore Crtc failed: {0}", ret);
+                               }
+                       }
+                       if (eglctx != null) {
+                               eglctx.ResetMakeCurrent ();
+                               eglctx.DestroyContext ();
+
+                               if (eglSurf != null)
+                                       eglSurf.Dispose ();     
+                               eglSurf = null;
+                       }
+
+                       if (gbmSurf != null)
+                               gbmSurf.Dispose ();
+                       if (eglctx != null)
+                               eglctx.Dispose ();
+                       eglctx = null;
+                       if (gbmDev != null)
+                               gbmDev.Dispose ();
+                       
+                       if (currentCrtc != null)
+                               currentCrtc.Dispose ();                 
+                       if (connector != null)
+                               connector.Dispose ();                   
+                       if (resources != null)
+                               resources.Dispose ();
+                       resources = null;
+                       if (fd_gpu > 0)
+                               Libc.close (fd_gpu);
+                       fd_gpu = -1;
+                       Console.WriteLine ("GPU controler disposed");
+               }
+               #endregion
+
+
+               unsafe public void MarkFBDirty(){
+                       IntPtr pClip = Marshal.AllocHGlobal (sizeof(drmClip));
+                       drmClip dc = new drmClip () { x1 = 0, y1 = 0, x2 = 500, y2 = 500 };
+                       Marshal.StructureToPtr (dc, pClip,false);
+                       int ret = drmModeDirtyFB (fd_gpu, currentCrtc.CurrentFbId, IntPtr.Zero, 0);
+                       if (ret < 0)
+                               Console.WriteLine ("set FB dirty failed: {0}", ret);
+               }
+
+
+//             unsafe static bool paint(gbm_bo * bo)
+//             {
+//                     uint w = (uint)bo->Width;
+//                     uint h = (uint)bo->Height;
+//                     uint stride = (uint)bo->Stride;
+//
+//                     Console.WriteLine ("trying to map bo: {0}x{1} stride:{2}", w, h, stride);
+//                     bool success = false;
+//                     try {
+//                             unsafe {
+//                                     IntPtr map_data = IntPtr.Zero;
+//                                     IntPtr addr = Gbm.Map (bo, 0, 0, w, h, TransferFlags.Write, ref stride, out map_data);
+//                                     if (addr == IntPtr.Zero || map_data == IntPtr.Zero) {
+//                                             Console.WriteLine ("failed to mmap gbm bo");
+//                                             return false;
+//                                     }
+//                                     Console.WriteLine ("addr = {0}", addr.ToString());
+//                                     byte* b = (byte*)addr;
+//                                     for (int y = 0; y < h; y++) {
+//                                             for (int x = 0; x < w; x++) {                                                   
+//                                                     *(b + x + y * stride) = 0xff;
+//                                             }
+//                                     }
+//                                     Gbm.Unmap (bo, map_data);
+//                                     success = true;
+//                             }
+//                     } catch (Exception ex) {
+//                             Console.WriteLine (ex.ToString ());
+//                     }
+//                     return success;
+//             }
+       }
+}
\ No newline at end of file
index 80b49455dbf422f62e5521c1a02db0a908d7b69e..c632e595f224b5c0ebbbd5dffff45483f7c96f27 100644 (file)
@@ -28,6 +28,11 @@ using System.Runtime.InteropServices;
 
 namespace Linux.DRI
 {
+       public enum PlaneType {
+               Overlay = 0,
+               Primary = 1,
+               Cursor = 2
+       }
        [StructLayout(LayoutKind.Sequential)]
        unsafe public struct drmPlane {
                public uint count_formats;
@@ -47,10 +52,18 @@ namespace Linux.DRI
        unsafe public class Plane : IDisposable
        {
                #region pinvoke
-               [DllImport("libdrm", EntryPoint = "drmModeGetPlane", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern drmPlane* ModeGetPlane(int fd, uint id);
-               [DllImport("libdrm", EntryPoint = "drmModeFreePlane", CallingConvention = CallingConvention.Cdecl)]
-               unsafe internal static extern void ModeFreePlane(drmPlane* ptr);
+               [DllImport("libdrm", CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern drmPlane* drmModeGetPlane(int fd, uint id);
+               [DllImport("libdrm", CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern void drmModeFreePlane(drmPlane* ptr);
+               [DllImport("libdrm", CallingConvention = CallingConvention.Cdecl)]
+               unsafe static extern int drmModeSetPlane(int fd, uint plane_id, uint crtc_id,
+                       uint fb_id, uint flags,
+                       int crtc_x, int crtc_y,
+                       uint crtc_w, uint crtc_h,
+                       uint src_x, uint src_y,
+                       uint src_w, uint src_h);
+               
                #endregion
 
                drmPlane* handle;
@@ -74,7 +87,7 @@ namespace Linux.DRI
                protected virtual void Dispose (bool disposing){
                        unsafe {
                                if (handle != null)
-                                       ModeFreePlane (handle);
+                                       drmModeFreePlane (handle);
                                handle = null;
                        }
                }
diff --git a/testDrm/src/Linux/DRI/PlaneResources.cs b/testDrm/src/Linux/DRI/PlaneResources.cs
new file mode 100644 (file)
index 0000000..cb7990e
--- /dev/null
@@ -0,0 +1,77 @@
+//
+// PlaneResources.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.Runtime.InteropServices;
+
+namespace Linux.DRI
+{
+       [StructLayout(LayoutKind.Sequential)]
+       unsafe internal struct drmPlaneRes {
+               public uint count_planes;
+               public uint *planes;
+       }
+
+       unsafe public class PlaneResources : IDisposable
+       {
+               #region pinvoke
+               [DllImport("libdrm", CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern drmPlaneRes* drmModeGetPlaneResources(int fd);
+               [DllImport("libdrm", CallingConvention = CallingConvention.Cdecl)]
+               unsafe internal static extern void drmModeFreePlaneResources(drmPlaneRes* ptr);
+               #endregion
+
+               int gpu_fd;
+               drmPlaneRes* handle;
+
+               internal PlaneResources (int fd_gpu)
+               {
+                       gpu_fd = fd_gpu;
+                       handle = drmModeGetPlaneResources (fd_gpu);
+
+                       if (handle == null)
+                               throw new NotSupportedException("[DRI] drmModeGetPlaneResources failed.");
+               }
+
+               #region IDisposable implementation
+               ~PlaneResources(){
+                       Dispose (false);
+               }
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+               protected virtual void Dispose (bool disposing){
+                       unsafe {
+                               if (handle != null)
+                                       drmModeFreePlaneResources (handle);
+                               handle = null;
+                       }
+               }
+               #endregion
+       }
+}
+
index 7f6012b341d431869149365b9cbc01ec7b2c7882..accf9103e74296d4b2b402e877f99cbf71799e69 100644 (file)
@@ -29,7 +29,7 @@ using System.Runtime.InteropServices;
 namespace Linux.GBM 
 {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
-       public delegate void DestroyUserDataCallback(ref GBM.gbm_bo bo, IntPtr data);
+       public delegate void DestroyUserDataCallback(ref GBM.gbm_bo bo, ref uint data);
 
        [StructLayout(LayoutKind.Sequential)]
        public struct gbm_bo {
@@ -46,9 +46,9 @@ namespace Linux.GBM
                {
                        get { return BufferObject.gbm_bo_get_stride(ref this); }
                }
-               public void SetUserData(IntPtr data, DestroyUserDataCallback destroyFB)
+               public void SetUserData(ref uint data, DestroyUserDataCallback destroyFB)
                {
-                       BufferObject.gbm_bo_set_user_data(ref this, data, destroyFB);
+                       BufferObject.gbm_bo_set_user_data(ref this, ref data, destroyFB);
                }
        }
        unsafe public class BufferObject : IDisposable
@@ -58,6 +58,8 @@ namespace Linux.GBM
                internal static extern gbm_bo* gbm_bo_create (IntPtr gbm, uint width, uint height, SurfaceFormat format, SurfaceFlags flags);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                internal static extern void gbm_bo_destroy (gbm_bo* bo);
+               [DllImport("gbm", EntryPoint = "gbm_bo_destroy", CallingConvention = CallingConvention.Cdecl)]
+               internal static extern void destryBO (ref gbm_bo bo);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                internal static extern int gbm_bo_write(gbm_bo* bo, IntPtr buf, IntPtr count);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
@@ -71,11 +73,11 @@ namespace Linux.GBM
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                internal static extern uint gbm_bo_get_stride (ref gbm_bo bo);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
-               internal static extern void gbm_bo_set_user_data(ref gbm_bo bo, IntPtr data, DestroyUserDataCallback callback);
+               internal static extern void gbm_bo_set_user_data(ref gbm_bo bo, ref uint data, DestroyUserDataCallback callback);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                internal static extern IntPtr gbm_bo_get_user_data (IntPtr bo);
                [DllImport("gbm",  CallingConvention = CallingConvention.Cdecl)]
-               internal static extern IntPtr   gbm_bo_map (ref gbm_bo bo, uint x, uint y, uint width, uint height, TransferFlags flags, ref uint stride, out IntPtr data);
+               internal static extern IntPtr gbm_bo_map (ref gbm_bo bo, uint x, uint y, uint width, uint height, TransferFlags flags, ref uint stride, out IntPtr data);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                internal static extern void gbm_bo_unmap (ref gbm_bo bo, IntPtr data);
                #endregion
index 9257e14e1a986d3bdc8065a39ea93a35535e8043..073fab61fcdb04e7b5c6dd32d0e85ecc18488794 100644 (file)
@@ -130,7 +130,7 @@ namespace Linux.GBM
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                static extern IntPtr gbm_surface_create (IntPtr gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
-               static extern void gbm_surface_destroy (IntPtr surface);
+               internal static extern void gbm_surface_destroy (IntPtr surface);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
                static extern gbm_bo* gbm_surface_lock_front_buffer (IntPtr surface);
                [DllImport("gbm", CallingConvention = CallingConvention.Cdecl)]
index 66df986a3aa6eed4f333d0589833cac19c723d02..290ebc2bc46c5c56f4b2588079bf95146ac73d9c 100644 (file)
@@ -24,7 +24,7 @@
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
-    <DefineConstants>DEBUG;</DefineConstants>
+    <DefineConstants>DEBUG;MEASURE_TIME;</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -67,7 +67,6 @@
     <Compile Include="src\Linux\TTY.cs" />
     <Compile Include="src\Linux\Signal.cs" />
     <Compile Include="src\Linux\VT.cs" />
-    <Compile Include="src\Linux\DRI.cs" />
     <Compile Include="src\Linux\DRI\Connector.cs" />
     <Compile Include="src\Linux\DRI\Encoder.cs" />
     <Compile Include="src\Linux\DRI\Resources.cs" />
@@ -81,6 +80,8 @@
     <Compile Include="src\Linux\GBM\Device.cs" />
     <Compile Include="src\Application.cs" />
     <Compile Include="Main.cs" />
+    <Compile Include="src\Linux\DRI\PlaneResources.cs" />
+    <Compile Include="src\Linux\DRI\DRIControler.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
     <EmbeddedResource Include="ui\2.crow" />
     <EmbeddedResource Include="ui\colorItem.crow" />
     <EmbeddedResource Include="test.style" />
+    <EmbeddedResource Include="ui\perfMsr.crow">
+      <LogicalName>ui.perfMsr.crow</LogicalName>
+    </EmbeddedResource>
+    <EmbeddedResource Include="ui\perfMeasures.crow">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
     <None Include="src\DRMContext.cs" />
index bcb80e7c336f2895c4b610e9fc70e8c8a4ca74da..ab786226c1128a146bf56ecea0b84aee276d126e 100755 (executable)
                                        MouseDown="{Background=Mantis}"
                                        MouseUp="{Background=Onyx}"/>
                        </HorizontalStack>
-                       <GroupBox Caption="Templated controls" Height="Fit" Margin="5">
-                               <HorizontalStack Height="Fit">
-                                       <VerticalStack Width="50%">
-                                               <CheckBox IsChecked="true" Style="CheckBox2"/>
-                                               <CheckBox Style="CheckBox2"/>
-                                               <CheckBox Style="CheckBox2"/>
-                                               <CheckBox Style="CheckBox2"/>
-                                       </VerticalStack>
-                                       <Splitter/>
-                                       <VerticalStack Width="50%">
-                                               <RadioButton Style="RadioButton2"/>
-                                               <RadioButton Style="RadioButton2"/>
-                                               <RadioButton Style="RadioButton2"/>
-                                               <RadioButton Style="RadioButton2"/>
-                                       </VerticalStack>
-                               </HorizontalStack>
-                       </GroupBox>
+
                        <HorizontalStack Height="Fit">
                                <Label Text="Spinner"/>
                                <Spinner Fit="true"/>
                                <DirectoryView Name="dv" CurrentDirectory="/" Margin="1"/>
                        </Border>
                        <Splitter/>-->
-<!--                   <ListBox Name="colorList" Data="{TestList}" Margin="5"/>-->
-<!--                                    ItemTemplate="#testDrm.ui.colorItem.crow"
-                                        Template="#Crow.Templates.ScrollingListBox.goml"-->
+                       <ListBox Name="colorList" Data="{TestList}" Margin="5"
+                                        ItemTemplate="#testDrm.ui.colorItem.crow"
+                                        Template="#Crow.Templates.ScrollingListBox.goml"/>
                </VerticalStack>
        </HorizontalStack>
 </Window>
\ No newline at end of file
index 1843e2ddcdfb7c11370dca10699a3a0c5b88ec7e..a56d079db7a9c99948e52d11e3a0804166b6e11b 100755 (executable)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<Window Caption="Performances" Height="160" Width="200"      
+<Window Caption="Performances" Height="160" Width="200" CornerRadius="5">      
        <VerticalStack Width="90%" Height="Fit" Spacing="1" Margin="10">
                <HorizontalStack>
                        <Label Text="Frame:" Style="FpsLabel"/>
                        <Label Text="Drawing:" Style="FpsLabel"/>
                        <Label Text="{drawing}" Style="FpsDisp"/>
                </HorizontalStack>
-       
+               <HorizontalStack>
+                       <Label Text="IfaceSleep:" Style="FpsLabel"/>
+                       <Spinner Maximum="100" Fit="true" Value="{²InterfaceSleep}" />
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="FlipPollSleep:" Style="FpsLabel"/>
+                       <Spinner Maximum="100" Fit="true" Value="{²FlipPollSleep}" />
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="UpdateSleep:" Style="FpsLabel"/>
+                       <Spinner Maximum="100" Fit="true" Value="{²UpdateSleep}" />
+               </HorizontalStack>
        </VerticalStack>
 </Window>
\ No newline at end of file
index b3863d5dc829b0a6dea90f8c9ebd0aaf3399495d..e65adfb91419874afd14b48ef3af3b278678da82 100755 (executable)
@@ -6,6 +6,11 @@
                <MenuItem Caption="Save"/>
                <MenuItem Caption="Quit" MouseClick="onQuitClick"/>
        </MenuItem>
+       <MenuItem Caption="View" Width="Fit">
+               <MenuItem Command="{CMDViewPerf}"/>
+               <MenuItem Command="{CMDViewCfg}"/>
+               <MenuItem Command="{CMDViewTest0}"/>
+       </MenuItem>
        <MenuItem Caption="Edit" Name="edit" Width="Fit">
                <MenuItem Caption="Cut"/>
                <MenuItem Caption="Copy"/>
diff --git a/testDrm/ui/perfMeasures.crow b/testDrm/ui/perfMeasures.crow
new file mode 100755 (executable)
index 0000000..e49e7f1
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<Window Focusable="true" Caption="Measures" Width="30%" Height="Fit" MinimumSize="100,100">
+       <ListBox Data="{PerfMeasures}" Fit="true"
+               ItemTemplate="#ui.perfMsr.crow"/>
+</Window>
diff --git a/testDrm/ui/perfMsr.crow b/testDrm/ui/perfMsr.crow
new file mode 100755 (executable)
index 0000000..d823ea4
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+
+       <VerticalStack Spacing="0" Fit="true" Width="160">
+               <HorizontalStack Background="Black">
+                       <Label Text="{Name}" Width="Stretched" Font="doid bold, 10" Margin="2"/>
+                       <Button Caption="Reset" MouseClick="onResetClick" Height="Fit"/>
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="Current:" Style="FpsLabel"/>
+                       <Label Text="{current}" Style="FpsDisp"/>
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="Minimum:" Style="FpsLabel"/>
+                       <Label Text="{minimum}" Style="FpsDisp"/>
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="Mean:" Style="FpsLabel"/>
+                       <Label Text="{mean}" Style="FpsDisp"/>
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="Maximum:" Style="FpsLabel"/>
+                       <Label Text="{maximum}" Style="FpsDisp"/>
+               </HorizontalStack>
+<!--           <HorizontalStack>
+                       <Label Text="Total:" Style="FpsLabel"/>
+                       <Label Text="{total}" Style="FpsDisp"/>
+               </HorizontalStack>
+               <HorizontalStack>
+                       <Label Text="Cpt:" Style="FpsLabel"/>
+                       <Label Text="{cptMeasures}" Style="FpsDisp"/>
+               </HorizontalStack>-->
+       </VerticalStack>
+