void Init(DrmCard card, DrmResources resources, DrmConnector connector, DrmModeInfo modeInfo) { FbDestroyDelegate = FbDestroyCallback; _card = card; uint GetCrtc() { if (resources.Encoders.TryGetValue(connector.EncoderId, out var encoder)) { // Not sure why that should work return(encoder.Encoder.crtc_id); } else { foreach (var encId in connector.EncoderIds) { if (resources.Encoders.TryGetValue(encId, out encoder) && encoder.PossibleCrtcs.Count > 0) { return(encoder.PossibleCrtcs.First().crtc_id); } } throw new InvalidOperationException("Unable to find CRTC matching the desired mode"); } } _crtcId = GetCrtc(); var device = gbm_create_device(card.Fd); _gbmTargetSurface = gbm_surface_create(device, modeInfo.Resolution.Width, modeInfo.Resolution.Height, GbmColorFormats.GBM_FORMAT_XRGB8888, GbmBoFlags.GBM_BO_USE_SCANOUT | GbmBoFlags.GBM_BO_USE_RENDERING); if (_gbmTargetSurface == null) { throw new InvalidOperationException("Unable to create GBM surface"); } _eglDisplay = new EglDisplay(new EglInterface(eglGetProcAddress), 0x31D7, device, null); _eglSurface = _eglDisplay.CreateWindowSurface(_gbmTargetSurface); EglContext CreateContext(EglContext share) { var offSurf = gbm_surface_create(device, 1, 1, GbmColorFormats.GBM_FORMAT_XRGB8888, GbmBoFlags.GBM_BO_USE_RENDERING); if (offSurf == null) { throw new InvalidOperationException("Unable to create 1x1 sized GBM surface"); } return(_eglDisplay.CreateContext(share, _eglDisplay.CreateWindowSurface(offSurf))); } _immediateContext = CreateContext(null); _deferredContext = CreateContext(_immediateContext); _immediateContext.MakeCurrent(_eglSurface); _eglDisplay.GlInterface.ClearColor(0, 0, 0, 0); _eglDisplay.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); _eglSurface.SwapBuffers(); var bo = gbm_surface_lock_front_buffer(_gbmTargetSurface); var fbId = GetFbIdForBo(bo); var connectorId = connector.Id; var mode = modeInfo.Mode; var res = drmModeSetCrtc(_card.Fd, _crtcId, fbId, 0, 0, &connectorId, 1, &mode); if (res != 0) { throw new Win32Exception(res, "drmModeSetCrtc failed"); } _mode = mode; _currentBo = bo; // Go trough two cycles of buffer swapping (there are render artifacts otherwise) for (var c = 0; c < 2; c++) { using (CreateGlRenderTarget().BeginDraw()) { _eglDisplay.GlInterface.ClearColor(0, 0, 0, 0); _eglDisplay.GlInterface.Clear(GlConsts.GL_COLOR_BUFFER_BIT | GlConsts.GL_STENCIL_BUFFER_BIT); } } }
private static int RunApp() { app.Out.WriteLine("Hello World!"); int brightnessValue = 100; if (brightness.HasValue()) { if (int.TryParse(brightness.Value(), out brightnessValue)) { if (brightnessValue < 1 || brightnessValue > 100) { app.Error.WriteLine("Brightness value outside allowed values"); return(-1); } } else { app.Error.WriteLine("Invalid brightness value"); return(-1); } } //long uid = UnixUserInfo.GetRealUserId(); //if (uid != 0) //{ // app.Out.WriteLine("You must run this app as root."); // return -1; //} //ServiceCollection serviceConfig = new ServiceCollection(); //serviceConfig.AddLogging(); //serviceConfig.AddOptions(); //serviceConfig.AddBcm(); //serviceConfig.AddOpenGl(); //serviceConfig.AddLedMatrix(); //using (ServiceProvider services = serviceConfig.BuildServiceProvider()) //{ // services.GetRequiredService<ILoggerFactory>().AddConsole(LogLevel.Information); // return RunApp(services); //} using (LedMatrixOptions options = new LedMatrixOptions() { chain_length = 2, parallel = 1, rows = 64, led_rgb_sequence = "RBG", pwm_bits = 8, show_refresh_rate = 1, brightness = brightnessValue, }) using (LedMatrix matrix = new LedMatrix(options.rows, options.chain_length, options.parallel)) using (BcmHost host = new BcmHost()) using (Resource target = host.Dispman.CreateResource(VC_IMAGE_TYPE_T.VC_IMAGE_RGB888, matrix.CanvasWidth, matrix.CanvasHeight)) using (Display display = host.Dispman.DisplayOpenOffscreen(target, DISPMANX_TRANSFORM_T.DISPMANX_NO_ROTATE)) //using (Display display = host.Dispman.DisplayOpen(Screen.MAIN_LCD)) using (ScopedElement element = ScopedElement.Create(host, display, null, destRect: display.Rectangle, srcRect: Rescale(display.Rectangle))) using (DispmanWindow window = new DispmanWindow(element, display.Width, display.Height)) using (EglDisplay eglDisp = new EglDisplay()) using (EglContext ctx = new EglContext(eglDisp)) using (EglSurface surface = new EglSurface(eglDisp, window)) using (Data data = new Data()) { Rectangle rect = display.Rectangle; app.Out.WriteLine("Ready to go, screen is {0}x{1}", display.Width, display.Height); Stopwatch swatch = Stopwatch.StartNew(); app.Out.WriteLine("Initializing 3D context"); ctx.MakeCurrent(surface); app.Out.WriteLine("init_ogl"); init_ogl(); app.Out.WriteLine("init_model_proj"); init_model_proj(rect, data); app.Out.WriteLine("init_textures"); init_textures(data); app.Out.WriteLine("Initializing buffer"); //int bufferLength = rect.Width * rect.Height * 3; //byte[] buffer = new byte[bufferLength]; app.Out.WriteLine("Init complete, starting loop"); //Render loop bool run = true; Console.CancelKeyPress += (s, e) => { if (run) { run = false; e.Cancel = true; } }; Console.TreatControlCAsInput = true; int pitch = Utils.ALIGN_UP(3 * display.Width, 32); byte[] image = new byte[pitch * display.Height]; app.Out.WriteLine("Buffer size: {0}", image.Length); while (run) { if (Console.KeyAvailable) { var key = Console.ReadKey(true); if (key.Key == ConsoleKey.C && key.Modifiers == ConsoleModifiers.Control) { run = false; Console.TreatControlCAsInput = false; continue; } if (key.Key == ConsoleKey.Add || key.Key == ConsoleKey.Subtract) { int newB; if (key.Key == ConsoleKey.Add) { newB = Math.Min(options.brightness + 1, 100); } else { newB = Math.Max(options.brightness - 1, 0); } if (options.brightness != newB) { options.brightness = newB; app.Out.WriteLine("New brightness: {0}%", newB); if (!matrix.UpdateOptions(options)) { app.Out.WriteLine("Update option failed"); } } } } update_model(); redraw_scene(surface); //extract data to buffer //target.WriteData(1, buffer, rect); target.ReadData(rect, image, pitch); //Display image to matrix matrix.UpdateCanvas(canvas => { for (int x = 0; x < canvas.Width; x++) { for (int y = 0; y < canvas.Height; y++) { int baseAddr = (x * canvas.Width + y) * 3; try { byte r = image[baseAddr + 0]; byte g = image[baseAddr + 1]; byte b = image[baseAddr + 2]; canvas.SetPixel(x, y, r, g, b); } catch (IndexOutOfRangeException ex) { app.Out.WriteLine("X={0} Y={1} baseAddre={2} pitch={3}", x, y, baseAddr, pitch); System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); } } } }); app.Out.Write("."); } return(0); } }