1 #include <drm_fourcc.h>
2 #include <stdexcept>
4 #include "dumbframebuffer.h"
5 #include "color.h"
6 #include "conv.h"
8 namespace kms
9 {
10 static RGB read_rgb(const DumbFramebuffer& fb, int x, int y)
11 {
12 uint32_t *pc = (uint32_t *)(fb.map(0) + fb.stride(0) * y);
14 uint32_t c = pc[x];
16 return RGB((c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
17 }
19 static YUV read_rgb_as_yuv(const DumbFramebuffer& fb, int x, int y)
20 {
21 RGB rgb = read_rgb(fb, x, y);
22 return YUV(rgb);
23 }
25 static void fb_rgb_to_packed_yuv(DumbFramebuffer& dst_fb, const DumbFramebuffer& src_fb)
26 {
27 unsigned w = src_fb.width();
28 unsigned h = src_fb.height();
30 uint8_t *dst = dst_fb.map(0);
32 for (unsigned y = 0; y < h; ++y) {
33 for (unsigned x = 0; x < w; x += 2) {
34 YUV yuv1 = read_rgb_as_yuv(src_fb, x + 0, y);
35 YUV yuv2 = read_rgb_as_yuv(src_fb, x + 1, y);
37 switch (dst_fb.format()) {
38 case DRM_FORMAT_UYVY:
39 dst[x * 2 + 0] = (yuv1.u + yuv2.u) / 2;
40 dst[x * 2 + 1] = yuv1.y;
41 dst[x * 2 + 2] = (yuv1.v + yuv2.v) / 2;
42 dst[x * 2 + 3] = yuv2.y;
43 break;
44 case DRM_FORMAT_YUYV:
45 dst[x * 2 + 0] = yuv1.y;
46 dst[x * 2 + 1] = (yuv1.u + yuv2.u) / 2;
47 dst[x * 2 + 2] = yuv2.y;
48 dst[x * 2 + 3] = (yuv1.v + yuv2.v) / 2;
49 break;
51 default:
52 throw std::invalid_argument("fo");
53 }
54 }
56 dst += dst_fb.stride(0);
57 }
58 }
60 static void fb_rgb_to_semiplanar_yuv(DumbFramebuffer& dst_fb, const DumbFramebuffer& src_fb)
61 {
62 unsigned w = src_fb.width();
63 unsigned h = src_fb.height();
65 uint8_t *dst_y = dst_fb.map(0);
66 uint8_t *dst_uv = dst_fb.map(1);
68 for (unsigned y = 0; y < h; ++y) {
69 for (unsigned x = 0; x < w; ++x) {
70 YUV yuv = read_rgb_as_yuv(src_fb, x, y);
71 dst_y[x] = yuv.y;
72 }
74 dst_y += dst_fb.stride(0);
75 }
77 for (unsigned y = 0; y < h; y += 2) {
78 for (unsigned x = 0; x < w; x += 2) {
79 YUV yuv00 = read_rgb_as_yuv(src_fb, x + 0, y + 0);
80 YUV yuv01 = read_rgb_as_yuv(src_fb, x + 1, y + 0);
81 YUV yuv10 = read_rgb_as_yuv(src_fb, x + 0, y + 1);
82 YUV yuv11 = read_rgb_as_yuv(src_fb, x + 1, y + 1);
84 unsigned u = (yuv00.u + yuv01.u + yuv10.u + yuv11.u) / 4;
85 unsigned v = (yuv00.v + yuv01.v + yuv10.v + yuv11.v) / 4;
87 dst_uv[x + 0] = u;
88 dst_uv[x + 1] = v;
89 }
91 dst_uv += dst_fb.stride(1);
92 }
93 }
95 static void fb_rgb_to_rgb565(DumbFramebuffer& dst_fb, const DumbFramebuffer& src_fb)
96 {
97 unsigned w = src_fb.width();
98 unsigned h = src_fb.height();
100 uint8_t *dst = dst_fb.map(0);
102 for (unsigned y = 0; y < h; ++y) {
103 for (unsigned x = 0; x < w; ++x) {
104 RGB rgb = read_rgb(src_fb, x, y);
106 unsigned r = rgb.r * 32 / 256;
107 unsigned g = rgb.g * 64 / 256;
108 unsigned b = rgb.b * 32 / 256;
110 ((uint16_t *)dst)[x] = (r << 11) | (g << 5) | (b << 0);
111 }
113 dst += dst_fb.stride(0);
114 }
115 }
117 void color_convert(DumbFramebuffer& dst, const DumbFramebuffer &src)
118 {
119 switch (dst.format()) {
120 case DRM_FORMAT_NV12:
121 case DRM_FORMAT_NV21:
122 fb_rgb_to_semiplanar_yuv(dst, src);
123 break;
125 case DRM_FORMAT_YUYV:
126 case DRM_FORMAT_UYVY:
127 fb_rgb_to_packed_yuv(dst, src);
128 break;
130 case DRM_FORMAT_RGB565:
131 fb_rgb_to_rgb565(dst, src);
132 break;
134 default:
135 throw std::invalid_argument("fo");
136 }
137 }
138 }