LinuxFramebuffer.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Runtime.InteropServices;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using Avalonia.Controls.Platform.Surfaces;
  10. using Avalonia.Platform;
  11. namespace Avalonia.LinuxFramebuffer
  12. {
  13. public sealed unsafe class LinuxFramebuffer : IFramebufferPlatformSurface, IDisposable
  14. {
  15. private readonly Vector _dpi;
  16. private int _fd;
  17. private fb_fix_screeninfo _fixedInfo;
  18. private fb_var_screeninfo _varInfo;
  19. private IntPtr _mappedLength;
  20. private IntPtr _mappedAddress;
  21. public LinuxFramebuffer(string fileName = null, Vector? dpi = null)
  22. {
  23. _dpi = dpi ?? new Vector(96, 96);
  24. fileName = fileName ?? Environment.GetEnvironmentVariable("FRAMEBUFFER") ?? "/dev/fb0";
  25. _fd = NativeUnsafeMethods.open(fileName, 2, 0);
  26. if (_fd <= 0)
  27. throw new Exception("Error: " + Marshal.GetLastWin32Error());
  28. try
  29. {
  30. Init();
  31. }
  32. catch
  33. {
  34. Dispose();
  35. throw;
  36. }
  37. }
  38. void Init()
  39. {
  40. fixed (void* pnfo = &_varInfo)
  41. {
  42. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, pnfo))
  43. throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
  44. SetBpp();
  45. _varInfo.yoffset = 100;
  46. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
  47. _varInfo.transp = new fb_bitfield();
  48. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
  49. throw new Exception("FBIOPUT_VSCREENINFO error: " + Marshal.GetLastWin32Error());
  50. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, pnfo))
  51. throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
  52. if (_varInfo.bits_per_pixel != 32)
  53. throw new Exception("Unable to set 32-bit display mode");
  54. }
  55. fixed(void*pnfo = &_fixedInfo)
  56. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_FSCREENINFO, pnfo))
  57. throw new Exception("FBIOGET_FSCREENINFO error: " + Marshal.GetLastWin32Error());
  58. _mappedLength = new IntPtr(_fixedInfo.line_length * _varInfo.yres);
  59. _mappedAddress = NativeUnsafeMethods.mmap(IntPtr.Zero, _mappedLength, 3, 1, _fd, IntPtr.Zero);
  60. if (_mappedAddress == new IntPtr(-1))
  61. throw new Exception($"Unable to mmap {_mappedLength} bytes, error {Marshal.GetLastWin32Error()}");
  62. fixed (fb_fix_screeninfo* pnfo = &_fixedInfo)
  63. {
  64. int idlen;
  65. for (idlen = 0; idlen < 16 && pnfo->id[idlen] != 0; idlen++) ;
  66. Id = Encoding.ASCII.GetString(pnfo->id, idlen);
  67. }
  68. }
  69. void SetBpp()
  70. {
  71. _varInfo.bits_per_pixel = 32;
  72. _varInfo.grayscale = 0;
  73. _varInfo.red = _varInfo.blue = _varInfo.green = _varInfo.transp = new fb_bitfield
  74. {
  75. length = 8
  76. };
  77. _varInfo.green.offset = 8;
  78. _varInfo.blue.offset = 16;
  79. _varInfo.transp.offset = 24;
  80. }
  81. public string Id { get; private set; }
  82. public Size PixelSize
  83. {
  84. get
  85. {
  86. fb_var_screeninfo nfo;
  87. if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, &nfo))
  88. throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
  89. return new Size(nfo.xres, nfo.yres);
  90. }
  91. }
  92. public ILockedFramebuffer Lock()
  93. {
  94. if (_fd <= 0)
  95. throw new ObjectDisposedException("LinuxFramebuffer");
  96. return new LockedFramebuffer(_fd, _fixedInfo, _varInfo, _mappedAddress, _dpi);
  97. }
  98. private void ReleaseUnmanagedResources()
  99. {
  100. if (_mappedAddress != IntPtr.Zero)
  101. {
  102. NativeUnsafeMethods.munmap(_mappedAddress, _mappedLength);
  103. _mappedAddress = IntPtr.Zero;
  104. }
  105. if(_fd == 0)
  106. return;
  107. NativeUnsafeMethods.close(_fd);
  108. _fd = 0;
  109. }
  110. public void Dispose()
  111. {
  112. ReleaseUnmanagedResources();
  113. GC.SuppressFinalize(this);
  114. }
  115. ~LinuxFramebuffer()
  116. {
  117. ReleaseUnmanagedResources();
  118. }
  119. }
  120. }