void SetCursor(MouseCursor cursor) { BufferObject bo = default(BufferObject); if (cursor == MouseCursor.Default) { bo = cursor_default; } else if (cursor == MouseCursor.Empty) { bo = cursor_empty; } else { if (cursor_custom != BufferObject.Zero) { cursor_custom.Dispose(); } cursor_custom = CreateCursor(window.BufferManager, cursor); bo = cursor_custom; } // If we failed to create a proper cursor, try falling back // to the empty cursor. We do not want to crash here! if (bo == BufferObject.Zero) { bo = cursor_empty; } if (bo != BufferObject.Zero) { Drm.SetCursor(window.FD, window.DisplayDevice.Id, bo.Handle, bo.Width, bo.Height, cursor.X, cursor.Y); } }
public override void Update(IWindowInfo window) { WaitFlip(true); base.SwapBuffers(); bo = LockSurface(); int fb = GetFramebuffer(bo); SetScanoutRegion(fb); }
private static void HandleDestroyFB(BufferObject bo, IntPtr data) { IntPtr gbm = bo.Device; int fb = data.ToInt32(); Debug.Print("[KMS] Destroying framebuffer {0}", fb); if (fb != 0) { Drm.ModeRmFB(Gbm.DeviceGetFD(gbm), fb); } }
private int GetFramebuffer(BufferObject bo) { if (bo == BufferObject.Zero) { goto fail; } int bo_handle = bo.Handle; if (bo_handle == 0) { Debug.Print("[KMS] Gbm.BOGetHandle({0:x}) failed.", bo); goto fail; } int width = bo.Width; int height = bo.Height; int bpp = Mode.ColorFormat.BitsPerPixel; int depth = Mode.Depth; int stride = bo.Stride; if (width == 0 || height == 0 || bpp == 0) { Debug.Print("[KMS] Invalid framebuffer format: {0}x{1} {2} {3} {4}", width, height, stride, bpp, depth); goto fail; } int buffer; int ret = Drm.ModeAddFB( fd, width, height, (byte)depth, (byte)bpp, stride, bo_handle, out buffer); if (ret != 0) { Debug.Print("[KMS] Drm.ModeAddFB({0}, {1}, {2}, {3}, {4}, {5}, {6}) failed. Error: {7}", fd, width, height, depth, bpp, stride, bo_handle, ret); goto fail; } bo.SetUserData((IntPtr)buffer, DestroyFB); return(buffer); fail: Debug.Print("[Error] Failed to create framebuffer."); return(-1); }
private void WaitFlip(bool block) { PollFD fds = new PollFD(); fds.fd = fd; fds.events = PollFlags.In; EventContext evctx = new EventContext(); evctx.version = EventContext.Version; evctx.page_flip_handler = PageFlipPtr; int timeout = block ? -1 : 0; while (is_flip_queued) { 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) { Drm.HandleEvent(fd, ref evctx); } else { break; } } // Page flip has taken place, update buffer objects if (!is_flip_queued) { IntPtr gbm_surface = WindowInfo.Handle; Gbm.ReleaseBuffer(gbm_surface, bo); bo = bo_next; } }
static BufferObject CreateCursor(IntPtr gbm, MouseCursor cursor) { if (cursor.Width > 64 || cursor.Height > 64) { Debug.Print("[KMS] Cursor size {0}x{1} unsupported. Maximum is 64x64.", cursor.Width, cursor.Height); return(default(BufferObject)); } int width = 64; int height = 64; SurfaceFormat format = SurfaceFormat.ARGB8888; SurfaceFlags usage = SurfaceFlags.Cursor64x64 | SurfaceFlags.Write; Debug.Print("[KMS] Gbm.CreateBuffer({0:X}, {1}, {2}, {3}, {4}).", gbm, width, height, format, usage); BufferObject bo = Gbm.CreateBuffer( gbm, width, height, format, usage); if (bo == BufferObject.Zero) { Debug.Print("[KMS] Failed to create buffer."); return(bo); } // Copy cursor.Data into a new buffer of the correct size byte[] cursor_data = new byte[width * height * 4]; for (int y = 0; y < cursor.Height; y++) { int dst_offset = y * width * 4; int src_offset = y * cursor.Width * 4; int src_length = cursor.Width * 4; Array.Copy( cursor.Data, src_offset, cursor_data, dst_offset, src_length); } bo.Write(cursor_data); return(bo); }
public LinuxNativeWindow(IntPtr display, IntPtr gbm, int fd, int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice display_device) { Debug.Print("[KMS] Creating window on display {0:x}", display); Title = title; display_device = display_device ?? DisplayDevice.Default; if (display_device == null) { throw new NotSupportedException("[KMS] Driver does not currently support headless systems"); } window = new LinuxWindowInfo(display, fd, gbm, display_device.Id as LinuxDisplay); // Note: we only support fullscreen windows on KMS. // We implicitly override the requested width and height // by the width and height of the DisplayDevice, if any. width = display_device.Width; height = display_device.Height; bounds = new Rectangle(0, 0, width, height); client_size = bounds.Size; if (!mode.Index.HasValue) { mode = new EglGraphicsMode().SelectGraphicsMode(window, mode, 0); } Debug.Print("[KMS] Selected EGL mode {0}", mode); SurfaceFormat format = GetSurfaceFormat(display, mode); SurfaceFlags usage = SurfaceFlags.Rendering | SurfaceFlags.Scanout; if (!Gbm.IsFormatSupported(gbm, format, usage)) { Debug.Print("[KMS] Failed to find suitable surface format, using XRGB8888"); format = SurfaceFormat.XRGB8888; } Debug.Print("[KMS] Creating GBM surface on {0:x} with {1}x{2} {3} [{4}]", gbm, width, height, format, usage); IntPtr gbm_surface = Gbm.CreateSurface(gbm, width, height, format, usage); if (gbm_surface == IntPtr.Zero) { throw new NotSupportedException("[KMS] Failed to create GBM surface for rendering"); } window.Handle = gbm_surface; Debug.Print("[KMS] Created GBM surface {0:x}", window.Handle); window.CreateWindowSurface(mode.Index.Value); Debug.Print("[KMS] Created EGL surface {0:x}", window.Surface); cursor_default = CreateCursor(gbm, Cursors.Default); cursor_empty = CreateCursor(gbm, Cursors.Empty); Cursor = MouseCursor.Default; exists = true; }
public static extern void ReleaseBuffer(Surface surface, BufferObject buffer);
public static extern void DestroyBuffer(BufferObject bo);