vkms_composer.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // SPDX-License-Identifier: GPL-2.0+
  2. #include <linux/crc32.h>
  3. #include <drm/drm_atomic.h>
  4. #include <drm/drm_atomic_helper.h>
  5. #include <drm/drm_blend.h>
  6. #include <drm/drm_colorop.h>
  7. #include <drm/drm_fourcc.h>
  8. #include <drm/drm_fixed.h>
  9. #include <drm/drm_gem_framebuffer_helper.h>
  10. #include <drm/drm_print.h>
  11. #include <drm/drm_vblank.h>
  12. #include <linux/minmax.h>
  13. #include <kunit/visibility.h>
  14. #include "vkms_composer.h"
  15. #include "vkms_luts.h"
  16. static u16 pre_mul_blend_channel(u16 src, u16 dst, u16 alpha)
  17. {
  18. u32 new_color;
  19. new_color = (src * 0xffff + dst * (0xffff - alpha));
  20. return DIV_ROUND_CLOSEST(new_color, 0xffff);
  21. }
  22. /**
  23. * pre_mul_alpha_blend - alpha blending equation
  24. * @stage_buffer: The line with the pixels from src_plane
  25. * @output_buffer: A line buffer that receives all the blends output
  26. * @x_start: The start offset
  27. * @pixel_count: The number of pixels to blend
  28. *
  29. * The pixels [@x_start;@x_start+@pixel_count) in stage_buffer are blended at
  30. * [@x_start;@x_start+@pixel_count) in output_buffer.
  31. *
  32. * The current DRM assumption is that pixel color values have been already
  33. * pre-multiplied with the alpha channel values. See more
  34. * drm_plane_create_blend_mode_property(). Also, this formula assumes a
  35. * completely opaque background.
  36. */
  37. static void pre_mul_alpha_blend(const struct line_buffer *stage_buffer,
  38. struct line_buffer *output_buffer, int x_start, int pixel_count)
  39. {
  40. struct pixel_argb_u16 *out = &output_buffer->pixels[x_start];
  41. const struct pixel_argb_u16 *in = &stage_buffer->pixels[x_start];
  42. for (int i = 0; i < pixel_count; i++) {
  43. out[i].a = (u16)0xffff;
  44. out[i].r = pre_mul_blend_channel(in[i].r, out[i].r, in[i].a);
  45. out[i].g = pre_mul_blend_channel(in[i].g, out[i].g, in[i].a);
  46. out[i].b = pre_mul_blend_channel(in[i].b, out[i].b, in[i].a);
  47. }
  48. }
  49. static void fill_background(const struct pixel_argb_u16 *background_color,
  50. struct line_buffer *output_buffer)
  51. {
  52. for (size_t i = 0; i < output_buffer->n_pixels; i++)
  53. output_buffer->pixels[i] = *background_color;
  54. }
  55. // lerp(a, b, t) = a + (b - a) * t
  56. VISIBLE_IF_KUNIT u16 lerp_u16(u16 a, u16 b, s64 t)
  57. {
  58. s64 a_fp = drm_int2fixp(a);
  59. s64 b_fp = drm_int2fixp(b);
  60. s64 delta = drm_fixp_mul(b_fp - a_fp, t);
  61. return drm_fixp2int_round(a_fp + delta);
  62. }
  63. EXPORT_SYMBOL_IF_KUNIT(lerp_u16);
  64. VISIBLE_IF_KUNIT s64 get_lut_index(const struct vkms_color_lut *lut, u16 channel_value)
  65. {
  66. s64 color_channel_fp = drm_int2fixp(channel_value);
  67. return drm_fixp_mul(color_channel_fp, lut->channel_value2index_ratio);
  68. }
  69. EXPORT_SYMBOL_IF_KUNIT(get_lut_index);
  70. VISIBLE_IF_KUNIT u16 apply_lut_to_channel_value(const struct vkms_color_lut *lut, u16 channel_value,
  71. enum lut_channel channel)
  72. {
  73. s64 lut_index = get_lut_index(lut, channel_value);
  74. u16 *floor_lut_value, *ceil_lut_value;
  75. u16 floor_channel_value, ceil_channel_value;
  76. /*
  77. * This checks if `struct drm_color_lut` has any gap added by the compiler
  78. * between the struct fields.
  79. */
  80. static_assert(sizeof(struct drm_color_lut) == sizeof(__u16) * 4);
  81. floor_lut_value = (__u16 *)&lut->base[drm_fixp2int(lut_index)];
  82. if (drm_fixp2int(lut_index) == (lut->lut_length - 1))
  83. /* We're at the end of the LUT array, use same value for ceil and floor */
  84. ceil_lut_value = floor_lut_value;
  85. else
  86. ceil_lut_value = (__u16 *)&lut->base[drm_fixp2int_ceil(lut_index)];
  87. floor_channel_value = floor_lut_value[channel];
  88. ceil_channel_value = ceil_lut_value[channel];
  89. return lerp_u16(floor_channel_value, ceil_channel_value,
  90. lut_index & DRM_FIXED_DECIMAL_MASK);
  91. }
  92. EXPORT_SYMBOL_IF_KUNIT(apply_lut_to_channel_value);
  93. static void apply_lut(const struct vkms_crtc_state *crtc_state, struct line_buffer *output_buffer)
  94. {
  95. if (!crtc_state->gamma_lut.base)
  96. return;
  97. if (!crtc_state->gamma_lut.lut_length)
  98. return;
  99. for (size_t x = 0; x < output_buffer->n_pixels; x++) {
  100. struct pixel_argb_u16 *pixel = &output_buffer->pixels[x];
  101. pixel->r = apply_lut_to_channel_value(&crtc_state->gamma_lut, pixel->r, LUT_RED);
  102. pixel->g = apply_lut_to_channel_value(&crtc_state->gamma_lut, pixel->g, LUT_GREEN);
  103. pixel->b = apply_lut_to_channel_value(&crtc_state->gamma_lut, pixel->b, LUT_BLUE);
  104. }
  105. }
  106. VISIBLE_IF_KUNIT void apply_3x4_matrix(struct pixel_argb_s32 *pixel,
  107. const struct drm_color_ctm_3x4 *matrix)
  108. {
  109. s64 rf, gf, bf;
  110. s64 r, g, b;
  111. r = drm_int2fixp(pixel->r);
  112. g = drm_int2fixp(pixel->g);
  113. b = drm_int2fixp(pixel->b);
  114. rf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[0]), r) +
  115. drm_fixp_mul(drm_sm2fixp(matrix->matrix[1]), g) +
  116. drm_fixp_mul(drm_sm2fixp(matrix->matrix[2]), b) +
  117. drm_sm2fixp(matrix->matrix[3]);
  118. gf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[4]), r) +
  119. drm_fixp_mul(drm_sm2fixp(matrix->matrix[5]), g) +
  120. drm_fixp_mul(drm_sm2fixp(matrix->matrix[6]), b) +
  121. drm_sm2fixp(matrix->matrix[7]);
  122. bf = drm_fixp_mul(drm_sm2fixp(matrix->matrix[8]), r) +
  123. drm_fixp_mul(drm_sm2fixp(matrix->matrix[9]), g) +
  124. drm_fixp_mul(drm_sm2fixp(matrix->matrix[10]), b) +
  125. drm_sm2fixp(matrix->matrix[11]);
  126. pixel->r = drm_fixp2int_round(rf);
  127. pixel->g = drm_fixp2int_round(gf);
  128. pixel->b = drm_fixp2int_round(bf);
  129. }
  130. EXPORT_SYMBOL_IF_KUNIT(apply_3x4_matrix);
  131. static void apply_colorop(struct pixel_argb_s32 *pixel, struct drm_colorop *colorop)
  132. {
  133. struct drm_colorop_state *colorop_state = colorop->state;
  134. struct drm_device *dev = colorop->dev;
  135. if (colorop->type == DRM_COLOROP_1D_CURVE) {
  136. switch (colorop_state->curve_1d_type) {
  137. case DRM_COLOROP_1D_CURVE_SRGB_INV_EOTF:
  138. pixel->r = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->r, LUT_RED);
  139. pixel->g = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->g, LUT_GREEN);
  140. pixel->b = apply_lut_to_channel_value(&srgb_inv_eotf, pixel->b, LUT_BLUE);
  141. break;
  142. case DRM_COLOROP_1D_CURVE_SRGB_EOTF:
  143. pixel->r = apply_lut_to_channel_value(&srgb_eotf, pixel->r, LUT_RED);
  144. pixel->g = apply_lut_to_channel_value(&srgb_eotf, pixel->g, LUT_GREEN);
  145. pixel->b = apply_lut_to_channel_value(&srgb_eotf, pixel->b, LUT_BLUE);
  146. break;
  147. default:
  148. drm_WARN_ONCE(dev, true,
  149. "unknown colorop 1D curve type %d\n",
  150. colorop_state->curve_1d_type);
  151. break;
  152. }
  153. } else if (colorop->type == DRM_COLOROP_CTM_3X4) {
  154. if (colorop_state->data)
  155. apply_3x4_matrix(pixel,
  156. (struct drm_color_ctm_3x4 *)colorop_state->data->data);
  157. }
  158. }
  159. static void pre_blend_color_transform(const struct vkms_plane_state *plane_state,
  160. struct line_buffer *output_buffer)
  161. {
  162. struct pixel_argb_s32 pixel;
  163. for (size_t x = 0; x < output_buffer->n_pixels; x++) {
  164. struct drm_colorop *colorop = plane_state->base.base.color_pipeline;
  165. /*
  166. * Some operations, such as applying a BT709 encoding matrix,
  167. * followed by a decoding matrix, require that we preserve
  168. * values above 1.0 and below 0.0 until the end of the pipeline.
  169. *
  170. * Pack the 16-bit UNORM values into s32 to give us head-room to
  171. * avoid clipping until we're at the end of the pipeline. Clip
  172. * intentionally at the end of the pipeline before packing
  173. * UNORM values back into u16.
  174. */
  175. pixel.a = output_buffer->pixels[x].a;
  176. pixel.r = output_buffer->pixels[x].r;
  177. pixel.g = output_buffer->pixels[x].g;
  178. pixel.b = output_buffer->pixels[x].b;
  179. while (colorop) {
  180. struct drm_colorop_state *colorop_state;
  181. colorop_state = colorop->state;
  182. if (!colorop_state)
  183. return;
  184. if (!colorop_state->bypass)
  185. apply_colorop(&pixel, colorop);
  186. colorop = colorop->next;
  187. }
  188. /* clamp values */
  189. output_buffer->pixels[x].a = clamp_val(pixel.a, 0, 0xffff);
  190. output_buffer->pixels[x].r = clamp_val(pixel.r, 0, 0xffff);
  191. output_buffer->pixels[x].g = clamp_val(pixel.g, 0, 0xffff);
  192. output_buffer->pixels[x].b = clamp_val(pixel.b, 0, 0xffff);
  193. }
  194. }
  195. /**
  196. * direction_for_rotation() - Get the correct reading direction for a given rotation
  197. *
  198. * @rotation: Rotation to analyze. It correspond the field @frame_info.rotation.
  199. *
  200. * This function will use the @rotation setting of a source plane to compute the reading
  201. * direction in this plane which correspond to a "left to right writing" in the CRTC.
  202. * For example, if the buffer is reflected on X axis, the pixel must be read from right to left
  203. * to be written from left to right on the CRTC.
  204. */
  205. static enum pixel_read_direction direction_for_rotation(unsigned int rotation)
  206. {
  207. struct drm_rect tmp_a, tmp_b;
  208. int x, y;
  209. /*
  210. * Points A and B are depicted as zero-size rectangles on the CRTC.
  211. * The CRTC writing direction is from A to B. The plane reading direction
  212. * is discovered by inverse-transforming A and B.
  213. * The reading direction is computed by rotating the vector AB (top-left to top-right) in a
  214. * 1x1 square.
  215. */
  216. tmp_a = DRM_RECT_INIT(0, 0, 0, 0);
  217. tmp_b = DRM_RECT_INIT(1, 0, 0, 0);
  218. drm_rect_rotate_inv(&tmp_a, 1, 1, rotation);
  219. drm_rect_rotate_inv(&tmp_b, 1, 1, rotation);
  220. x = tmp_b.x1 - tmp_a.x1;
  221. y = tmp_b.y1 - tmp_a.y1;
  222. if (x == 1 && y == 0)
  223. return READ_LEFT_TO_RIGHT;
  224. else if (x == -1 && y == 0)
  225. return READ_RIGHT_TO_LEFT;
  226. else if (y == 1 && x == 0)
  227. return READ_TOP_TO_BOTTOM;
  228. else if (y == -1 && x == 0)
  229. return READ_BOTTOM_TO_TOP;
  230. WARN_ONCE(true, "The inverse of the rotation gives an incorrect direction.");
  231. return READ_LEFT_TO_RIGHT;
  232. }
  233. /**
  234. * clamp_line_coordinates() - Compute and clamp the coordinate to read and write during the blend
  235. * process.
  236. *
  237. * @direction: direction of the reading
  238. * @current_plane: current plane blended
  239. * @src_line: source line of the reading. Only the top-left coordinate is used. This rectangle
  240. * must be rotated and have a shape of 1*pixel_count if @direction is vertical and a shape of
  241. * pixel_count*1 if @direction is horizontal.
  242. * @src_x_start: x start coordinate for the line reading
  243. * @src_y_start: y start coordinate for the line reading
  244. * @dst_x_start: x coordinate to blend the read line
  245. * @pixel_count: number of pixels to blend
  246. *
  247. * This function is mainly a safety net to avoid reading outside the source buffer. As the
  248. * userspace should never ask to read outside the source plane, all the cases covered here should
  249. * be dead code.
  250. */
  251. static void clamp_line_coordinates(enum pixel_read_direction direction,
  252. const struct vkms_plane_state *current_plane,
  253. const struct drm_rect *src_line, int *src_x_start,
  254. int *src_y_start, int *dst_x_start, int *pixel_count)
  255. {
  256. /* By default the start points are correct */
  257. *src_x_start = src_line->x1;
  258. *src_y_start = src_line->y1;
  259. *dst_x_start = current_plane->frame_info->dst.x1;
  260. /* Get the correct number of pixel to blend, it depends of the direction */
  261. switch (direction) {
  262. case READ_LEFT_TO_RIGHT:
  263. case READ_RIGHT_TO_LEFT:
  264. *pixel_count = drm_rect_width(src_line);
  265. break;
  266. case READ_BOTTOM_TO_TOP:
  267. case READ_TOP_TO_BOTTOM:
  268. *pixel_count = drm_rect_height(src_line);
  269. break;
  270. }
  271. /*
  272. * Clamp the coordinates to avoid reading outside the buffer
  273. *
  274. * This is mainly a security check to avoid reading outside the buffer, the userspace
  275. * should never request to read outside the source buffer.
  276. */
  277. switch (direction) {
  278. case READ_LEFT_TO_RIGHT:
  279. case READ_RIGHT_TO_LEFT:
  280. if (*src_x_start < 0) {
  281. *pixel_count += *src_x_start;
  282. *dst_x_start -= *src_x_start;
  283. *src_x_start = 0;
  284. }
  285. if (*src_x_start + *pixel_count > current_plane->frame_info->fb->width)
  286. *pixel_count = max(0, (int)current_plane->frame_info->fb->width -
  287. *src_x_start);
  288. break;
  289. case READ_BOTTOM_TO_TOP:
  290. case READ_TOP_TO_BOTTOM:
  291. if (*src_y_start < 0) {
  292. *pixel_count += *src_y_start;
  293. *dst_x_start -= *src_y_start;
  294. *src_y_start = 0;
  295. }
  296. if (*src_y_start + *pixel_count > current_plane->frame_info->fb->height)
  297. *pixel_count = max(0, (int)current_plane->frame_info->fb->height -
  298. *src_y_start);
  299. break;
  300. }
  301. }
  302. /**
  303. * blend_line() - Blend a line from a plane to the output buffer
  304. *
  305. * @current_plane: current plane to work on
  306. * @y: line to write in the output buffer
  307. * @crtc_x_limit: width of the output buffer
  308. * @stage_buffer: temporary buffer to convert the pixel line from the source buffer
  309. * @output_buffer: buffer to blend the read line into.
  310. */
  311. static void blend_line(struct vkms_plane_state *current_plane, int y,
  312. int crtc_x_limit, struct line_buffer *stage_buffer,
  313. struct line_buffer *output_buffer)
  314. {
  315. int src_x_start, src_y_start, dst_x_start, pixel_count;
  316. struct drm_rect dst_line, tmp_src, src_line;
  317. /* Avoid rendering useless lines */
  318. if (y < current_plane->frame_info->dst.y1 ||
  319. y >= current_plane->frame_info->dst.y2)
  320. return;
  321. /*
  322. * dst_line is the line to copy. The initial coordinates are inside the
  323. * destination framebuffer, and then drm_rect_* helpers are used to
  324. * compute the correct position into the source framebuffer.
  325. */
  326. dst_line = DRM_RECT_INIT(current_plane->frame_info->dst.x1, y,
  327. drm_rect_width(&current_plane->frame_info->dst),
  328. 1);
  329. drm_rect_fp_to_int(&tmp_src, &current_plane->frame_info->src);
  330. /*
  331. * [1]: Clamping src_line to the crtc_x_limit to avoid writing outside of
  332. * the destination buffer
  333. */
  334. dst_line.x1 = max_t(int, dst_line.x1, 0);
  335. dst_line.x2 = min_t(int, dst_line.x2, crtc_x_limit);
  336. /* The destination is completely outside of the crtc. */
  337. if (dst_line.x2 <= dst_line.x1)
  338. return;
  339. src_line = dst_line;
  340. /*
  341. * Transform the coordinate x/y from the crtc to coordinates into
  342. * coordinates for the src buffer.
  343. *
  344. * - Cancel the offset of the dst buffer.
  345. * - Invert the rotation. This assumes that
  346. * dst = drm_rect_rotate(src, rotation) (dst and src have the
  347. * same size, but can be rotated).
  348. * - Apply the offset of the source rectangle to the coordinate.
  349. */
  350. drm_rect_translate(&src_line, -current_plane->frame_info->dst.x1,
  351. -current_plane->frame_info->dst.y1);
  352. drm_rect_rotate_inv(&src_line, drm_rect_width(&tmp_src),
  353. drm_rect_height(&tmp_src),
  354. current_plane->frame_info->rotation);
  355. drm_rect_translate(&src_line, tmp_src.x1, tmp_src.y1);
  356. /* Get the correct reading direction in the source buffer. */
  357. enum pixel_read_direction direction =
  358. direction_for_rotation(current_plane->frame_info->rotation);
  359. /* [2]: Compute and clamp the number of pixel to read */
  360. clamp_line_coordinates(direction, current_plane, &src_line, &src_x_start, &src_y_start,
  361. &dst_x_start, &pixel_count);
  362. if (pixel_count <= 0) {
  363. /* Nothing to read, so avoid multiple function calls */
  364. return;
  365. }
  366. /*
  367. * Modify the starting point to take in account the rotation
  368. *
  369. * src_line is the top-left corner, so when reading READ_RIGHT_TO_LEFT or
  370. * READ_BOTTOM_TO_TOP, it must be changed to the top-right/bottom-left
  371. * corner.
  372. */
  373. if (direction == READ_RIGHT_TO_LEFT) {
  374. // src_x_start is now the right point
  375. src_x_start += pixel_count - 1;
  376. } else if (direction == READ_BOTTOM_TO_TOP) {
  377. // src_y_start is now the bottom point
  378. src_y_start += pixel_count - 1;
  379. }
  380. /*
  381. * Perform the conversion and the blending
  382. *
  383. * Here we know that the read line (x_start, y_start, pixel_count) is
  384. * inside the source buffer [2] and we don't write outside the stage
  385. * buffer [1].
  386. */
  387. current_plane->pixel_read_line(current_plane, src_x_start, src_y_start, direction,
  388. pixel_count, &stage_buffer->pixels[dst_x_start]);
  389. pre_blend_color_transform(current_plane, stage_buffer);
  390. pre_mul_alpha_blend(stage_buffer, output_buffer,
  391. dst_x_start, pixel_count);
  392. }
  393. /**
  394. * blend - blend the pixels from all planes and compute crc
  395. * @wb: The writeback frame buffer metadata
  396. * @crtc_state: The crtc state
  397. * @crc32: The crc output of the final frame
  398. * @output_buffer: A buffer of a row that will receive the result of the blend(s)
  399. * @stage_buffer: The line with the pixels from plane being blend to the output
  400. * @row_size: The size, in bytes, of a single row
  401. *
  402. * This function blends the pixels (Using the `pre_mul_alpha_blend`)
  403. * from all planes, calculates the crc32 of the output from the former step,
  404. * and, if necessary, convert and store the output to the writeback buffer.
  405. */
  406. static void blend(struct vkms_writeback_job *wb,
  407. struct vkms_crtc_state *crtc_state,
  408. u32 *crc32, struct line_buffer *stage_buffer,
  409. struct line_buffer *output_buffer, size_t row_size)
  410. {
  411. struct vkms_plane_state **plane = crtc_state->active_planes;
  412. u32 n_active_planes = crtc_state->num_active_planes;
  413. const struct pixel_argb_u16 background_color = { .a = 0xffff };
  414. int crtc_y_limit = crtc_state->base.mode.vdisplay;
  415. int crtc_x_limit = crtc_state->base.mode.hdisplay;
  416. /*
  417. * The planes are composed line-by-line to avoid heavy memory usage. It is a necessary
  418. * complexity to avoid poor blending performance.
  419. *
  420. * The function pixel_read_line callback is used to read a line, using an efficient
  421. * algorithm for a specific format, into the staging buffer.
  422. */
  423. for (int y = 0; y < crtc_y_limit; y++) {
  424. fill_background(&background_color, output_buffer);
  425. /* The active planes are composed associatively in z-order. */
  426. for (size_t i = 0; i < n_active_planes; i++) {
  427. blend_line(plane[i], y, crtc_x_limit, stage_buffer, output_buffer);
  428. }
  429. apply_lut(crtc_state, output_buffer);
  430. *crc32 = crc32_le(*crc32, (void *)output_buffer->pixels, row_size);
  431. if (wb)
  432. vkms_writeback_row(wb, output_buffer, y);
  433. }
  434. }
  435. static int check_format_funcs(struct vkms_crtc_state *crtc_state,
  436. struct vkms_writeback_job *active_wb)
  437. {
  438. struct vkms_plane_state **planes = crtc_state->active_planes;
  439. u32 n_active_planes = crtc_state->num_active_planes;
  440. for (size_t i = 0; i < n_active_planes; i++)
  441. if (!planes[i]->pixel_read_line)
  442. return -1;
  443. if (active_wb && !active_wb->pixel_write)
  444. return -1;
  445. return 0;
  446. }
  447. static int check_iosys_map(struct vkms_crtc_state *crtc_state)
  448. {
  449. struct vkms_plane_state **plane_state = crtc_state->active_planes;
  450. u32 n_active_planes = crtc_state->num_active_planes;
  451. for (size_t i = 0; i < n_active_planes; i++)
  452. if (iosys_map_is_null(&plane_state[i]->frame_info->map[0]))
  453. return -1;
  454. return 0;
  455. }
  456. static int compose_active_planes(struct vkms_writeback_job *active_wb,
  457. struct vkms_crtc_state *crtc_state,
  458. u32 *crc32)
  459. {
  460. size_t line_width, pixel_size = sizeof(struct pixel_argb_u16);
  461. struct line_buffer output_buffer, stage_buffer;
  462. int ret = 0;
  463. /*
  464. * This check exists so we can call `crc32_le` for the entire line
  465. * instead doing it for each channel of each pixel in case
  466. * `struct `pixel_argb_u16` had any gap added by the compiler
  467. * between the struct fields.
  468. */
  469. static_assert(sizeof(struct pixel_argb_u16) == 8);
  470. if (WARN_ON(check_iosys_map(crtc_state)))
  471. return -EINVAL;
  472. if (WARN_ON(check_format_funcs(crtc_state, active_wb)))
  473. return -EINVAL;
  474. line_width = crtc_state->base.mode.hdisplay;
  475. stage_buffer.n_pixels = line_width;
  476. output_buffer.n_pixels = line_width;
  477. stage_buffer.pixels = kvmalloc(line_width * pixel_size, GFP_KERNEL);
  478. if (!stage_buffer.pixels) {
  479. DRM_ERROR("Cannot allocate memory for the output line buffer");
  480. return -ENOMEM;
  481. }
  482. output_buffer.pixels = kvmalloc(line_width * pixel_size, GFP_KERNEL);
  483. if (!output_buffer.pixels) {
  484. DRM_ERROR("Cannot allocate memory for intermediate line buffer");
  485. ret = -ENOMEM;
  486. goto free_stage_buffer;
  487. }
  488. blend(active_wb, crtc_state, crc32, &stage_buffer,
  489. &output_buffer, line_width * pixel_size);
  490. kvfree(output_buffer.pixels);
  491. free_stage_buffer:
  492. kvfree(stage_buffer.pixels);
  493. return ret;
  494. }
  495. /**
  496. * vkms_composer_worker - ordered work_struct to compute CRC
  497. *
  498. * @work: work_struct
  499. *
  500. * Work handler for composing and computing CRCs. work_struct scheduled in
  501. * an ordered workqueue that's periodically scheduled to run by
  502. * vkms_vblank_simulate() and flushed at vkms_atomic_commit_tail().
  503. */
  504. void vkms_composer_worker(struct work_struct *work)
  505. {
  506. struct vkms_crtc_state *crtc_state = container_of(work,
  507. struct vkms_crtc_state,
  508. composer_work);
  509. struct drm_crtc *crtc = crtc_state->base.crtc;
  510. struct vkms_writeback_job *active_wb = crtc_state->active_writeback;
  511. struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
  512. bool crc_pending, wb_pending;
  513. u64 frame_start, frame_end;
  514. u32 crc32 = 0;
  515. int ret;
  516. spin_lock_irq(&out->composer_lock);
  517. frame_start = crtc_state->frame_start;
  518. frame_end = crtc_state->frame_end;
  519. crc_pending = crtc_state->crc_pending;
  520. wb_pending = crtc_state->wb_pending;
  521. crtc_state->frame_start = 0;
  522. crtc_state->frame_end = 0;
  523. crtc_state->crc_pending = false;
  524. if (crtc->state->gamma_lut) {
  525. s64 max_lut_index_fp;
  526. s64 u16_max_fp = drm_int2fixp(0xffff);
  527. crtc_state->gamma_lut.base = (struct drm_color_lut *)crtc->state->gamma_lut->data;
  528. crtc_state->gamma_lut.lut_length =
  529. crtc->state->gamma_lut->length / sizeof(struct drm_color_lut);
  530. max_lut_index_fp = drm_int2fixp(crtc_state->gamma_lut.lut_length - 1);
  531. crtc_state->gamma_lut.channel_value2index_ratio = drm_fixp_div(max_lut_index_fp,
  532. u16_max_fp);
  533. } else {
  534. crtc_state->gamma_lut.base = NULL;
  535. }
  536. spin_unlock_irq(&out->composer_lock);
  537. /*
  538. * We raced with the vblank hrtimer and previous work already computed
  539. * the crc, nothing to do.
  540. */
  541. if (!crc_pending)
  542. return;
  543. if (wb_pending)
  544. ret = compose_active_planes(active_wb, crtc_state, &crc32);
  545. else
  546. ret = compose_active_planes(NULL, crtc_state, &crc32);
  547. if (ret)
  548. return;
  549. if (wb_pending) {
  550. drm_writeback_signal_completion(&out->wb_connector, 0);
  551. spin_lock_irq(&out->composer_lock);
  552. crtc_state->wb_pending = false;
  553. spin_unlock_irq(&out->composer_lock);
  554. }
  555. /*
  556. * The worker can fall behind the vblank hrtimer, make sure we catch up.
  557. */
  558. while (frame_start <= frame_end)
  559. drm_crtc_add_crc_entry(crtc, true, frame_start++, &crc32);
  560. }
  561. static const char *const pipe_crc_sources[] = { "auto" };
  562. const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
  563. size_t *count)
  564. {
  565. *count = ARRAY_SIZE(pipe_crc_sources);
  566. return pipe_crc_sources;
  567. }
  568. static int vkms_crc_parse_source(const char *src_name, bool *enabled)
  569. {
  570. int ret = 0;
  571. if (!src_name) {
  572. *enabled = false;
  573. } else if (strcmp(src_name, "auto") == 0) {
  574. *enabled = true;
  575. } else {
  576. *enabled = false;
  577. ret = -EINVAL;
  578. }
  579. return ret;
  580. }
  581. int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
  582. size_t *values_cnt)
  583. {
  584. bool enabled;
  585. if (vkms_crc_parse_source(src_name, &enabled) < 0) {
  586. DRM_DEBUG_DRIVER("unknown source %s\n", src_name);
  587. return -EINVAL;
  588. }
  589. *values_cnt = 1;
  590. return 0;
  591. }
  592. void vkms_set_composer(struct vkms_output *out, bool enabled)
  593. {
  594. bool old_enabled;
  595. if (enabled)
  596. drm_crtc_vblank_get(&out->crtc);
  597. spin_lock_irq(&out->lock);
  598. old_enabled = out->composer_enabled;
  599. out->composer_enabled = enabled;
  600. spin_unlock_irq(&out->lock);
  601. if (old_enabled)
  602. drm_crtc_vblank_put(&out->crtc);
  603. }
  604. int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
  605. {
  606. struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
  607. bool enabled = false;
  608. int ret = 0;
  609. ret = vkms_crc_parse_source(src_name, &enabled);
  610. vkms_set_composer(out, enabled);
  611. return ret;
  612. }