1 /*
2 libgo2 - Support library for the ODROID-GO Advance
3 Copyright (C) 2020 OtherCrashOverride
4 
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9 
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19 
20 #include "display.h"
21 
22 #include "queue.h"
23 
24 #include <xf86drm.h>
25 #include <xf86drmMode.h>
26 #include <drm/drm_fourcc.h>
27 #include <gbm.h>
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39 #include <pthread.h>
40 #include <semaphore.h>
41 
42 #include <rga/RgaApi.h>
43 
44 #define EGL_EGLEXT_PROTOTYPES
45 //#define GL_GLEXT_PROTOTYPES
46 #include <EGL/egl.h>
47 #include <EGL/eglext.h>
48 // #include <GLES2/gl2.h>
49 // #include <GLES2/gl2ext.h>
50 
51 #include <png.h>
52 
53 
54 typedef struct go2_display
55 {
56     int fd;
57     uint32_t connector_id;
58     drmModeModeInfo mode;
59     uint32_t width;
60     uint32_t height;
61     uint32_t crtc_id;
62 } go2_display_t;
63 
64 typedef struct go2_surface
65 {
66     go2_display_t* display;
67     uint32_t gem_handle;
68     uint64_t size;
69     int width;
70     int height;
71     int stride;
72     uint32_t format;
73     int prime_fd;
74     uint8_t* map;
75 } go2_surface_t;
76 
77 typedef struct go2_frame_buffer
78 {
79     go2_surface_t* surface;
80     uint32_t fb_id;
81 } go2_frame_buffer_t;
82 
83 typedef struct go2_presenter
84 {
85     go2_display_t* display;
86     uint32_t format;
87     uint32_t background_color;
88     go2_queue_t* freeFrameBuffers;
89     go2_queue_t* usedFrameBuffers;
90     pthread_mutex_t queueMutex;
91     pthread_t renderThread;
92     sem_t freeSem;
93     sem_t usedSem;
94     volatile bool terminating;
95     bool managed;
96 } go2_presenter_t;
97 
98 
go2_display_create()99 go2_display_t* go2_display_create()
100 {
101     int i;
102 
103     go2_display_t* result = malloc(sizeof(*result));
104     if (!result)
105     {
106         printf("malloc failed.\n");
107         goto out;
108     }
109 
110     memset(result, 0, sizeof(*result));
111 
112 
113     // Open device
114     result->fd = open("/dev/dri/card0", O_RDWR);
115     if (result->fd < 0)
116     {
117         printf("open /dev/dri/card0 failed.\n");
118         goto err_00;
119     }
120 
121 
122     drmModeRes* resources = drmModeGetResources(result->fd);
123     if (!resources)
124     {
125         printf("drmModeGetResources failed: %s\n", strerror(errno));
126         goto err_01;
127     }
128 
129 
130     // Find connector
131     drmModeConnector* connector;
132     for (i = 0; i < resources->count_connectors; i++)
133     {
134         connector = drmModeGetConnector(result->fd, resources->connectors[i]);
135         if (connector->connection == DRM_MODE_CONNECTED) {
136             break;
137         }
138 
139         drmModeFreeConnector(connector);
140         connector = NULL;
141     }
142 
143     if (!connector)
144     {
145         printf("DRM_MODE_CONNECTED not found.\n");
146         goto err_02;
147     }
148 
149     result->connector_id = connector->connector_id;
150 
151 
152     // Find prefered mode
153     drmModeModeInfo* mode;
154     for (i = 0; i < connector->count_modes; i++)
155     {
156         drmModeModeInfo *current_mode = &connector->modes[i];
157         if (current_mode->type & DRM_MODE_TYPE_PREFERRED)
158         {
159             mode = current_mode;
160             break;
161         }
162 
163         mode = NULL;
164     }
165 
166     if (!mode)
167     {
168         printf("DRM_MODE_TYPE_PREFERRED not found.\n");
169         goto err_03;
170     }
171 
172     result->mode = *mode;
173     result->width = mode->hdisplay;
174     result->height = mode->vdisplay;
175 
176 
177     // Find encoder
178     drmModeEncoder* encoder;
179     for (i = 0; i < resources->count_encoders; i++)
180     {
181         encoder = drmModeGetEncoder(result->fd, resources->encoders[i]);
182         if (encoder->encoder_id == connector->encoder_id)
183         {
184             break;
185         }
186 
187         drmModeFreeEncoder(encoder);
188         encoder = NULL;
189     }
190 
191     if (!encoder)
192     {
193 
194         printf("could not find encoder!\n");
195         goto err_03;
196     }
197 
198     result->crtc_id = encoder->crtc_id;
199 
200     drmModeFreeEncoder(encoder);
201     drmModeFreeConnector(connector);
202     drmModeFreeResources(resources);
203 
204     return result;
205 
206 
207 err_03:
208     drmModeFreeConnector(connector);
209 
210 err_02:
211     drmModeFreeResources(resources);
212 
213 err_01:
214     close(result->fd);
215 
216 err_00:
217     free(result);
218 
219 out:
220     return NULL;
221 }
222 
223 
go2_display_destroy(go2_display_t * display)224 void go2_display_destroy(go2_display_t* display)
225 {
226     close(display->fd);
227     free(display);
228 }
229 
go2_display_width_get(go2_display_t * display)230 int go2_display_width_get(go2_display_t* display)
231 {
232     return display->width;
233 }
234 
go2_display_height_get(go2_display_t * display)235 int go2_display_height_get(go2_display_t* display)
236 {
237     return display->height;
238 }
239 
go2_display_present(go2_display_t * display,go2_frame_buffer_t * frame_buffer)240 void go2_display_present(go2_display_t* display, go2_frame_buffer_t* frame_buffer)
241 {
242     int ret = drmModeSetCrtc(display->fd, display->crtc_id, frame_buffer->fb_id, 0, 0, &display->connector_id, 1, &display->mode);
243     if (ret)
244     {
245         printf("drmModeSetCrtc failed.\n");
246     }
247 }
248 
249 const char* BACKLIGHT_BRIGHTNESS_NAME = "/sys/class/backlight/backlight/brightness";
250 const char* BACKLIGHT_BRIGHTNESS_MAX_NAME = "/sys/class/backlight/backlight/max_brightness";
251 #define BACKLIGHT_BUFFER_SIZE (127)
252 
go2_display_backlight_get(go2_display_t * display)253 uint32_t go2_display_backlight_get(go2_display_t* display)
254 {
255     int fd;
256     int max = 255;
257     int value = 0;
258     char buffer[BACKLIGHT_BUFFER_SIZE + 1];
259 
260     fd = open(BACKLIGHT_BRIGHTNESS_MAX_NAME, O_RDONLY);
261     if (fd > 0)
262     {
263         memset(buffer, 0, BACKLIGHT_BUFFER_SIZE + 1);
264 
265         ssize_t count = read(fd, buffer, BACKLIGHT_BUFFER_SIZE);
266         if (count > 0)
267         {
268             max = atoi(buffer);
269         }
270 
271         close(fd);
272 
273         if (max == 0) return 0;
274     }
275 
276     fd = open(BACKLIGHT_BRIGHTNESS_NAME, O_RDONLY);
277     if (fd > 0)
278     {
279         memset(buffer, 0, BACKLIGHT_BUFFER_SIZE + 1);
280 
281         ssize_t count = read(fd, buffer, BACKLIGHT_BUFFER_SIZE);
282         if (count > 0)
283         {
284             value = atoi(buffer);
285         }
286 
287         close(fd);
288     }
289 
290     float percent = value / (float)max * 100.0f;
291     return (uint32_t)percent;
292 }
293 
go2_display_backlight_set(go2_display_t * display,uint32_t value)294 void go2_display_backlight_set(go2_display_t* display, uint32_t value)
295 {
296     int fd;
297     int max = 255;
298     char buffer[BACKLIGHT_BUFFER_SIZE + 1];
299 
300 
301     if (value > 100) value = 100;
302 
303     fd = open(BACKLIGHT_BRIGHTNESS_MAX_NAME, O_RDONLY);
304     if (fd > 0)
305     {
306         memset(buffer, 0, BACKLIGHT_BUFFER_SIZE + 1);
307 
308         ssize_t count = read(fd, buffer, BACKLIGHT_BUFFER_SIZE);
309         if (count > 0)
310         {
311             max = atoi(buffer);
312         }
313 
314         close(fd);
315 
316         if (max == 0) return;
317     }
318 
319     fd = open(BACKLIGHT_BRIGHTNESS_NAME, O_WRONLY);
320     if (fd > 0)
321     {
322         float percent = value / 100.0f * (float)max;
323         sprintf(buffer, "%d\n", (uint32_t)percent);
324 
325         //printf("backlight=%d, max=%d\n", (uint32_t)percent, max);
326 
327         ssize_t count = write(fd, buffer, strlen(buffer));
328         if (count < 0)
329         {
330             printf("go2_display_backlight_set write failed.\n");
331         }
332 
333         close(fd);
334     }
335     else
336     {
337         printf("go2_display_backlight_set open failed.\n");
338     }
339 
340 }
341 
342 
go2_drm_format_get_bpp(uint32_t format)343 int go2_drm_format_get_bpp(uint32_t format)
344 {
345     int result;
346 
347     switch(format)
348     {
349         case DRM_FORMAT_XRGB4444:
350         case DRM_FORMAT_XBGR4444:
351         case DRM_FORMAT_RGBX4444:
352         case DRM_FORMAT_BGRX4444:
353 
354         case DRM_FORMAT_ARGB4444:
355         case DRM_FORMAT_ABGR4444:
356         case DRM_FORMAT_RGBA4444:
357         case DRM_FORMAT_BGRA4444:
358 
359         case DRM_FORMAT_XRGB1555:
360         case DRM_FORMAT_XBGR1555:
361         case DRM_FORMAT_RGBX5551:
362         case DRM_FORMAT_BGRX5551:
363 
364         case DRM_FORMAT_ARGB1555:
365         case DRM_FORMAT_ABGR1555:
366         case DRM_FORMAT_RGBA5551:
367         case DRM_FORMAT_BGRA5551:
368 
369         case DRM_FORMAT_RGB565:
370         case DRM_FORMAT_BGR565:
371             result = 16;
372             break;
373 
374 
375         case DRM_FORMAT_RGB888:
376         case DRM_FORMAT_BGR888:
377             result = 24;
378             break;
379 
380 
381         case DRM_FORMAT_XRGB8888:
382         case DRM_FORMAT_XBGR8888:
383         case DRM_FORMAT_RGBX8888:
384         case DRM_FORMAT_BGRX8888:
385 
386         case DRM_FORMAT_ARGB8888:
387         case DRM_FORMAT_ABGR8888:
388         case DRM_FORMAT_RGBA8888:
389         case DRM_FORMAT_BGRA8888:
390 
391         case DRM_FORMAT_XRGB2101010:
392         case DRM_FORMAT_XBGR2101010:
393         case DRM_FORMAT_RGBX1010102:
394         case DRM_FORMAT_BGRX1010102:
395 
396         case DRM_FORMAT_ARGB2101010:
397         case DRM_FORMAT_ABGR2101010:
398         case DRM_FORMAT_RGBA1010102:
399         case DRM_FORMAT_BGRA1010102:
400             result = 32;
401             break;
402 
403 
404         default:
405             printf("unhandled DRM FORMAT.\n");
406             result = 0;
407     }
408 
409     return result;
410 }
411 
go2_surface_create(go2_display_t * display,int width,int height,uint32_t format)412 go2_surface_t* go2_surface_create(go2_display_t* display, int width, int height, uint32_t format)
413 {
414     go2_surface_t* result = malloc(sizeof(*result));
415     if (!result)
416     {
417         printf("malloc failed.\n");
418         goto out;
419     }
420 
421     memset(result, 0, sizeof(*result));
422 
423 
424     struct drm_mode_create_dumb args = {0};
425     args.width = width;
426     args.height = height;
427     args.bpp = go2_drm_format_get_bpp(format);
428     args.flags = 0;
429 
430     int io = drmIoctl(display->fd, DRM_IOCTL_MODE_CREATE_DUMB, &args);
431     if (io < 0)
432     {
433         printf("DRM_IOCTL_MODE_CREATE_DUMB failed.\n");
434         goto out;
435     }
436 
437 
438     result->display = display;
439     result->gem_handle = args.handle;
440     result->size = args.size;
441     result->width = width;
442     result->height = height;
443     result->stride = args.pitch;
444     result->format = format;
445     result->map = NULL;
446 
447     return result;
448 
449 out:
450     free(result);
451     return NULL;
452 }
453 
go2_surface_destroy(go2_surface_t * surface)454 void go2_surface_destroy(go2_surface_t* surface)
455 {
456     struct drm_mode_destroy_dumb args = { 0 };
457     args.handle = surface->gem_handle;
458 
459     int io = drmIoctl(surface->display->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &args);
460     if (io < 0)
461     {
462         printf("DRM_IOCTL_MODE_DESTROY_DUMB failed.\n");
463     }
464 
465     free(surface);
466 }
467 
go2_surface_width_get(go2_surface_t * surface)468 int go2_surface_width_get(go2_surface_t* surface)
469 {
470     return surface->width;
471 }
472 
go2_surface_height_get(go2_surface_t * surface)473 int go2_surface_height_get(go2_surface_t* surface)
474 {
475     return surface->height;
476 }
477 
go2_surface_format_get(go2_surface_t * surface)478 uint32_t go2_surface_format_get(go2_surface_t* surface)
479 {
480     return surface->format;
481 }
482 
go2_surface_stride_get(go2_surface_t * surface)483 int go2_surface_stride_get(go2_surface_t* surface)
484 {
485     return surface->stride;
486 }
487 
go2_surface_display_get(go2_surface_t * surface)488 go2_display_t* go2_surface_display_get(go2_surface_t* surface)
489 {
490     return surface->display;
491 }
492 
go2_surface_prime_fd(go2_surface_t * surface)493 int go2_surface_prime_fd(go2_surface_t* surface)
494 {
495     if (surface->prime_fd <= 0)
496     {
497         int io = drmPrimeHandleToFD(surface->display->fd, surface->gem_handle, DRM_RDWR | DRM_CLOEXEC, &surface->prime_fd);
498         if (io < 0)
499         {
500             printf("drmPrimeHandleToFD failed.\n");
501             goto out;
502         }
503     }
504 
505     return surface->prime_fd;
506 
507 out:
508     surface->prime_fd = 0;
509     return 0;
510 }
511 
go2_surface_map(go2_surface_t * surface)512 void* go2_surface_map(go2_surface_t* surface)
513 {
514     if (surface->map)
515         return surface->map;
516 
517     int prime_fd = go2_surface_prime_fd(surface);
518     surface->map = mmap(NULL, surface->size, PROT_READ | PROT_WRITE, MAP_SHARED, prime_fd, 0);
519     if (surface->map == MAP_FAILED)
520     {
521         printf("mmap failed.\n");
522         return NULL;
523     }
524 
525     return surface->map;
526 }
527 
go2_surface_unmap(go2_surface_t * surface)528 void go2_surface_unmap(go2_surface_t* surface)
529 {
530     if (surface->map)
531     {
532         munmap(surface->map, surface->size);
533         surface->map = NULL;
534     }
535 }
536 
537 
go2_rkformat_get(uint32_t drm_fourcc)538 static uint32_t go2_rkformat_get(uint32_t drm_fourcc)
539 {
540     switch (drm_fourcc)
541     {
542         case DRM_FORMAT_RGBA8888:
543             return RK_FORMAT_RGBA_8888;
544 
545         case DRM_FORMAT_RGBX8888:
546             return RK_FORMAT_RGBX_8888;
547 
548         case DRM_FORMAT_RGB888:
549             return RK_FORMAT_RGB_888;
550 
551         case DRM_FORMAT_ARGB8888:
552         case DRM_FORMAT_XRGB8888:
553             return RK_FORMAT_BGRA_8888;
554 
555         case DRM_FORMAT_RGB565:
556             return RK_FORMAT_RGB_565;
557 
558         case DRM_FORMAT_RGBA5551:
559             return RK_FORMAT_RGBA_5551;
560 
561         case DRM_FORMAT_RGBA4444:
562             return RK_FORMAT_RGBA_4444;
563 
564         case DRM_FORMAT_BGR888:
565             return RK_FORMAT_BGR_888;
566 
567         default:
568             printf("RKFORMAT not supported. ");
569             printf("drm_fourcc=%c%c%c%c\n", drm_fourcc & 0xff, drm_fourcc >> 8 & 0xff, drm_fourcc >> 16 & 0xff, drm_fourcc >> 24);
570             return 0;
571     }
572 }
573 
go2_surface_blit(go2_surface_t * srcSurface,int srcX,int srcY,int srcWidth,int srcHeight,go2_surface_t * dstSurface,int dstX,int dstY,int dstWidth,int dstHeight,go2_rotation_t rotation,int scale_mode)574 void go2_surface_blit(go2_surface_t* srcSurface, int srcX, int srcY, int srcWidth, int srcHeight,
575                       go2_surface_t* dstSurface, int dstX, int dstY, int dstWidth, int dstHeight,
576                       go2_rotation_t rotation, int scale_mode)
577 {
578     rga_info_t dst = { 0 };
579     dst.fd = go2_surface_prime_fd(dstSurface);
580     dst.mmuFlag = 1;
581     dst.rect.xoffset = dstX;
582     dst.rect.yoffset = dstY;
583     dst.rect.width = dstWidth;
584     dst.rect.height = dstHeight;
585     dst.rect.wstride = dstSurface->stride / (go2_drm_format_get_bpp(dstSurface->format) / 8);
586     dst.rect.hstride = dstSurface->height;
587     dst.rect.format = go2_rkformat_get(dstSurface->format);
588 
589     rga_info_t src = { 0 };
590     src.fd = go2_surface_prime_fd(srcSurface);
591     src.mmuFlag = 1;
592 
593     switch (rotation)
594     {
595         case GO2_ROTATION_DEGREES_0:
596             src.rotation = 0;
597             break;
598 
599         case GO2_ROTATION_DEGREES_90:
600             src.rotation = HAL_TRANSFORM_ROT_90;
601             break;
602 
603         case GO2_ROTATION_DEGREES_180:
604             src.rotation = HAL_TRANSFORM_ROT_180;
605             break;
606 
607         case GO2_ROTATION_DEGREES_270:
608             src.rotation = HAL_TRANSFORM_ROT_270;
609             break;
610 
611         default:
612             printf("rotation not supported.\n");
613             return;
614     }
615 
616     src.rect.xoffset = srcX;
617     src.rect.yoffset = srcY;
618     src.rect.width = srcWidth;
619     src.rect.height = srcHeight;
620     src.rect.wstride = srcSurface->stride / (go2_drm_format_get_bpp(srcSurface->format) / 8);
621     src.rect.hstride = srcSurface->height;
622     src.rect.format = go2_rkformat_get(srcSurface->format);
623 
624 #if 0
625     enum
626     {
627         CATROM    = 0x0,
628         MITCHELL  = 0x1,
629         HERMITE   = 0x2,
630         B_SPLINE  = 0x3,
631     };  /*bicubic coefficient*/
632 #endif
633     src.scale_mode = scale_mode;
634 
635     int ret = c_RkRgaBlit(&src, &dst, NULL);
636     if (ret)
637     {
638         printf("c_RkRgaBlit failed.\n");
639     }
640 }
641 
go2_surface_save_as_png(go2_surface_t * surface,const char * filename)642 int go2_surface_save_as_png(go2_surface_t* surface, const char* filename)
643 {
644     png_structp png_ptr = NULL;
645     png_infop info_ptr = NULL;
646     png_bytep* row_pointers = NULL;
647 
648 
649     png_byte color_type = 0;
650     png_byte bit_depth = 0;
651     switch (surface->format)
652     {
653         case DRM_FORMAT_RGBA8888:
654             color_type = PNG_COLOR_TYPE_RGBA;
655             bit_depth = 8;
656             break;
657 
658         case DRM_FORMAT_RGB888:
659             color_type = PNG_COLOR_TYPE_RGB;
660             bit_depth = 8;
661             break;
662 
663         case DRM_FORMAT_RGBX8888:
664         case DRM_FORMAT_RGB565:
665         case DRM_FORMAT_ARGB8888:
666         case DRM_FORMAT_XRGB8888:
667         case DRM_FORMAT_RGBA5551:
668         case DRM_FORMAT_RGBA4444:
669         case DRM_FORMAT_BGR888:
670 
671         default:
672             printf("The image format is not supported.\n");
673             return -2;
674     }
675 
676 
677     // based on http://zarb.org/~gc/html/libpng.html
678 
679     /* create file */
680     FILE *fp = fopen(filename, "wb");
681     if (!fp)
682     {
683         printf("fopen failed. filename='%s'\n", filename);
684         return -1;
685     }
686 
687 
688     /* initialize stuff */
689     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
690 
691     if (!png_ptr)
692     {
693         printf("png_create_write_struct failed.\n");
694         fclose(fp);
695         return -1;
696     }
697 
698     info_ptr = png_create_info_struct(png_ptr);
699     if (!info_ptr)
700     {
701         printf("png_create_info_struct failed.\n");
702         fclose(fp);
703         return -1;
704     }
705 
706     if (setjmp(png_jmpbuf(png_ptr)))
707     {
708         printf("init_io failed.\n");
709         goto out;
710     }
711 
712     png_init_io(png_ptr, fp);
713 
714 
715     /* write header */
716     if (setjmp(png_jmpbuf(png_ptr)))
717      {
718         printf("write header failed.\n");
719         goto out;
720     }
721 
722     png_set_IHDR(png_ptr, info_ptr, surface->width, surface->height,
723                  bit_depth, color_type, PNG_INTERLACE_NONE,
724                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
725 
726     png_write_info(png_ptr, info_ptr);
727 
728 
729     /* write bytes */
730     png_bytep src = (png_bytep)go2_surface_map(surface);
731     row_pointers = malloc(sizeof(png_bytep) * surface->height);
732     for (int y = 0; y < surface->height; ++y)
733     {
734         row_pointers[y] = src + (surface->stride * y);
735     }
736 
737     if (setjmp(png_jmpbuf(png_ptr)))
738     {
739         printf("writing bytes failed.\n");
740         goto out;
741     }
742 
743     png_write_image(png_ptr, row_pointers);
744 
745 
746     /* end write */
747     if (setjmp(png_jmpbuf(png_ptr)))
748     {
749         printf("end of write failed.\n");
750         goto out;
751     }
752 
753     png_write_end(png_ptr, NULL);
754 
755     /* cleanup heap allocation */
756     free(row_pointers);
757 
758     fclose(fp);
759     return 0;
760 
761 out:
762     if (info_ptr)
763         png_destroy_info_struct(png_ptr, &info_ptr);
764 
765     if (png_ptr)
766         png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
767 
768     if (row_pointers)
769         free(row_pointers);
770 
771     if (fp)
772         fclose(fp);
773 
774     return -1;
775 }
776 
777 
go2_frame_buffer_create(go2_surface_t * surface)778 go2_frame_buffer_t* go2_frame_buffer_create(go2_surface_t* surface)
779 {
780     go2_frame_buffer_t* result = malloc(sizeof(*result));
781     if (!result)
782     {
783         printf("malloc failed.\n");
784         return NULL;
785     }
786 
787     memset(result, 0, sizeof(*result));
788 
789 
790     result->surface = surface;
791 
792     const uint32_t handles[4] = {surface->gem_handle, 0, 0, 0};
793     const uint32_t pitches[4] = {surface->stride, 0, 0, 0};
794     const uint32_t offsets[4] = {0, 0, 0, 0};
795 
796     int ret = drmModeAddFB2(surface->display->fd,
797         surface->width,
798         surface->height,
799         surface->format,
800         handles,
801         pitches,
802         offsets,
803         &result->fb_id,
804         0);
805     if (ret)
806     {
807         printf("drmModeAddFB2 failed.\n");
808         free(result);
809         return NULL;
810     }
811 
812     return result;
813 }
814 
go2_frame_buffer_destroy(go2_frame_buffer_t * frame_buffer)815 void go2_frame_buffer_destroy(go2_frame_buffer_t* frame_buffer)
816 {
817     int ret = drmModeRmFB(frame_buffer->surface->display->fd, frame_buffer->fb_id);
818     if (ret)
819     {
820         printf("drmModeRmFB failed.\n");
821     }
822 
823     free(frame_buffer);
824 }
825 
go2_frame_buffer_surface_get(go2_frame_buffer_t * frame_buffer)826 go2_surface_t* go2_frame_buffer_surface_get(go2_frame_buffer_t* frame_buffer)
827 {
828     return frame_buffer->surface;
829 }
830 
831 
832 
833 
834 
835 #if 0
836 typedef struct go2_presenter
837 {
838     go2_display_t* display;
839     uint32_t format;
840     uint32_t background_color;
841     go2_queue_t* freeFrameBuffers;
842     go2_queue_t* usedFrameBuffers;
843     pthread_mutex_t queueMutex;
844     pthread_t renderThread;
845     sem_t freeSem;
846     sem_t usedSem;
847     volatile bool terminating;
848 } go2_presenter_t;
849 #endif
850 
851 #define BUFFER_COUNT (3)
852 
go2_presenter_renderloop(void * arg)853 static void* go2_presenter_renderloop(void* arg)
854 {
855     go2_presenter_t* presenter = (go2_presenter_t*)arg;
856     go2_frame_buffer_t* prevFrameBuffer = NULL;
857 
858     presenter->terminating = false;
859     while(!presenter->terminating)
860     {
861         sem_wait(&presenter->usedSem);
862         if(presenter->terminating) break;
863 
864 
865         pthread_mutex_lock(&presenter->queueMutex);
866 
867         if (go2_queue_count_get(presenter->usedFrameBuffers) < 1)
868         {
869             printf("no framebuffer available.\n");
870             abort();
871         }
872 
873         go2_frame_buffer_t* dstFrameBuffer = (go2_frame_buffer_t*)go2_queue_pop(presenter->usedFrameBuffers);
874 
875         pthread_mutex_unlock(&presenter->queueMutex);
876 
877 
878         go2_display_present(presenter->display, dstFrameBuffer);
879 
880         if (prevFrameBuffer)
881         {
882             pthread_mutex_lock(&presenter->queueMutex);
883             go2_queue_push(presenter->freeFrameBuffers, prevFrameBuffer);
884             pthread_mutex_unlock(&presenter->queueMutex);
885 
886             sem_post(&presenter->freeSem);
887         }
888 
889         prevFrameBuffer = dstFrameBuffer;
890     }
891 
892 
893     return NULL;
894 }
895 
go2_presenter_display_get(go2_presenter_t * presenter)896 go2_display_t* go2_presenter_display_get(go2_presenter_t* presenter)
897 {
898     return presenter->display;
899 }
900 
go2_presenter_create(go2_display_t * display,uint32_t format,uint32_t background_color,bool managed)901 go2_presenter_t* go2_presenter_create(go2_display_t* display, uint32_t format, uint32_t background_color, bool managed)
902 {
903     go2_presenter_t* result = malloc(sizeof(*result));
904     if (!result)
905     {
906         printf("malloc failed.\n");
907         return NULL;
908     }
909 
910     memset(result, 0, sizeof(*result));
911 
912 
913     result->display = display;
914     result->format = format;
915     result->background_color = background_color;
916     result->managed = managed;
917     if (managed) {
918         result->freeFrameBuffers = go2_queue_create(BUFFER_COUNT);
919         result->usedFrameBuffers = go2_queue_create(BUFFER_COUNT);
920 
921         int width = go2_display_width_get(display);
922         int height = go2_display_height_get(display);
923 
924         for (int i = 0; i < BUFFER_COUNT; ++i)
925         {
926             go2_surface_t* surface = go2_surface_create(display, width, height, format);
927             go2_frame_buffer_t* frameBuffer = go2_frame_buffer_create(surface);
928 
929             go2_queue_push(result->freeFrameBuffers, frameBuffer);
930         }
931 
932         sem_init(&result->usedSem, 0, 0);
933         sem_init(&result->freeSem, 0, BUFFER_COUNT);
934 
935         pthread_mutex_init(&result->queueMutex, NULL);
936 
937         pthread_create(&result->renderThread, NULL, go2_presenter_renderloop, result);
938     }
939     else {
940         result->freeFrameBuffers = go2_queue_create(0);
941         result->usedFrameBuffers = go2_queue_create(0);
942     }
943 
944     return result;
945 }
946 
go2_presenter_destroy(go2_presenter_t * presenter)947 void go2_presenter_destroy(go2_presenter_t* presenter)
948 {
949     if (presenter->managed) {
950         presenter->terminating = true;
951         sem_post(&presenter->usedSem);
952 
953         pthread_join(presenter->renderThread, NULL);
954         pthread_mutex_destroy(&presenter->queueMutex);
955 
956         sem_destroy(&presenter->freeSem);
957         sem_destroy(&presenter->usedSem);
958 
959         while(go2_queue_count_get(presenter->usedFrameBuffers) > 0)
960         {
961             go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->usedFrameBuffers);
962 
963             go2_surface_t* surface = frameBuffer->surface;
964 
965             go2_frame_buffer_destroy(frameBuffer);
966             go2_surface_destroy(surface);
967         }
968 
969         while(go2_queue_count_get(presenter->freeFrameBuffers) > 0)
970         {
971             go2_frame_buffer_t* frameBuffer = go2_queue_pop(presenter->freeFrameBuffers);
972 
973             go2_surface_t* surface = frameBuffer->surface;
974 
975             go2_frame_buffer_destroy(frameBuffer);
976             go2_surface_destroy(surface);
977         }
978     }
979 
980     free(presenter);
981 }
982 
go2_presenter_post(go2_presenter_t * presenter,go2_surface_t * surface,int srcX,int srcY,int srcWidth,int srcHeight,int dstX,int dstY,int dstWidth,int dstHeight,go2_rotation_t rotation,int scale_mode)983 void go2_presenter_post(go2_presenter_t* presenter, go2_surface_t* surface, int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, go2_rotation_t rotation, int scale_mode)
984 {
985     sem_wait(&presenter->freeSem);
986 
987 
988     pthread_mutex_lock(&presenter->queueMutex);
989 
990     if (go2_queue_count_get(presenter->freeFrameBuffers) < 1)
991     {
992         printf("no framebuffer available.\n");
993         abort();
994     }
995 
996     go2_frame_buffer_t* dstFrameBuffer = go2_queue_pop(presenter->freeFrameBuffers);
997 
998     pthread_mutex_unlock(&presenter->queueMutex);
999 
1000 
1001     go2_surface_t* dstSurface = go2_frame_buffer_surface_get(dstFrameBuffer);
1002 
1003     rga_info_t dst = { 0 };
1004     dst.fd = go2_surface_prime_fd(dstSurface);
1005     dst.mmuFlag = 1;
1006     dst.rect.xoffset = 0;
1007     dst.rect.yoffset = 0;
1008     dst.rect.width = go2_surface_width_get(dstSurface);
1009     dst.rect.height = go2_surface_height_get(dstSurface);
1010     dst.rect.wstride = go2_surface_stride_get(dstSurface) / (go2_drm_format_get_bpp(go2_surface_format_get(dstSurface)) / 8);
1011     dst.rect.hstride = go2_surface_height_get(dstSurface);
1012     dst.rect.format = go2_rkformat_get(go2_surface_format_get(dstSurface));
1013     dst.color = presenter->background_color;
1014 
1015     int ret = c_RkRgaColorFill(&dst);
1016     if (ret)
1017     {
1018         printf("c_RkRgaColorFill failed.\n");
1019     }
1020 
1021 
1022     go2_surface_blit(surface, srcX, srcY, srcWidth, srcHeight, dstSurface, dstX, dstY, dstWidth, dstHeight, rotation, scale_mode);
1023 
1024 
1025     pthread_mutex_lock(&presenter->queueMutex);
1026     go2_queue_push(presenter->usedFrameBuffers, dstFrameBuffer);
1027     pthread_mutex_unlock(&presenter->queueMutex);
1028 
1029     sem_post(&presenter->usedSem);
1030 }
1031 
1032 #define BUFFER_MAX (3)
1033 
1034 typedef struct buffer_surface_pair
1035 {
1036     struct gbm_bo* gbmBuffer;
1037     go2_surface_t* surface;
1038 } buffer_surface_pair_t;
1039 
1040 typedef struct go2_context
1041 {
1042     go2_display_t* display;
1043     int width;
1044     int height;
1045     go2_context_attributes_t attributes;
1046     struct gbm_device* gbmDevice;
1047     EGLDisplay eglDisplay;
1048     struct gbm_surface* gbmSurface;
1049     EGLSurface eglSurface;
1050     EGLContext eglContext;
1051     uint32_t drmFourCC;
1052     buffer_surface_pair_t bufferMap[BUFFER_MAX];
1053     int bufferCount;
1054 } go2_context_t;
1055 
1056 
1057 
FindConfig(EGLDisplay eglDisplay,int redBits,int greenBits,int blueBits,int alphaBits,int depthBits,int stencilBits)1058 static EGLConfig FindConfig(EGLDisplay eglDisplay, int redBits, int greenBits, int blueBits, int alphaBits, int depthBits, int stencilBits)
1059 {
1060     EGLint configAttributes[] =
1061     {
1062         EGL_RED_SIZE,            redBits,
1063         EGL_GREEN_SIZE,          greenBits,
1064         EGL_BLUE_SIZE,           blueBits,
1065         EGL_ALPHA_SIZE,          alphaBits,
1066 
1067         EGL_DEPTH_SIZE,          depthBits,
1068         EGL_STENCIL_SIZE,        stencilBits,
1069 
1070         EGL_SURFACE_TYPE,        EGL_WINDOW_BIT,
1071 
1072         EGL_NONE
1073     };
1074 
1075 
1076     int num_configs;
1077     EGLBoolean success = eglChooseConfig(eglDisplay, configAttributes, NULL, 0, &num_configs);
1078     if (success != EGL_TRUE)
1079     {
1080         printf("eglChooseConfig failed.\n");
1081         abort();
1082     }
1083 
1084 
1085     //EGLConfig* configs = new EGLConfig[num_configs];
1086     EGLConfig configs[num_configs];
1087     success = eglChooseConfig(eglDisplay, configAttributes, configs, num_configs, &num_configs);
1088     if (success != EGL_TRUE)
1089     {
1090         printf("eglChooseConfig failed.\n");
1091         abort();
1092     }
1093 
1094 
1095     EGLConfig match = 0;
1096     for (int i = 0; i < num_configs; ++i)
1097     {
1098         EGLint configRedSize;
1099         EGLint configGreenSize;
1100         EGLint configBlueSize;
1101         EGLint configAlphaSize;
1102         EGLint configDepthSize;
1103         EGLint configStencilSize;
1104 
1105         eglGetConfigAttrib(eglDisplay, configs[i], EGL_RED_SIZE, &configRedSize);
1106         eglGetConfigAttrib(eglDisplay, configs[i], EGL_GREEN_SIZE, &configGreenSize);
1107         eglGetConfigAttrib(eglDisplay, configs[i], EGL_BLUE_SIZE, &configBlueSize);
1108         eglGetConfigAttrib(eglDisplay, configs[i], EGL_ALPHA_SIZE, &configAlphaSize);
1109         eglGetConfigAttrib(eglDisplay, configs[i], EGL_DEPTH_SIZE, &configDepthSize);
1110         eglGetConfigAttrib(eglDisplay, configs[i], EGL_STENCIL_SIZE, &configStencilSize);
1111 
1112         //printf("Egl::FindConfig: index=%d, red=%d, green=%d, blue=%d, alpha=%d\n",
1113         //	i, configRedSize, configGreenSize, configBlueSize, configAlphaSize);
1114 
1115         if (configRedSize == redBits &&
1116             configBlueSize == blueBits &&
1117             configGreenSize == greenBits &&
1118             configAlphaSize == alphaBits &&
1119             configDepthSize == depthBits &&
1120             configStencilSize == stencilBits)
1121         {
1122             match = configs[i];
1123             break;
1124         }
1125     }
1126 
1127     return match;
1128 }
1129 
go2_context_create(go2_display_t * display,int width,int height,const go2_context_attributes_t * attributes)1130 go2_context_t* go2_context_create(go2_display_t* display, int width, int height, const go2_context_attributes_t* attributes)
1131 {
1132     EGLBoolean success;
1133 
1134 
1135     go2_context_t* result = malloc(sizeof(*result));
1136     if (!result)
1137     {
1138         printf("malloc failed.\n");
1139         return NULL;
1140     }
1141 
1142     memset(result, 0, sizeof(*result));
1143 
1144 
1145     result->display = display;
1146     result->width = width;
1147     result->height = height;
1148     result->attributes = *attributes;
1149 
1150 
1151     result->gbmDevice = gbm_create_device(display->fd);
1152     if (!result->gbmDevice)
1153     {
1154         printf("gbm_create_device failed.\n");
1155         goto err_00;
1156     }
1157 
1158 
1159     PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
1160     get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC) eglGetProcAddress("eglGetPlatformDisplayEXT");
1161     if(get_platform_display == NULL)
1162     {
1163         printf("eglGetProcAddress failed.\n");
1164         goto err_01;
1165     }
1166 
1167     result->eglDisplay = get_platform_display(EGL_PLATFORM_GBM_KHR, result->gbmDevice, NULL);
1168     if (result->eglDisplay == EGL_NO_DISPLAY)
1169     {
1170         printf("eglGetPlatformDisplayEXT failed.\n");
1171         goto err_01;
1172     }
1173 
1174 
1175     // Initialize EGL
1176     EGLint major;
1177     EGLint minor;
1178     success = eglInitialize(result->eglDisplay, &major, &minor);
1179     if (success != EGL_TRUE)
1180     {
1181         printf("eglInitialize failed.\n");
1182         goto err_01;
1183     }
1184 
1185     printf("EGL: major=%d, minor=%d\n", major, minor);
1186     printf("EGL: Vendor=%s\n", eglQueryString(result->eglDisplay, EGL_VENDOR));
1187     printf("EGL: Version=%s\n", eglQueryString(result->eglDisplay, EGL_VERSION));
1188     printf("EGL: ClientAPIs=%s\n", eglQueryString(result->eglDisplay, EGL_CLIENT_APIS));
1189     printf("EGL: Extensions=%s\n", eglQueryString(result->eglDisplay, EGL_EXTENSIONS));
1190     printf("EGL: ClientExtensions=%s\n", eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS));
1191     printf("\n");
1192 
1193 
1194     EGLConfig eglConfig = FindConfig(result->eglDisplay, attributes->red_bits, attributes->green_bits,
1195         attributes->blue_bits, attributes->alpha_bits, attributes->depth_bits, attributes->stencil_bits);
1196 
1197 
1198     // Get the native visual id associated with the config
1199     //int visual_id;
1200     eglGetConfigAttrib(result->eglDisplay, eglConfig, EGL_NATIVE_VISUAL_ID, (EGLint*)&result->drmFourCC);
1201 
1202     result->gbmSurface = gbm_surface_create(result->gbmDevice,
1203         width,
1204         height,
1205         result->drmFourCC,
1206         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
1207     if (!result->gbmSurface)
1208     {
1209         printf("gbm_surface_create failed.\n");
1210         abort();
1211     }
1212 
1213 
1214     result->eglSurface = eglCreateWindowSurface(result->eglDisplay, eglConfig, (EGLNativeWindowType)result->gbmSurface, NULL);
1215     if (result->eglSurface == EGL_NO_SURFACE)
1216     {
1217         printf("eglCreateWindowSurface failed\n");
1218         abort();
1219     }
1220 
1221 
1222     // Create a context
1223     eglBindAPI(EGL_OPENGL_ES_API);
1224 
1225     EGLint contextAttributes[] = {
1226         EGL_CONTEXT_CLIENT_VERSION, attributes->major,
1227         EGL_NONE };
1228 
1229     result->eglContext = eglCreateContext(result->eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttributes);
1230     if (result->eglContext == EGL_NO_CONTEXT)
1231     {
1232         printf("eglCreateContext failed\n");
1233         abort();
1234     }
1235 
1236     success = eglMakeCurrent(result->eglDisplay, result->eglSurface, result->eglSurface, result->eglContext);
1237     if (success != EGL_TRUE)
1238     {
1239         printf("eglMakeCurrent failed\n");
1240         abort();
1241     }
1242 
1243 
1244     return result;
1245 
1246 
1247 err_01:
1248     gbm_device_destroy(result->gbmDevice);
1249 
1250 err_00:
1251     free(result);
1252     return NULL;
1253 }
1254 
go2_context_destroy(go2_context_t * context)1255 void go2_context_destroy(go2_context_t* context)
1256 {
1257     eglDestroyContext(context->eglDisplay, context->eglContext);
1258     eglDestroySurface(context->eglDisplay, context->eglSurface);
1259     gbm_surface_destroy(context->gbmSurface);
1260     eglTerminate(context->eglDisplay);
1261     gbm_device_destroy(context->gbmDevice);
1262 
1263     for(int i = 0; i < context->bufferCount; ++i)
1264     {
1265         free(context->bufferMap[i].surface);
1266     }
1267 
1268     free(context);
1269 }
1270 
go2_context_egldisplay_get(go2_context_t * context)1271 void* go2_context_egldisplay_get(go2_context_t* context)
1272 {
1273     return context->eglDisplay;
1274 }
1275 
go2_context_make_current(go2_context_t * context)1276 void go2_context_make_current(go2_context_t* context)
1277 {
1278     EGLBoolean success = eglMakeCurrent(context->eglDisplay, context->eglSurface, context->eglSurface, context->eglContext);
1279     if (success != EGL_TRUE)
1280     {
1281         printf("eglMakeCurrent failed\n");
1282         abort();
1283     }
1284 }
1285 
go2_context_swap_buffers(go2_context_t * context)1286 void go2_context_swap_buffers(go2_context_t* context)
1287 {
1288     EGLBoolean ret = eglSwapBuffers(context->eglDisplay, context->eglSurface);
1289     if (ret == EGL_FALSE)
1290     {
1291         printf("eglSwapBuffers failed\n");
1292         //abort();
1293     }
1294 }
1295 
go2_context_surface_lock(go2_context_t * context)1296 go2_surface_t* go2_context_surface_lock(go2_context_t* context)
1297 {
1298     struct gbm_bo *bo = gbm_surface_lock_front_buffer(context->gbmSurface);
1299     if (!bo)
1300     {
1301         printf("gbm_surface_lock_front_buffer failed.\n");
1302         abort();
1303     }
1304 
1305     go2_surface_t* surface = NULL;
1306     for (int i = 0; i < context->bufferCount; ++i)
1307     {
1308         buffer_surface_pair_t* pair = &context->bufferMap[i];
1309         if (pair->gbmBuffer == bo)
1310         {
1311             surface = pair->surface;
1312             break;
1313         }
1314     }
1315 
1316     if (!surface)
1317     {
1318         if (context->bufferCount >= BUFFER_MAX)
1319         {
1320             printf("swap buffers count exceeded.\n");
1321             abort();
1322         }
1323 
1324         surface = malloc(sizeof(*surface));
1325         if (!surface)
1326         {
1327             printf("malloc failed.\n");
1328             abort();
1329         }
1330 
1331         memset(surface, 0, sizeof(*surface));
1332 
1333 
1334         surface->display = context->display;
1335         surface->gem_handle = gbm_bo_get_handle(bo).u32;
1336         surface->size = gbm_bo_get_stride(bo);
1337         surface->width = gbm_bo_get_width(bo);
1338         surface->height = gbm_bo_get_height(bo);
1339         surface->stride = gbm_bo_get_stride(bo);
1340         surface->format = context->drmFourCC;
1341 
1342 
1343         buffer_surface_pair_t* pair = &context->bufferMap[context->bufferCount++];
1344         pair->gbmBuffer = bo;
1345         pair->surface = surface;
1346 
1347         //printf("added buffer - bo=%p, count=%d\n", bo, context->bufferCount);
1348     }
1349 
1350     return surface;
1351 }
1352 
go2_context_surface_unlock(go2_context_t * context,go2_surface_t * surface)1353 void go2_context_surface_unlock(go2_context_t* context, go2_surface_t* surface)
1354 {
1355     struct gbm_bo* bo = NULL;
1356     for (int i = 0; i < context->bufferCount; ++i)
1357     {
1358         buffer_surface_pair_t* pair = &context->bufferMap[i];
1359         if (pair->surface == surface)
1360         {
1361             bo = pair->gbmBuffer;
1362             break;
1363         }
1364     }
1365 
1366     if (!bo)
1367     {
1368         abort();
1369     }
1370 
1371     gbm_surface_release_buffer(context->gbmSurface, bo);
1372 }
1373