xref: /aosp_15_r20/external/libkmsxx/kms++util/src/drawing.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1*f0687c8aSRaman Tenneti 
2*f0687c8aSRaman Tenneti #include <cmath>
3*f0687c8aSRaman Tenneti 
4*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
5*f0687c8aSRaman Tenneti #include <kms++util/kms++util.h>
6*f0687c8aSRaman Tenneti 
7*f0687c8aSRaman Tenneti using namespace std;
8*f0687c8aSRaman Tenneti 
9*f0687c8aSRaman Tenneti namespace kms
10*f0687c8aSRaman Tenneti {
draw_rgb_pixel(IFramebuffer & buf,unsigned x,unsigned y,RGB color)11*f0687c8aSRaman Tenneti void draw_rgb_pixel(IFramebuffer& buf, unsigned x, unsigned y, RGB color)
12*f0687c8aSRaman Tenneti {
13*f0687c8aSRaman Tenneti 	if (x >= buf.width() || y >= buf.height())
14*f0687c8aSRaman Tenneti 		throw runtime_error("attempt to draw outside the buffer");
15*f0687c8aSRaman Tenneti 
16*f0687c8aSRaman Tenneti 	switch (buf.format()) {
17*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB8888:
18*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB8888: {
19*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
20*f0687c8aSRaman Tenneti 		*p = color.argb8888();
21*f0687c8aSRaman Tenneti 		break;
22*f0687c8aSRaman Tenneti 	}
23*f0687c8aSRaman Tenneti 	case PixelFormat::XBGR8888:
24*f0687c8aSRaman Tenneti 	case PixelFormat::ABGR8888: {
25*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
26*f0687c8aSRaman Tenneti 		*p = color.abgr8888();
27*f0687c8aSRaman Tenneti 		break;
28*f0687c8aSRaman Tenneti 	}
29*f0687c8aSRaman Tenneti 	case PixelFormat::RGBX8888:
30*f0687c8aSRaman Tenneti 	case PixelFormat::RGBA8888: {
31*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
32*f0687c8aSRaman Tenneti 		*p = color.rgba8888();
33*f0687c8aSRaman Tenneti 		break;
34*f0687c8aSRaman Tenneti 	}
35*f0687c8aSRaman Tenneti 	case PixelFormat::BGRX8888:
36*f0687c8aSRaman Tenneti 	case PixelFormat::BGRA8888: {
37*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
38*f0687c8aSRaman Tenneti 		*p = color.bgra8888();
39*f0687c8aSRaman Tenneti 		break;
40*f0687c8aSRaman Tenneti 	}
41*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB2101010:
42*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB2101010: {
43*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
44*f0687c8aSRaman Tenneti 		*p = color.argb2101010();
45*f0687c8aSRaman Tenneti 		break;
46*f0687c8aSRaman Tenneti 	}
47*f0687c8aSRaman Tenneti 	case PixelFormat::XBGR2101010:
48*f0687c8aSRaman Tenneti 	case PixelFormat::ABGR2101010: {
49*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
50*f0687c8aSRaman Tenneti 		*p = color.abgr2101010();
51*f0687c8aSRaman Tenneti 		break;
52*f0687c8aSRaman Tenneti 	}
53*f0687c8aSRaman Tenneti 	case PixelFormat::RGBX1010102:
54*f0687c8aSRaman Tenneti 	case PixelFormat::RGBA1010102: {
55*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
56*f0687c8aSRaman Tenneti 		*p = color.rgba1010102();
57*f0687c8aSRaman Tenneti 		break;
58*f0687c8aSRaman Tenneti 	}
59*f0687c8aSRaman Tenneti 	case PixelFormat::BGRX1010102:
60*f0687c8aSRaman Tenneti 	case PixelFormat::BGRA1010102: {
61*f0687c8aSRaman Tenneti 		uint32_t* p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
62*f0687c8aSRaman Tenneti 		*p = color.bgra1010102();
63*f0687c8aSRaman Tenneti 		break;
64*f0687c8aSRaman Tenneti 	}
65*f0687c8aSRaman Tenneti 	case PixelFormat::RGB888: {
66*f0687c8aSRaman Tenneti 		uint8_t* p = buf.map(0) + buf.stride(0) * y + x * 3;
67*f0687c8aSRaman Tenneti 		p[0] = color.b;
68*f0687c8aSRaman Tenneti 		p[1] = color.g;
69*f0687c8aSRaman Tenneti 		p[2] = color.r;
70*f0687c8aSRaman Tenneti 		break;
71*f0687c8aSRaman Tenneti 	}
72*f0687c8aSRaman Tenneti 	case PixelFormat::BGR888: {
73*f0687c8aSRaman Tenneti 		uint8_t* p = buf.map(0) + buf.stride(0) * y + x * 3;
74*f0687c8aSRaman Tenneti 		p[0] = color.r;
75*f0687c8aSRaman Tenneti 		p[1] = color.g;
76*f0687c8aSRaman Tenneti 		p[2] = color.b;
77*f0687c8aSRaman Tenneti 		break;
78*f0687c8aSRaman Tenneti 	}
79*f0687c8aSRaman Tenneti 	case PixelFormat::RGB332: {
80*f0687c8aSRaman Tenneti 		uint8_t* p = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x);
81*f0687c8aSRaman Tenneti 		*p = color.rgb332();
82*f0687c8aSRaman Tenneti 		break;
83*f0687c8aSRaman Tenneti 	}
84*f0687c8aSRaman Tenneti 	case PixelFormat::RGB565: {
85*f0687c8aSRaman Tenneti 		uint16_t* p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
86*f0687c8aSRaman Tenneti 		*p = color.rgb565();
87*f0687c8aSRaman Tenneti 		break;
88*f0687c8aSRaman Tenneti 	}
89*f0687c8aSRaman Tenneti 	case PixelFormat::BGR565: {
90*f0687c8aSRaman Tenneti 		uint16_t* p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
91*f0687c8aSRaman Tenneti 		*p = color.bgr565();
92*f0687c8aSRaman Tenneti 		break;
93*f0687c8aSRaman Tenneti 	}
94*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB4444:
95*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB4444: {
96*f0687c8aSRaman Tenneti 		uint16_t* p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
97*f0687c8aSRaman Tenneti 		*p = color.argb4444();
98*f0687c8aSRaman Tenneti 		break;
99*f0687c8aSRaman Tenneti 	}
100*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB1555:
101*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB1555: {
102*f0687c8aSRaman Tenneti 		uint16_t* p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
103*f0687c8aSRaman Tenneti 		*p = color.argb1555();
104*f0687c8aSRaman Tenneti 		break;
105*f0687c8aSRaman Tenneti 	}
106*f0687c8aSRaman Tenneti 	default:
107*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
108*f0687c8aSRaman Tenneti 	}
109*f0687c8aSRaman Tenneti }
110*f0687c8aSRaman Tenneti 
draw_yuv444_pixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv)111*f0687c8aSRaman Tenneti void draw_yuv444_pixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv)
112*f0687c8aSRaman Tenneti {
113*f0687c8aSRaman Tenneti 	if (x >= buf.width() || y >= buf.height())
114*f0687c8aSRaman Tenneti 		throw runtime_error("attempt to draw outside the buffer");
115*f0687c8aSRaman Tenneti 
116*f0687c8aSRaman Tenneti 	uint8_t* py = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x);
117*f0687c8aSRaman Tenneti 	uint8_t* pu = (uint8_t*)(buf.map(1) + buf.stride(1) * y + x);
118*f0687c8aSRaman Tenneti 	uint8_t* pv = (uint8_t*)(buf.map(2) + buf.stride(2) * y + x);
119*f0687c8aSRaman Tenneti 
120*f0687c8aSRaman Tenneti 	switch (buf.format()) {
121*f0687c8aSRaman Tenneti 	case PixelFormat::YUV444:
122*f0687c8aSRaman Tenneti 		py[0] = yuv.y;
123*f0687c8aSRaman Tenneti 		pu[0] = yuv.u;
124*f0687c8aSRaman Tenneti 		pv[0] = yuv.v;
125*f0687c8aSRaman Tenneti 		break;
126*f0687c8aSRaman Tenneti 
127*f0687c8aSRaman Tenneti 	case PixelFormat::YVU444:
128*f0687c8aSRaman Tenneti 		py[0] = yuv.y;
129*f0687c8aSRaman Tenneti 		pu[0] = yuv.v;
130*f0687c8aSRaman Tenneti 		pv[0] = yuv.u;
131*f0687c8aSRaman Tenneti 		break;
132*f0687c8aSRaman Tenneti 
133*f0687c8aSRaman Tenneti 	default:
134*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
135*f0687c8aSRaman Tenneti 	}
136*f0687c8aSRaman Tenneti }
137*f0687c8aSRaman Tenneti 
draw_yuv422_packed_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2)138*f0687c8aSRaman Tenneti static void draw_yuv422_packed_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
139*f0687c8aSRaman Tenneti 					  YUV yuv1, YUV yuv2)
140*f0687c8aSRaman Tenneti {
141*f0687c8aSRaman Tenneti 	uint8_t* p = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
142*f0687c8aSRaman Tenneti 
143*f0687c8aSRaman Tenneti 	uint8_t y0 = yuv1.y;
144*f0687c8aSRaman Tenneti 	uint8_t y1 = yuv2.y;
145*f0687c8aSRaman Tenneti 	uint8_t u = (yuv1.u + yuv2.u) / 2;
146*f0687c8aSRaman Tenneti 	uint8_t v = (yuv1.v + yuv2.v) / 2;
147*f0687c8aSRaman Tenneti 
148*f0687c8aSRaman Tenneti 	switch (buf.format()) {
149*f0687c8aSRaman Tenneti 	case PixelFormat::UYVY:
150*f0687c8aSRaman Tenneti 		p[0] = u;
151*f0687c8aSRaman Tenneti 		p[1] = y0;
152*f0687c8aSRaman Tenneti 		p[2] = v;
153*f0687c8aSRaman Tenneti 		p[3] = y1;
154*f0687c8aSRaman Tenneti 		break;
155*f0687c8aSRaman Tenneti 
156*f0687c8aSRaman Tenneti 	case PixelFormat::YUYV:
157*f0687c8aSRaman Tenneti 		p[0] = y0;
158*f0687c8aSRaman Tenneti 		p[1] = u;
159*f0687c8aSRaman Tenneti 		p[2] = y1;
160*f0687c8aSRaman Tenneti 		p[3] = v;
161*f0687c8aSRaman Tenneti 		break;
162*f0687c8aSRaman Tenneti 
163*f0687c8aSRaman Tenneti 	case PixelFormat::YVYU:
164*f0687c8aSRaman Tenneti 		p[0] = y0;
165*f0687c8aSRaman Tenneti 		p[1] = v;
166*f0687c8aSRaman Tenneti 		p[2] = y1;
167*f0687c8aSRaman Tenneti 		p[3] = u;
168*f0687c8aSRaman Tenneti 		break;
169*f0687c8aSRaman Tenneti 
170*f0687c8aSRaman Tenneti 	case PixelFormat::VYUY:
171*f0687c8aSRaman Tenneti 		p[0] = v;
172*f0687c8aSRaman Tenneti 		p[1] = y0;
173*f0687c8aSRaman Tenneti 		p[2] = u;
174*f0687c8aSRaman Tenneti 		p[3] = y1;
175*f0687c8aSRaman Tenneti 		break;
176*f0687c8aSRaman Tenneti 
177*f0687c8aSRaman Tenneti 	default:
178*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
179*f0687c8aSRaman Tenneti 	}
180*f0687c8aSRaman Tenneti }
181*f0687c8aSRaman Tenneti 
draw_yuv422_semiplanar_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2)182*f0687c8aSRaman Tenneti static void draw_yuv422_semiplanar_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
183*f0687c8aSRaman Tenneti 					      YUV yuv1, YUV yuv2)
184*f0687c8aSRaman Tenneti {
185*f0687c8aSRaman Tenneti 	uint8_t* py = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x);
186*f0687c8aSRaman Tenneti 	uint8_t* puv = (uint8_t*)(buf.map(1) + buf.stride(1) * y + x);
187*f0687c8aSRaman Tenneti 
188*f0687c8aSRaman Tenneti 	uint8_t y0 = yuv1.y;
189*f0687c8aSRaman Tenneti 	uint8_t y1 = yuv2.y;
190*f0687c8aSRaman Tenneti 	uint8_t u = (yuv1.u + yuv2.u) / 2;
191*f0687c8aSRaman Tenneti 	uint8_t v = (yuv1.v + yuv2.v) / 2;
192*f0687c8aSRaman Tenneti 
193*f0687c8aSRaman Tenneti 	switch (buf.format()) {
194*f0687c8aSRaman Tenneti 	case PixelFormat::NV16:
195*f0687c8aSRaman Tenneti 		py[0] = y0;
196*f0687c8aSRaman Tenneti 		py[1] = y1;
197*f0687c8aSRaman Tenneti 		puv[0] = u;
198*f0687c8aSRaman Tenneti 		puv[1] = v;
199*f0687c8aSRaman Tenneti 		break;
200*f0687c8aSRaman Tenneti 
201*f0687c8aSRaman Tenneti 	case PixelFormat::NV61:
202*f0687c8aSRaman Tenneti 		py[0] = y0;
203*f0687c8aSRaman Tenneti 		py[1] = y1;
204*f0687c8aSRaman Tenneti 		puv[0] = v;
205*f0687c8aSRaman Tenneti 		puv[1] = u;
206*f0687c8aSRaman Tenneti 		break;
207*f0687c8aSRaman Tenneti 
208*f0687c8aSRaman Tenneti 	default:
209*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
210*f0687c8aSRaman Tenneti 	}
211*f0687c8aSRaman Tenneti }
212*f0687c8aSRaman Tenneti 
draw_yuv422_planar_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2)213*f0687c8aSRaman Tenneti static void draw_yuv422_planar_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
214*f0687c8aSRaman Tenneti 					  YUV yuv1, YUV yuv2)
215*f0687c8aSRaman Tenneti {
216*f0687c8aSRaman Tenneti 	uint8_t* py = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x);
217*f0687c8aSRaman Tenneti 	uint8_t* pu = (uint8_t*)(buf.map(1) + buf.stride(1) * y + x / 2);
218*f0687c8aSRaman Tenneti 	uint8_t* pv = (uint8_t*)(buf.map(2) + buf.stride(2) * y + x / 2);
219*f0687c8aSRaman Tenneti 
220*f0687c8aSRaman Tenneti 	uint8_t y0 = yuv1.y;
221*f0687c8aSRaman Tenneti 	uint8_t y1 = yuv2.y;
222*f0687c8aSRaman Tenneti 	uint8_t u = (yuv1.u + yuv2.u) / 2;
223*f0687c8aSRaman Tenneti 	uint8_t v = (yuv1.v + yuv2.v) / 2;
224*f0687c8aSRaman Tenneti 
225*f0687c8aSRaman Tenneti 	switch (buf.format()) {
226*f0687c8aSRaman Tenneti 	case PixelFormat::YUV422:
227*f0687c8aSRaman Tenneti 		py[0] = y0;
228*f0687c8aSRaman Tenneti 		py[1] = y1;
229*f0687c8aSRaman Tenneti 		pu[0] = u;
230*f0687c8aSRaman Tenneti 		pv[0] = v;
231*f0687c8aSRaman Tenneti 		break;
232*f0687c8aSRaman Tenneti 
233*f0687c8aSRaman Tenneti 	case PixelFormat::YVU422:
234*f0687c8aSRaman Tenneti 		py[0] = y0;
235*f0687c8aSRaman Tenneti 		py[1] = y1;
236*f0687c8aSRaman Tenneti 		pu[0] = v;
237*f0687c8aSRaman Tenneti 		pv[0] = u;
238*f0687c8aSRaman Tenneti 		break;
239*f0687c8aSRaman Tenneti 
240*f0687c8aSRaman Tenneti 	default:
241*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
242*f0687c8aSRaman Tenneti 	}
243*f0687c8aSRaman Tenneti }
244*f0687c8aSRaman Tenneti 
draw_yuv422_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2)245*f0687c8aSRaman Tenneti void draw_yuv422_macropixel(IFramebuffer& buf, unsigned x, unsigned y, YUV yuv1, YUV yuv2)
246*f0687c8aSRaman Tenneti {
247*f0687c8aSRaman Tenneti 	if ((x + 1) >= buf.width() || y >= buf.height())
248*f0687c8aSRaman Tenneti 		throw runtime_error("attempt to draw outside the buffer");
249*f0687c8aSRaman Tenneti 
250*f0687c8aSRaman Tenneti 	ASSERT((x & 1) == 0);
251*f0687c8aSRaman Tenneti 
252*f0687c8aSRaman Tenneti 	switch (buf.format()) {
253*f0687c8aSRaman Tenneti 	case PixelFormat::UYVY:
254*f0687c8aSRaman Tenneti 	case PixelFormat::YUYV:
255*f0687c8aSRaman Tenneti 	case PixelFormat::YVYU:
256*f0687c8aSRaman Tenneti 	case PixelFormat::VYUY:
257*f0687c8aSRaman Tenneti 		draw_yuv422_packed_macropixel(buf, x, y, yuv1, yuv2);
258*f0687c8aSRaman Tenneti 		break;
259*f0687c8aSRaman Tenneti 
260*f0687c8aSRaman Tenneti 	case PixelFormat::NV16:
261*f0687c8aSRaman Tenneti 	case PixelFormat::NV61:
262*f0687c8aSRaman Tenneti 		draw_yuv422_semiplanar_macropixel(buf, x, y, yuv1, yuv2);
263*f0687c8aSRaman Tenneti 		break;
264*f0687c8aSRaman Tenneti 
265*f0687c8aSRaman Tenneti 	case PixelFormat::YUV422:
266*f0687c8aSRaman Tenneti 	case PixelFormat::YVU422:
267*f0687c8aSRaman Tenneti 		draw_yuv422_planar_macropixel(buf, x, y, yuv1, yuv2);
268*f0687c8aSRaman Tenneti 		break;
269*f0687c8aSRaman Tenneti 
270*f0687c8aSRaman Tenneti 	default:
271*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
272*f0687c8aSRaman Tenneti 	}
273*f0687c8aSRaman Tenneti }
274*f0687c8aSRaman Tenneti 
draw_yuv420_semiplanar_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2,YUV yuv3,YUV yuv4)275*f0687c8aSRaman Tenneti static void draw_yuv420_semiplanar_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
276*f0687c8aSRaman Tenneti 					      YUV yuv1, YUV yuv2, YUV yuv3, YUV yuv4)
277*f0687c8aSRaman Tenneti {
278*f0687c8aSRaman Tenneti 	uint8_t* py1 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 0) + x);
279*f0687c8aSRaman Tenneti 	uint8_t* py2 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 1) + x);
280*f0687c8aSRaman Tenneti 
281*f0687c8aSRaman Tenneti 	uint8_t* puv = (uint8_t*)(buf.map(1) + buf.stride(1) * (y / 2) + x);
282*f0687c8aSRaman Tenneti 
283*f0687c8aSRaman Tenneti 	uint8_t y0 = yuv1.y;
284*f0687c8aSRaman Tenneti 	uint8_t y1 = yuv2.y;
285*f0687c8aSRaman Tenneti 	uint8_t y2 = yuv3.y;
286*f0687c8aSRaman Tenneti 	uint8_t y3 = yuv4.y;
287*f0687c8aSRaman Tenneti 	uint8_t u = (yuv1.u + yuv2.u + yuv3.u + yuv4.u) / 4;
288*f0687c8aSRaman Tenneti 	uint8_t v = (yuv1.v + yuv2.v + yuv3.v + yuv4.v) / 4;
289*f0687c8aSRaman Tenneti 
290*f0687c8aSRaman Tenneti 	switch (buf.format()) {
291*f0687c8aSRaman Tenneti 	case PixelFormat::NV12:
292*f0687c8aSRaman Tenneti 		py1[0] = y0;
293*f0687c8aSRaman Tenneti 		py1[1] = y1;
294*f0687c8aSRaman Tenneti 		py2[0] = y2;
295*f0687c8aSRaman Tenneti 		py2[1] = y3;
296*f0687c8aSRaman Tenneti 		puv[0] = u;
297*f0687c8aSRaman Tenneti 		puv[1] = v;
298*f0687c8aSRaman Tenneti 		break;
299*f0687c8aSRaman Tenneti 
300*f0687c8aSRaman Tenneti 	case PixelFormat::NV21:
301*f0687c8aSRaman Tenneti 		py1[0] = y0;
302*f0687c8aSRaman Tenneti 		py1[1] = y1;
303*f0687c8aSRaman Tenneti 		py2[0] = y2;
304*f0687c8aSRaman Tenneti 		py2[1] = y3;
305*f0687c8aSRaman Tenneti 		puv[0] = v;
306*f0687c8aSRaman Tenneti 		puv[1] = u;
307*f0687c8aSRaman Tenneti 		break;
308*f0687c8aSRaman Tenneti 
309*f0687c8aSRaman Tenneti 	default:
310*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
311*f0687c8aSRaman Tenneti 	}
312*f0687c8aSRaman Tenneti }
313*f0687c8aSRaman Tenneti 
draw_yuv420_planar_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2,YUV yuv3,YUV yuv4)314*f0687c8aSRaman Tenneti static void draw_yuv420_planar_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
315*f0687c8aSRaman Tenneti 					  YUV yuv1, YUV yuv2, YUV yuv3, YUV yuv4)
316*f0687c8aSRaman Tenneti {
317*f0687c8aSRaman Tenneti 	uint8_t* py1 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 0) + x);
318*f0687c8aSRaman Tenneti 	uint8_t* py2 = (uint8_t*)(buf.map(0) + buf.stride(0) * (y + 1) + x);
319*f0687c8aSRaman Tenneti 
320*f0687c8aSRaman Tenneti 	uint8_t* pu = (uint8_t*)(buf.map(1) + buf.stride(1) * (y / 2) + x / 2);
321*f0687c8aSRaman Tenneti 	uint8_t* pv = (uint8_t*)(buf.map(2) + buf.stride(2) * (y / 2) + x / 2);
322*f0687c8aSRaman Tenneti 
323*f0687c8aSRaman Tenneti 	uint8_t y0 = yuv1.y;
324*f0687c8aSRaman Tenneti 	uint8_t y1 = yuv2.y;
325*f0687c8aSRaman Tenneti 	uint8_t y2 = yuv3.y;
326*f0687c8aSRaman Tenneti 	uint8_t y3 = yuv4.y;
327*f0687c8aSRaman Tenneti 	uint8_t u = (yuv1.u + yuv2.u + yuv3.u + yuv4.u) / 4;
328*f0687c8aSRaman Tenneti 	uint8_t v = (yuv1.v + yuv2.v + yuv3.v + yuv4.v) / 4;
329*f0687c8aSRaman Tenneti 
330*f0687c8aSRaman Tenneti 	switch (buf.format()) {
331*f0687c8aSRaman Tenneti 	case PixelFormat::YUV420:
332*f0687c8aSRaman Tenneti 		py1[0] = y0;
333*f0687c8aSRaman Tenneti 		py1[1] = y1;
334*f0687c8aSRaman Tenneti 		py2[0] = y2;
335*f0687c8aSRaman Tenneti 		py2[1] = y3;
336*f0687c8aSRaman Tenneti 		pu[0] = u;
337*f0687c8aSRaman Tenneti 		pv[0] = v;
338*f0687c8aSRaman Tenneti 		break;
339*f0687c8aSRaman Tenneti 
340*f0687c8aSRaman Tenneti 	case PixelFormat::YVU420:
341*f0687c8aSRaman Tenneti 		py1[0] = y0;
342*f0687c8aSRaman Tenneti 		py1[1] = y1;
343*f0687c8aSRaman Tenneti 		py2[0] = y2;
344*f0687c8aSRaman Tenneti 		py2[1] = y3;
345*f0687c8aSRaman Tenneti 		pu[0] = v;
346*f0687c8aSRaman Tenneti 		pv[0] = u;
347*f0687c8aSRaman Tenneti 		break;
348*f0687c8aSRaman Tenneti 
349*f0687c8aSRaman Tenneti 	default:
350*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
351*f0687c8aSRaman Tenneti 	}
352*f0687c8aSRaman Tenneti }
353*f0687c8aSRaman Tenneti 
draw_yuv420_macropixel(IFramebuffer & buf,unsigned x,unsigned y,YUV yuv1,YUV yuv2,YUV yuv3,YUV yuv4)354*f0687c8aSRaman Tenneti void draw_yuv420_macropixel(IFramebuffer& buf, unsigned x, unsigned y,
355*f0687c8aSRaman Tenneti 			    YUV yuv1, YUV yuv2, YUV yuv3, YUV yuv4)
356*f0687c8aSRaman Tenneti {
357*f0687c8aSRaman Tenneti 	if ((x + 1) >= buf.width() || (y + 1) >= buf.height())
358*f0687c8aSRaman Tenneti 		throw runtime_error("attempt to draw outside the buffer");
359*f0687c8aSRaman Tenneti 
360*f0687c8aSRaman Tenneti 	ASSERT((x & 1) == 0);
361*f0687c8aSRaman Tenneti 	ASSERT((y & 1) == 0);
362*f0687c8aSRaman Tenneti 
363*f0687c8aSRaman Tenneti 	switch (buf.format()) {
364*f0687c8aSRaman Tenneti 	case PixelFormat::NV12:
365*f0687c8aSRaman Tenneti 	case PixelFormat::NV21:
366*f0687c8aSRaman Tenneti 		draw_yuv420_semiplanar_macropixel(buf, x, y, yuv1, yuv2, yuv3, yuv4);
367*f0687c8aSRaman Tenneti 		break;
368*f0687c8aSRaman Tenneti 
369*f0687c8aSRaman Tenneti 	case PixelFormat::YUV420:
370*f0687c8aSRaman Tenneti 	case PixelFormat::YVU420:
371*f0687c8aSRaman Tenneti 		draw_yuv420_planar_macropixel(buf, x, y, yuv1, yuv2, yuv3, yuv4);
372*f0687c8aSRaman Tenneti 		break;
373*f0687c8aSRaman Tenneti 
374*f0687c8aSRaman Tenneti 	default:
375*f0687c8aSRaman Tenneti 		throw std::invalid_argument("invalid pixelformat");
376*f0687c8aSRaman Tenneti 	}
377*f0687c8aSRaman Tenneti }
378*f0687c8aSRaman Tenneti 
draw_rect(IFramebuffer & fb,uint32_t x,uint32_t y,uint32_t w,uint32_t h,RGB color)379*f0687c8aSRaman Tenneti void draw_rect(IFramebuffer& fb, uint32_t x, uint32_t y, uint32_t w, uint32_t h, RGB color)
380*f0687c8aSRaman Tenneti {
381*f0687c8aSRaman Tenneti 	unsigned i, j;
382*f0687c8aSRaman Tenneti 	YUV yuvcolor = color.yuv();
383*f0687c8aSRaman Tenneti 
384*f0687c8aSRaman Tenneti 	switch (fb.format()) {
385*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB8888:
386*f0687c8aSRaman Tenneti 	case PixelFormat::XBGR8888:
387*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB8888:
388*f0687c8aSRaman Tenneti 	case PixelFormat::ABGR8888:
389*f0687c8aSRaman Tenneti 	case PixelFormat::RGB888:
390*f0687c8aSRaman Tenneti 	case PixelFormat::BGR888:
391*f0687c8aSRaman Tenneti 	case PixelFormat::RGB565:
392*f0687c8aSRaman Tenneti 	case PixelFormat::BGR565:
393*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB4444:
394*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB1555:
395*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB4444:
396*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB1555:
397*f0687c8aSRaman Tenneti 	case PixelFormat::RGB332:
398*f0687c8aSRaman Tenneti 		for (j = 0; j < h; j++) {
399*f0687c8aSRaman Tenneti 			for (i = 0; i < w; i++) {
400*f0687c8aSRaman Tenneti 				draw_rgb_pixel(fb, x + i, y + j, color);
401*f0687c8aSRaman Tenneti 			}
402*f0687c8aSRaman Tenneti 		}
403*f0687c8aSRaman Tenneti 		break;
404*f0687c8aSRaman Tenneti 
405*f0687c8aSRaman Tenneti 	case PixelFormat::YUV444:
406*f0687c8aSRaman Tenneti 	case PixelFormat::YVU444:
407*f0687c8aSRaman Tenneti 		for (j = 0; j < h; j++) {
408*f0687c8aSRaman Tenneti 			for (i = 0; i < w; i++) {
409*f0687c8aSRaman Tenneti 				draw_yuv444_pixel(fb, x + i, y + j, yuvcolor);
410*f0687c8aSRaman Tenneti 			}
411*f0687c8aSRaman Tenneti 		}
412*f0687c8aSRaman Tenneti 		break;
413*f0687c8aSRaman Tenneti 
414*f0687c8aSRaman Tenneti 	case PixelFormat::UYVY:
415*f0687c8aSRaman Tenneti 	case PixelFormat::YUYV:
416*f0687c8aSRaman Tenneti 	case PixelFormat::YVYU:
417*f0687c8aSRaman Tenneti 	case PixelFormat::VYUY:
418*f0687c8aSRaman Tenneti 	case PixelFormat::NV16:
419*f0687c8aSRaman Tenneti 	case PixelFormat::NV61:
420*f0687c8aSRaman Tenneti 	case PixelFormat::YUV422:
421*f0687c8aSRaman Tenneti 	case PixelFormat::YVU422:
422*f0687c8aSRaman Tenneti 		for (j = 0; j < h; j++) {
423*f0687c8aSRaman Tenneti 			for (i = 0; i < w; i += 2) {
424*f0687c8aSRaman Tenneti 				draw_yuv422_macropixel(fb, x + i, y + j, yuvcolor, yuvcolor);
425*f0687c8aSRaman Tenneti 			}
426*f0687c8aSRaman Tenneti 		}
427*f0687c8aSRaman Tenneti 		break;
428*f0687c8aSRaman Tenneti 
429*f0687c8aSRaman Tenneti 	case PixelFormat::NV12:
430*f0687c8aSRaman Tenneti 	case PixelFormat::NV21:
431*f0687c8aSRaman Tenneti 	case PixelFormat::YUV420:
432*f0687c8aSRaman Tenneti 	case PixelFormat::YVU420:
433*f0687c8aSRaman Tenneti 		for (j = 0; j < h; j += 2) {
434*f0687c8aSRaman Tenneti 			for (i = 0; i < w; i += 2) {
435*f0687c8aSRaman Tenneti 				draw_yuv420_macropixel(fb, x + i, y + j,
436*f0687c8aSRaman Tenneti 						       yuvcolor, yuvcolor, yuvcolor, yuvcolor);
437*f0687c8aSRaman Tenneti 			}
438*f0687c8aSRaman Tenneti 		}
439*f0687c8aSRaman Tenneti 		break;
440*f0687c8aSRaman Tenneti 	default:
441*f0687c8aSRaman Tenneti 		throw std::invalid_argument("draw_rect: unknown pixelformat");
442*f0687c8aSRaman Tenneti 	}
443*f0687c8aSRaman Tenneti }
444*f0687c8aSRaman Tenneti 
draw_horiz_line(IFramebuffer & fb,uint32_t x1,uint32_t x2,uint32_t y,RGB color)445*f0687c8aSRaman Tenneti void draw_horiz_line(IFramebuffer& fb, uint32_t x1, uint32_t x2, uint32_t y, RGB color)
446*f0687c8aSRaman Tenneti {
447*f0687c8aSRaman Tenneti 	for (uint32_t x = x1; x <= x2; ++x)
448*f0687c8aSRaman Tenneti 		draw_rgb_pixel(fb, x, y, color);
449*f0687c8aSRaman Tenneti }
450*f0687c8aSRaman Tenneti 
draw_circle(IFramebuffer & fb,int32_t xCenter,int32_t yCenter,int32_t radius,RGB color)451*f0687c8aSRaman Tenneti void draw_circle(IFramebuffer& fb, int32_t xCenter, int32_t yCenter, int32_t radius, RGB color)
452*f0687c8aSRaman Tenneti {
453*f0687c8aSRaman Tenneti 	int32_t r2 = radius * radius;
454*f0687c8aSRaman Tenneti 
455*f0687c8aSRaman Tenneti 	for (int y = -radius; y <= radius; y++) {
456*f0687c8aSRaman Tenneti 		int32_t x = (int)(sqrt(r2 - y * y) + 0.5);
457*f0687c8aSRaman Tenneti 		draw_horiz_line(fb, xCenter - x, xCenter + x, yCenter - y, color);
458*f0687c8aSRaman Tenneti 	}
459*f0687c8aSRaman Tenneti }
460*f0687c8aSRaman Tenneti 
get_char_pixel(char c,uint32_t x,uint32_t y)461*f0687c8aSRaman Tenneti static bool get_char_pixel(char c, uint32_t x, uint32_t y)
462*f0687c8aSRaman Tenneti {
463*f0687c8aSRaman Tenneti #include "font_8x8.h"
464*f0687c8aSRaman Tenneti 
465*f0687c8aSRaman Tenneti 	uint8_t bits = fontdata_8x8[8 * c + y];
466*f0687c8aSRaman Tenneti 	bool bit = (bits >> (7 - x)) & 1;
467*f0687c8aSRaman Tenneti 
468*f0687c8aSRaman Tenneti 	return bit;
469*f0687c8aSRaman Tenneti }
470*f0687c8aSRaman Tenneti 
draw_char(IFramebuffer & buf,uint32_t xpos,uint32_t ypos,char c,RGB color)471*f0687c8aSRaman Tenneti static void draw_char(IFramebuffer& buf, uint32_t xpos, uint32_t ypos, char c, RGB color)
472*f0687c8aSRaman Tenneti {
473*f0687c8aSRaman Tenneti 	unsigned x, y;
474*f0687c8aSRaman Tenneti 	YUV yuvcolor = color.yuv();
475*f0687c8aSRaman Tenneti 
476*f0687c8aSRaman Tenneti 	switch (buf.format()) {
477*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB8888:
478*f0687c8aSRaman Tenneti 	case PixelFormat::XBGR8888:
479*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB8888:
480*f0687c8aSRaman Tenneti 	case PixelFormat::ABGR8888:
481*f0687c8aSRaman Tenneti 	case PixelFormat::RGB888:
482*f0687c8aSRaman Tenneti 	case PixelFormat::BGR888:
483*f0687c8aSRaman Tenneti 	case PixelFormat::RGB565:
484*f0687c8aSRaman Tenneti 	case PixelFormat::BGR565:
485*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB4444:
486*f0687c8aSRaman Tenneti 	case PixelFormat::XRGB1555:
487*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB4444:
488*f0687c8aSRaman Tenneti 	case PixelFormat::ARGB1555:
489*f0687c8aSRaman Tenneti 	case PixelFormat::RGB332:
490*f0687c8aSRaman Tenneti 		for (y = 0; y < 8; y++) {
491*f0687c8aSRaman Tenneti 			for (x = 0; x < 8; x++) {
492*f0687c8aSRaman Tenneti 				bool b = get_char_pixel(c, x, y);
493*f0687c8aSRaman Tenneti 
494*f0687c8aSRaman Tenneti 				draw_rgb_pixel(buf, xpos + x, ypos + y, b ? color : RGB());
495*f0687c8aSRaman Tenneti 			}
496*f0687c8aSRaman Tenneti 		}
497*f0687c8aSRaman Tenneti 		break;
498*f0687c8aSRaman Tenneti 
499*f0687c8aSRaman Tenneti 	case PixelFormat::YUV444:
500*f0687c8aSRaman Tenneti 	case PixelFormat::YVU444:
501*f0687c8aSRaman Tenneti 		for (y = 0; y < 8; y++) {
502*f0687c8aSRaman Tenneti 			for (x = 0; x < 8; x++) {
503*f0687c8aSRaman Tenneti 				bool b = get_char_pixel(c, x, y);
504*f0687c8aSRaman Tenneti 
505*f0687c8aSRaman Tenneti 				draw_yuv444_pixel(buf, xpos + x, ypos + y, b ? yuvcolor : YUV(RGB()));
506*f0687c8aSRaman Tenneti 			}
507*f0687c8aSRaman Tenneti 		}
508*f0687c8aSRaman Tenneti 		break;
509*f0687c8aSRaman Tenneti 
510*f0687c8aSRaman Tenneti 	case PixelFormat::UYVY:
511*f0687c8aSRaman Tenneti 	case PixelFormat::YUYV:
512*f0687c8aSRaman Tenneti 	case PixelFormat::YVYU:
513*f0687c8aSRaman Tenneti 	case PixelFormat::VYUY:
514*f0687c8aSRaman Tenneti 	case PixelFormat::NV16:
515*f0687c8aSRaman Tenneti 	case PixelFormat::NV61:
516*f0687c8aSRaman Tenneti 	case PixelFormat::YUV422:
517*f0687c8aSRaman Tenneti 	case PixelFormat::YVU422:
518*f0687c8aSRaman Tenneti 		for (y = 0; y < 8; y++) {
519*f0687c8aSRaman Tenneti 			for (x = 0; x < 8; x += 2) {
520*f0687c8aSRaman Tenneti 				bool b0 = get_char_pixel(c, x, y);
521*f0687c8aSRaman Tenneti 				bool b1 = get_char_pixel(c, x + 1, y);
522*f0687c8aSRaman Tenneti 
523*f0687c8aSRaman Tenneti 				draw_yuv422_macropixel(buf, xpos + x, ypos + y,
524*f0687c8aSRaman Tenneti 						       b0 ? yuvcolor : YUV(RGB()), b1 ? yuvcolor : YUV(RGB()));
525*f0687c8aSRaman Tenneti 			}
526*f0687c8aSRaman Tenneti 		}
527*f0687c8aSRaman Tenneti 		break;
528*f0687c8aSRaman Tenneti 
529*f0687c8aSRaman Tenneti 	case PixelFormat::NV12:
530*f0687c8aSRaman Tenneti 	case PixelFormat::NV21:
531*f0687c8aSRaman Tenneti 	case PixelFormat::YUV420:
532*f0687c8aSRaman Tenneti 	case PixelFormat::YVU420:
533*f0687c8aSRaman Tenneti 		for (y = 0; y < 8; y += 2) {
534*f0687c8aSRaman Tenneti 			for (x = 0; x < 8; x += 2) {
535*f0687c8aSRaman Tenneti 				bool b00 = get_char_pixel(c, x, y);
536*f0687c8aSRaman Tenneti 				bool b10 = get_char_pixel(c, x + 1, y);
537*f0687c8aSRaman Tenneti 				bool b01 = get_char_pixel(c, x, y + 1);
538*f0687c8aSRaman Tenneti 				bool b11 = get_char_pixel(c, x + 1, y + 1);
539*f0687c8aSRaman Tenneti 
540*f0687c8aSRaman Tenneti 				draw_yuv420_macropixel(buf, xpos + x, ypos + y,
541*f0687c8aSRaman Tenneti 						       b00 ? yuvcolor : YUV(RGB()), b10 ? yuvcolor : YUV(RGB()),
542*f0687c8aSRaman Tenneti 						       b01 ? yuvcolor : YUV(RGB()), b11 ? yuvcolor : YUV(RGB()));
543*f0687c8aSRaman Tenneti 			}
544*f0687c8aSRaman Tenneti 		}
545*f0687c8aSRaman Tenneti 		break;
546*f0687c8aSRaman Tenneti 	default:
547*f0687c8aSRaman Tenneti 		throw std::invalid_argument("draw_char: unknown pixelformat");
548*f0687c8aSRaman Tenneti 	}
549*f0687c8aSRaman Tenneti }
550*f0687c8aSRaman Tenneti 
draw_text(IFramebuffer & buf,uint32_t x,uint32_t y,const string & str,RGB color)551*f0687c8aSRaman Tenneti void draw_text(IFramebuffer& buf, uint32_t x, uint32_t y, const string& str, RGB color)
552*f0687c8aSRaman Tenneti {
553*f0687c8aSRaman Tenneti 	for (unsigned i = 0; i < str.size(); i++)
554*f0687c8aSRaman Tenneti 		draw_char(buf, (x + 8 * i), y, str[i], color);
555*f0687c8aSRaman Tenneti }
556*f0687c8aSRaman Tenneti 
557*f0687c8aSRaman Tenneti } // namespace kms
558