| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Threading.Tasks;
- using Avalonia.Controls.Platform.Surfaces;
- using Avalonia.Platform;
- namespace Avalonia.LinuxFramebuffer
- {
- public sealed unsafe class LinuxFramebuffer : IFramebufferPlatformSurface, IDisposable
- {
- private readonly Vector _dpi;
- private int _fd;
- private fb_fix_screeninfo _fixedInfo;
- private fb_var_screeninfo _varInfo;
- private IntPtr _mappedLength;
- private IntPtr _mappedAddress;
- public LinuxFramebuffer(string fileName = null, Vector? dpi = null)
- {
- _dpi = dpi ?? new Vector(96, 96);
- fileName = fileName ?? Environment.GetEnvironmentVariable("FRAMEBUFFER") ?? "/dev/fb0";
- _fd = NativeUnsafeMethods.open(fileName, 2, 0);
- if (_fd <= 0)
- throw new Exception("Error: " + Marshal.GetLastWin32Error());
- try
- {
- Init();
- }
- catch
- {
- Dispose();
- throw;
- }
- }
- void Init()
- {
- fixed (void* pnfo = &_varInfo)
- {
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, pnfo))
- throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
- SetBpp();
- _varInfo.yoffset = 100;
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
- _varInfo.transp = new fb_bitfield();
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOPUT_VSCREENINFO, pnfo))
- throw new Exception("FBIOPUT_VSCREENINFO error: " + Marshal.GetLastWin32Error());
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, pnfo))
- throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
- if (_varInfo.bits_per_pixel != 32)
- throw new Exception("Unable to set 32-bit display mode");
- }
- fixed(void*pnfo = &_fixedInfo)
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_FSCREENINFO, pnfo))
- throw new Exception("FBIOGET_FSCREENINFO error: " + Marshal.GetLastWin32Error());
- _mappedLength = new IntPtr(_fixedInfo.line_length * _varInfo.yres);
- _mappedAddress = NativeUnsafeMethods.mmap(IntPtr.Zero, _mappedLength, 3, 1, _fd, IntPtr.Zero);
- if (_mappedAddress == new IntPtr(-1))
- throw new Exception($"Unable to mmap {_mappedLength} bytes, error {Marshal.GetLastWin32Error()}");
- fixed (fb_fix_screeninfo* pnfo = &_fixedInfo)
- {
- int idlen;
- for (idlen = 0; idlen < 16 && pnfo->id[idlen] != 0; idlen++) ;
- Id = Encoding.ASCII.GetString(pnfo->id, idlen);
- }
- }
- void SetBpp()
- {
- _varInfo.bits_per_pixel = 32;
- _varInfo.grayscale = 0;
- _varInfo.red = _varInfo.blue = _varInfo.green = _varInfo.transp = new fb_bitfield
- {
- length = 8
- };
- _varInfo.green.offset = 8;
- _varInfo.blue.offset = 16;
- _varInfo.transp.offset = 24;
- }
- public string Id { get; private set; }
- public Size PixelSize
- {
- get
- {
- fb_var_screeninfo nfo;
- if (-1 == NativeUnsafeMethods.ioctl(_fd, FbIoCtl.FBIOGET_VSCREENINFO, &nfo))
- throw new Exception("FBIOGET_VSCREENINFO error: " + Marshal.GetLastWin32Error());
- return new Size(nfo.xres, nfo.yres);
- }
- }
- public ILockedFramebuffer Lock()
- {
- if (_fd <= 0)
- throw new ObjectDisposedException("LinuxFramebuffer");
- return new LockedFramebuffer(_fd, _fixedInfo, _varInfo, _mappedAddress, _dpi);
- }
- private void ReleaseUnmanagedResources()
- {
- if (_mappedAddress != IntPtr.Zero)
- {
- NativeUnsafeMethods.munmap(_mappedAddress, _mappedLength);
- _mappedAddress = IntPtr.Zero;
- }
- if(_fd == 0)
- return;
- NativeUnsafeMethods.close(_fd);
- _fd = 0;
- }
- public void Dispose()
- {
- ReleaseUnmanagedResources();
- GC.SuppressFinalize(this);
- }
- ~LinuxFramebuffer()
- {
- ReleaseUnmanagedResources();
- }
- }
- }
|