1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Migrant; 10 using Antmicro.Renode.Backends.Display; 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.UserInterface; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.Video 17 { 18 [Icon("lcd")] 19 public abstract class AutoRepaintingVideo : IVideo, IDisposable 20 { AutoRepaintingVideo(IMachine machine)21 protected AutoRepaintingVideo(IMachine machine) 22 { 23 innerLock = new object(); 24 // we use synchronized thread since some deriving classes can generate interrupt on repainting 25 this.machine = machine; 26 repainter = machine.ObtainManagedThread(DoRepaint, FramesPerVirtualSecond); 27 Endianess = ELFSharp.ELF.Endianess.LittleEndian; 28 } 29 TakeScreenshot()30 public RawImageData TakeScreenshot() 31 { 32 if(buffer == null) 33 { 34 throw new RecoverableException("Frame buffer is empty."); 35 } 36 37 var converter = PixelManipulationTools.GetConverter(Format, Endianess, RawImageData.PixelFormat, ELFSharp.ELF.Endianess.BigEndian); 38 var outBuffer = new byte[Width * Height * RawImageData.PixelFormat.GetColorDepth()]; 39 converter.Convert(buffer, ref outBuffer); 40 41 return new RawImageData(outBuffer, Width, Height); 42 } 43 Dispose()44 public void Dispose() 45 { 46 repainter.Dispose(); 47 } 48 49 [field: Transient] 50 public event Action<byte[]> FrameRendered; 51 52 public uint FramesPerVirtualSecond 53 { 54 get 55 { 56 return framesPerVirtualSecond; 57 } 58 set 59 { 60 repainter.Dispose(); 61 repainter = machine.ObtainManagedThread(DoRepaint, value); 62 if(RepainterIsRunning) 63 { 64 repainter.Start(); 65 } 66 67 framesPerVirtualSecond = value; 68 } 69 } 70 public int Width { get; private set; } 71 public int Height { get; private set; } 72 public PixelFormat Format { get; private set; } 73 public ELFSharp.ELF.Endianess Endianess { get; protected set; } 74 public bool RepainterIsRunning { get; private set; } 75 76 public event Action<int, int, PixelFormat, ELFSharp.ELF.Endianess> ConfigurationChanged 77 { 78 add 79 { 80 lock (innerLock) 81 { 82 configurationChanged += value; 83 value(Width, Height, Format, Endianess); 84 } 85 } 86 87 remove 88 { 89 configurationChanged -= value; 90 } 91 } 92 Reset()93 public abstract void Reset(); 94 Reconfigure(int? width = null, int? height = null, PixelFormat? format = null, bool autoRepaint = true)95 protected void Reconfigure(int? width = null, int? height = null, PixelFormat? format = null, bool autoRepaint = true) 96 { 97 lock(innerLock) 98 { 99 var flag = false; 100 if(width != null && Width != width.Value) 101 { 102 Width = width.Value; 103 flag = true; 104 } 105 106 if(height != null && Height != height.Value) 107 { 108 Height = height.Value; 109 flag = true; 110 } 111 112 if(format != null && Format != format.Value) 113 { 114 Format = format.Value; 115 flag = true; 116 } 117 118 if(flag && Width > 0 && Height > 0) 119 { 120 buffer = new byte[Width * Height * Format.GetColorDepth()]; 121 122 var cc = configurationChanged; 123 if(cc != null) 124 { 125 cc(Width, Height, Format, Endianess); 126 } 127 if(autoRepaint) 128 { 129 RepainterIsRunning = true; 130 repainter.Start(); 131 } 132 else 133 { 134 RepainterIsRunning = false; 135 repainter.Stop(); 136 } 137 } 138 else 139 { 140 RepainterIsRunning = false; 141 repainter.Stop(); 142 } 143 } 144 } 145 Repaint()146 protected abstract void Repaint(); 147 DoRepaint()148 protected void DoRepaint() 149 { 150 if(buffer != null) 151 { 152 Repaint(); 153 var fr = FrameRendered; 154 if(fr != null) 155 { 156 lock(innerLock) 157 { 158 fr(buffer); 159 } 160 } 161 } 162 } 163 164 protected byte[] buffer; 165 166 private IManagedThread repainter; 167 [Transient] 168 private Action<int, int, PixelFormat, ELFSharp.ELF.Endianess> configurationChanged; 169 private readonly object innerLock; 170 private readonly IMachine machine; 171 private uint framesPerVirtualSecond = 25; 172 } 173 } 174 175