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