1 /*
2 * This file is part of libplacebo.
3 *
4 * libplacebo is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * libplacebo is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifndef LIBPLACEBO_DAV1D_H_
19 #error This header should be included as part of <libplacebo/utils/dav1d.h>
20 #else
21
22 #include <stdlib.h>
23
pl_system_from_dav1d(enum Dav1dMatrixCoefficients mc)24 static inline enum pl_color_system pl_system_from_dav1d(enum Dav1dMatrixCoefficients mc)
25 {
26 switch (mc) {
27 case DAV1D_MC_IDENTITY: return PL_COLOR_SYSTEM_RGB; // or XYZ (unlikely)
28 case DAV1D_MC_BT709: return PL_COLOR_SYSTEM_BT_709;
29 case DAV1D_MC_UNKNOWN: return PL_COLOR_SYSTEM_UNKNOWN;
30 case DAV1D_MC_FCC: return PL_COLOR_SYSTEM_UNKNOWN; // missing
31 case DAV1D_MC_BT470BG: return PL_COLOR_SYSTEM_BT_601;
32 case DAV1D_MC_BT601: return PL_COLOR_SYSTEM_BT_601;
33 case DAV1D_MC_SMPTE240: return PL_COLOR_SYSTEM_SMPTE_240M;
34 case DAV1D_MC_SMPTE_YCGCO: return PL_COLOR_SYSTEM_YCGCO;
35 case DAV1D_MC_BT2020_NCL: return PL_COLOR_SYSTEM_BT_2020_NC;
36 case DAV1D_MC_BT2020_CL: return PL_COLOR_SYSTEM_BT_2020_C;
37 case DAV1D_MC_SMPTE2085: return PL_COLOR_SYSTEM_UNKNOWN; // missing
38 case DAV1D_MC_CHROMAT_NCL: return PL_COLOR_SYSTEM_UNKNOWN; // missing
39 case DAV1D_MC_CHROMAT_CL: return PL_COLOR_SYSTEM_UNKNOWN; // missing
40 // Note: this colorspace is confused between PQ and HLG, which dav1d
41 // requires inferring from other sources, but libplacebo makes
42 // explicit. Default to PQ as it's the more common scenario.
43 case DAV1D_MC_ICTCP: return PL_COLOR_SYSTEM_BT_2100_PQ;
44 case DAV1D_MC_RESERVED: abort();
45 }
46
47 return PL_COLOR_SYSTEM_UNKNOWN;
48 }
49
pl_system_to_dav1d(enum pl_color_system sys)50 static inline enum Dav1dMatrixCoefficients pl_system_to_dav1d(enum pl_color_system sys)
51 {
52 switch (sys) {
53 case PL_COLOR_SYSTEM_UNKNOWN: return DAV1D_MC_UNKNOWN;
54 case PL_COLOR_SYSTEM_BT_601: return DAV1D_MC_BT601;
55 case PL_COLOR_SYSTEM_BT_709: return DAV1D_MC_BT709;
56 case PL_COLOR_SYSTEM_SMPTE_240M: return DAV1D_MC_SMPTE240;
57 case PL_COLOR_SYSTEM_BT_2020_NC: return DAV1D_MC_BT2020_NCL;
58 case PL_COLOR_SYSTEM_BT_2020_C: return DAV1D_MC_BT2020_CL;
59 case PL_COLOR_SYSTEM_BT_2100_PQ: return DAV1D_MC_ICTCP;
60 case PL_COLOR_SYSTEM_BT_2100_HLG: return DAV1D_MC_ICTCP;
61 case PL_COLOR_SYSTEM_YCGCO: return DAV1D_MC_SMPTE_YCGCO;
62 case PL_COLOR_SYSTEM_RGB: return DAV1D_MC_IDENTITY;
63 case PL_COLOR_SYSTEM_XYZ: return DAV1D_MC_IDENTITY;
64 case PL_COLOR_SYSTEM_COUNT: abort();
65 }
66
67 return DAV1D_MC_UNKNOWN;
68 }
69
pl_levels_from_dav1d(int color_range)70 static inline enum pl_color_levels pl_levels_from_dav1d(int color_range)
71 {
72 return color_range ? PL_COLOR_LEVELS_FULL : PL_COLOR_LEVELS_LIMITED;
73 }
74
pl_levels_to_dav1d(enum pl_color_levels levels)75 static inline int pl_levels_to_dav1d(enum pl_color_levels levels)
76 {
77 return levels == PL_COLOR_LEVELS_FULL;
78 }
79
pl_primaries_from_dav1d(enum Dav1dColorPrimaries prim)80 static inline enum pl_color_primaries pl_primaries_from_dav1d(enum Dav1dColorPrimaries prim)
81 {
82 switch (prim) {
83 case DAV1D_COLOR_PRI_BT709: return PL_COLOR_PRIM_BT_709;
84 case DAV1D_COLOR_PRI_UNKNOWN: return PL_COLOR_PRIM_UNKNOWN;
85 case DAV1D_COLOR_PRI_RESERVED: return PL_COLOR_PRIM_UNKNOWN;
86 case DAV1D_COLOR_PRI_BT470M: return PL_COLOR_PRIM_BT_470M;
87 case DAV1D_COLOR_PRI_BT470BG: return PL_COLOR_PRIM_BT_601_625;
88 case DAV1D_COLOR_PRI_BT601: return PL_COLOR_PRIM_BT_601_525;
89 case DAV1D_COLOR_PRI_SMPTE240: return PL_COLOR_PRIM_BT_601_525;
90 case DAV1D_COLOR_PRI_FILM: return PL_COLOR_PRIM_FILM_C;
91 case DAV1D_COLOR_PRI_BT2020: return PL_COLOR_PRIM_BT_2020;
92 case DAV1D_COLOR_PRI_XYZ: return PL_COLOR_PRIM_CIE_1931;
93 case DAV1D_COLOR_PRI_SMPTE431: return PL_COLOR_PRIM_DCI_P3;
94 case DAV1D_COLOR_PRI_SMPTE432: return PL_COLOR_PRIM_DISPLAY_P3;
95 case DAV1D_COLOR_PRI_EBU3213: return PL_COLOR_PRIM_EBU_3213;
96 }
97
98 return PL_COLOR_PRIM_UNKNOWN;
99 }
100
pl_primaries_to_dav1d(enum pl_color_primaries prim)101 static inline enum Dav1dColorPrimaries pl_primaries_to_dav1d(enum pl_color_primaries prim)
102 {
103 switch (prim) {
104 case PL_COLOR_PRIM_UNKNOWN: return DAV1D_COLOR_PRI_UNKNOWN;
105 case PL_COLOR_PRIM_BT_601_525: return DAV1D_COLOR_PRI_BT601;
106 case PL_COLOR_PRIM_BT_601_625: return DAV1D_COLOR_PRI_BT470BG;
107 case PL_COLOR_PRIM_BT_709: return DAV1D_COLOR_PRI_BT709;
108 case PL_COLOR_PRIM_BT_470M: return DAV1D_COLOR_PRI_BT470M;
109 case PL_COLOR_PRIM_EBU_3213: return DAV1D_COLOR_PRI_EBU3213;
110 case PL_COLOR_PRIM_BT_2020: return DAV1D_COLOR_PRI_BT2020;
111 case PL_COLOR_PRIM_APPLE: return DAV1D_COLOR_PRI_UNKNOWN; // missing
112 case PL_COLOR_PRIM_ADOBE: return DAV1D_COLOR_PRI_UNKNOWN; // missing
113 case PL_COLOR_PRIM_PRO_PHOTO: return DAV1D_COLOR_PRI_UNKNOWN; // missing
114 case PL_COLOR_PRIM_CIE_1931: return DAV1D_COLOR_PRI_XYZ;
115 case PL_COLOR_PRIM_DCI_P3: return DAV1D_COLOR_PRI_SMPTE431;
116 case PL_COLOR_PRIM_DISPLAY_P3: return DAV1D_COLOR_PRI_SMPTE432;
117 case PL_COLOR_PRIM_V_GAMUT: return DAV1D_COLOR_PRI_UNKNOWN; // missing
118 case PL_COLOR_PRIM_S_GAMUT: return DAV1D_COLOR_PRI_UNKNOWN; // missing
119 case PL_COLOR_PRIM_FILM_C: return DAV1D_COLOR_PRI_FILM;
120 case PL_COLOR_PRIM_COUNT: abort();
121 }
122
123 return DAV1D_COLOR_PRI_UNKNOWN;
124 }
125
pl_transfer_from_dav1d(enum Dav1dTransferCharacteristics trc)126 static inline enum pl_color_transfer pl_transfer_from_dav1d(enum Dav1dTransferCharacteristics trc)
127 {
128 switch (trc) {
129 case DAV1D_TRC_BT709: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
130 case DAV1D_TRC_UNKNOWN: return PL_COLOR_TRC_UNKNOWN;
131 case DAV1D_TRC_BT470M: return PL_COLOR_TRC_GAMMA22;
132 case DAV1D_TRC_BT470BG: return PL_COLOR_TRC_GAMMA28;
133 case DAV1D_TRC_BT601: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
134 case DAV1D_TRC_SMPTE240: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
135 case DAV1D_TRC_LINEAR: return PL_COLOR_TRC_LINEAR;
136 case DAV1D_TRC_LOG100: return PL_COLOR_TRC_UNKNOWN; // missing
137 case DAV1D_TRC_LOG100_SQRT10: return PL_COLOR_TRC_UNKNOWN; // missing
138 case DAV1D_TRC_IEC61966: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
139 case DAV1D_TRC_BT1361: return PL_COLOR_TRC_BT_1886; // ETOF != OETF
140 case DAV1D_TRC_SRGB: return PL_COLOR_TRC_SRGB;
141 case DAV1D_TRC_BT2020_10BIT: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
142 case DAV1D_TRC_BT2020_12BIT: return PL_COLOR_TRC_BT_1886; // EOTF != OETF
143 case DAV1D_TRC_SMPTE2084: return PL_COLOR_TRC_PQ;
144 case DAV1D_TRC_SMPTE428: return PL_COLOR_TRC_UNKNOWN; // missing
145 case DAV1D_TRC_HLG: return PL_COLOR_TRC_HLG;
146 case DAV1D_TRC_RESERVED: abort();
147 }
148
149 return PL_COLOR_TRC_UNKNOWN;
150 }
151
pl_transfer_to_dav1d(enum pl_color_transfer trc)152 static inline enum Dav1dTransferCharacteristics pl_transfer_to_dav1d(enum pl_color_transfer trc)
153 {
154 switch (trc) {
155 case PL_COLOR_TRC_UNKNOWN: return DAV1D_TRC_UNKNOWN;
156 case PL_COLOR_TRC_BT_1886: return DAV1D_TRC_BT709; // EOTF != OETF
157 case PL_COLOR_TRC_SRGB: return DAV1D_TRC_SRGB;
158 case PL_COLOR_TRC_LINEAR: return DAV1D_TRC_LINEAR;
159 case PL_COLOR_TRC_GAMMA18: return DAV1D_TRC_UNKNOWN; // missing
160 case PL_COLOR_TRC_GAMMA20: return DAV1D_TRC_UNKNOWN; // missing
161 case PL_COLOR_TRC_GAMMA22: return DAV1D_TRC_BT470M;
162 case PL_COLOR_TRC_GAMMA24: return DAV1D_TRC_UNKNOWN; // missing
163 case PL_COLOR_TRC_GAMMA26: return DAV1D_TRC_UNKNOWN; // missing
164 case PL_COLOR_TRC_GAMMA28: return DAV1D_TRC_BT470BG;
165 case PL_COLOR_TRC_PRO_PHOTO: return DAV1D_TRC_UNKNOWN; // missing
166 case PL_COLOR_TRC_PQ: return DAV1D_TRC_SMPTE2084;
167 case PL_COLOR_TRC_HLG: return DAV1D_TRC_HLG;
168 case PL_COLOR_TRC_V_LOG: return DAV1D_TRC_UNKNOWN; // missing
169 case PL_COLOR_TRC_S_LOG1: return DAV1D_TRC_UNKNOWN; // missing
170 case PL_COLOR_TRC_S_LOG2: return DAV1D_TRC_UNKNOWN; // missing
171 case PL_COLOR_TRC_COUNT: abort();
172 }
173
174 return DAV1D_TRC_UNKNOWN;
175 }
176
pl_chroma_from_dav1d(enum Dav1dChromaSamplePosition loc)177 static inline enum pl_chroma_location pl_chroma_from_dav1d(enum Dav1dChromaSamplePosition loc)
178 {
179 switch (loc) {
180 case DAV1D_CHR_UNKNOWN: return PL_CHROMA_UNKNOWN;
181 case DAV1D_CHR_VERTICAL: return PL_CHROMA_LEFT;
182 case DAV1D_CHR_COLOCATED: return PL_CHROMA_TOP_LEFT;
183 }
184
185 return PL_CHROMA_UNKNOWN;
186 }
187
pl_chroma_to_dav1d(enum pl_chroma_location loc)188 static inline enum Dav1dChromaSamplePosition pl_chroma_to_dav1d(enum pl_chroma_location loc)
189 {
190 switch (loc) {
191 case PL_CHROMA_UNKNOWN: return DAV1D_CHR_UNKNOWN;
192 case PL_CHROMA_LEFT: return DAV1D_CHR_VERTICAL;
193 case PL_CHROMA_CENTER: return DAV1D_CHR_UNKNOWN; // missing
194 case PL_CHROMA_TOP_LEFT: return DAV1D_CHR_COLOCATED;
195 case PL_CHROMA_TOP_CENTER: return DAV1D_CHR_UNKNOWN; // missing
196 case PL_CHROMA_BOTTOM_LEFT: return DAV1D_CHR_UNKNOWN; // missing
197 case PL_CHROMA_BOTTOM_CENTER: return DAV1D_CHR_UNKNOWN; // missing
198 case PL_CHROMA_COUNT: abort();
199 }
200
201 return DAV1D_CHR_UNKNOWN;
202 }
203
pl_fixed24_8(uint32_t n)204 static inline float pl_fixed24_8(uint32_t n)
205 {
206 return (float) n / (1 << 8);
207 }
208
pl_fixed18_14(uint32_t n)209 static inline float pl_fixed18_14(uint32_t n)
210 {
211 return (float) n / (1 << 14);
212 }
213
pl_fixed0_16(uint16_t n)214 static inline float pl_fixed0_16(uint16_t n)
215 {
216 return (float) n / (1 << 16);
217 }
218
219 // Align to a power of 2
220 #define PL_ALIGN2(x, align) (((x) + (align) - 1) & ~((align) - 1))
221
pl_frame_from_dav1dpicture(struct pl_frame * out,const Dav1dPicture * picture)222 static inline void pl_frame_from_dav1dpicture(struct pl_frame *out,
223 const Dav1dPicture *picture)
224 {
225 const Dav1dSequenceHeader *seq_hdr = picture->seq_hdr;
226 int num_planes;
227 switch (picture->p.layout) {
228 case DAV1D_PIXEL_LAYOUT_I400:
229 num_planes = 1;
230 break;
231 case DAV1D_PIXEL_LAYOUT_I420:
232 case DAV1D_PIXEL_LAYOUT_I422:
233 case DAV1D_PIXEL_LAYOUT_I444:
234 num_planes = 3;
235 break;
236 default: abort();
237 }
238
239 *out = (struct pl_frame) {
240 .num_planes = num_planes,
241 .planes = {
242 // Components are always in order, which makes things easy
243 {
244 .components = 1,
245 .component_mapping = {0},
246 }, {
247 .components = 1,
248 .component_mapping = {1},
249 }, {
250 .components = 1,
251 .component_mapping = {2},
252 },
253 },
254 .crop = {
255 0, 0, picture->p.w, picture->p.h,
256 },
257 .color = {
258 .primaries = pl_primaries_from_dav1d(seq_hdr->pri),
259 .transfer = pl_transfer_from_dav1d(seq_hdr->trc),
260 .light = PL_COLOR_LIGHT_UNKNOWN,
261 },
262 .repr = {
263 .sys = pl_system_from_dav1d(seq_hdr->mtrx),
264 .levels = pl_levels_from_dav1d(seq_hdr->color_range),
265 .bits = {
266 .sample_depth = PL_ALIGN2(picture->p.bpc, 8),
267 .color_depth = picture->p.bpc,
268 },
269 },
270 };
271
272 if (seq_hdr->mtrx == DAV1D_MC_ICTCP && seq_hdr->trc == DAV1D_TRC_HLG) {
273
274 // dav1d makes no distinction between PQ and HLG ICtCp, so we need
275 // to manually fix it in the case that we have HLG ICtCp data.
276 out->repr.sys = PL_COLOR_SYSTEM_BT_2100_HLG;
277
278 } else if (seq_hdr->mtrx == DAV1D_MC_IDENTITY &&
279 seq_hdr->pri == DAV1D_COLOR_PRI_XYZ)
280 {
281
282 // dav1d handles this as a special case, but doesn't provide an
283 // explicit flag for it either, so we have to resort to this ugly hack,
284 // even though CIE 1931 RGB *is* a valid thing in principle!
285 out->repr.sys= PL_COLOR_SYSTEM_XYZ;
286
287 } else if (!out->repr.sys) {
288
289 // PL_COLOR_SYSTEM_UNKNOWN maps to RGB, so hard-code this one
290 out->repr.sys = pl_color_system_guess_ycbcr(picture->p.w, picture->p.h);
291 }
292
293 const Dav1dContentLightLevel *cll = picture->content_light;
294 if (cll) {
295 out->color.sig_peak = cll->max_content_light_level / PL_COLOR_SDR_WHITE;
296 out->color.sig_avg = cll->max_frame_average_light_level / PL_COLOR_SDR_WHITE;
297 }
298
299 // This overrides the CLL values above, if both are present
300 const Dav1dMasteringDisplay *md = picture->mastering_display;
301 if (md) {
302 out->color.sig_peak = pl_fixed24_8(md->max_luminance) / PL_COLOR_SDR_WHITE;
303 out->color.sig_floor = pl_fixed18_14(md->min_luminance) / PL_COLOR_SDR_WHITE;
304 }
305
306 // Make sure this value is more or less legal
307 if (out->color.sig_peak < 1.0 || out->color.sig_peak > 50.0)
308 out->color.sig_peak = 0.0;
309
310 if (picture->frame_hdr->film_grain.present) {
311 const Dav1dFilmGrainData *fg = &picture->frame_hdr->film_grain.data;
312 struct pl_av1_grain_data *av1 = &out->av1_grain;
313 *av1 = (struct pl_av1_grain_data) {
314 .grain_seed = fg->seed,
315 .num_points_y = fg->num_y_points,
316 .chroma_scaling_from_luma = fg->chroma_scaling_from_luma,
317 .num_points_uv = { fg->num_uv_points[0], fg->num_uv_points[1] },
318 .scaling_shift = fg->scaling_shift,
319 .ar_coeff_lag = fg->ar_coeff_lag,
320 .ar_coeff_shift = (int) fg->ar_coeff_shift,
321 .grain_scale_shift = fg->grain_scale_shift,
322 .uv_mult = { fg->uv_mult[0], fg->uv_mult[1] },
323 .uv_mult_luma = { fg->uv_luma_mult[0], fg->uv_luma_mult[1] },
324 .uv_offset = { fg->uv_offset[0], fg->uv_offset[1] },
325 .overlap = fg->overlap_flag,
326 };
327
328 memcpy(av1->points_y, fg->y_points, sizeof(av1->points_y));
329 memcpy(av1->points_uv, fg->uv_points, sizeof(av1->points_uv));
330 memcpy(av1->ar_coeffs_y, fg->ar_coeffs_y, sizeof(av1->ar_coeffs_y));
331 memcpy(av1->ar_coeffs_uv[0], fg->ar_coeffs_uv[0], sizeof(av1->ar_coeffs_uv[0]));
332 memcpy(av1->ar_coeffs_uv[1], fg->ar_coeffs_uv[1], sizeof(av1->ar_coeffs_uv[1]));
333 }
334
335 switch (picture->p.layout) {
336 case DAV1D_PIXEL_LAYOUT_I400:
337 case DAV1D_PIXEL_LAYOUT_I444:
338 break;
339 case DAV1D_PIXEL_LAYOUT_I420:
340 case DAV1D_PIXEL_LAYOUT_I422:
341 // Only set the chroma location for definitely subsampled images
342 pl_frame_set_chroma_location(out, pl_chroma_from_dav1d(seq_hdr->chr));
343 break;
344 }
345 }
346
pl_swapchain_colors_from_dav1dpicture(struct pl_swapchain_colors * out_colors,const Dav1dPicture * picture)347 static void pl_swapchain_colors_from_dav1dpicture(struct pl_swapchain_colors *out_colors,
348 const Dav1dPicture *picture)
349 {
350 struct pl_frame frame;
351 pl_frame_from_dav1dpicture(&frame, picture);
352
353 *out_colors = (struct pl_swapchain_colors) {
354 .primaries = frame.color.primaries,
355 .transfer = frame.color.transfer,
356 };
357
358 const Dav1dContentLightLevel *cll = picture->content_light;
359 if (cll) {
360 out_colors->hdr.max_cll = cll->max_content_light_level;
361 out_colors->hdr.max_fall = cll->max_frame_average_light_level;
362 }
363
364 const Dav1dMasteringDisplay *md = picture->mastering_display;
365 if (md) {
366 out_colors->hdr.min_luma = pl_fixed18_14(md->min_luminance);
367 out_colors->hdr.max_luma = pl_fixed24_8(md->max_luminance);
368 out_colors->hdr.prim.red.x = pl_fixed0_16(md->primaries[0][0]);
369 out_colors->hdr.prim.red.y = pl_fixed0_16(md->primaries[0][1]);
370 out_colors->hdr.prim.green.x = pl_fixed0_16(md->primaries[1][0]);
371 out_colors->hdr.prim.green.y = pl_fixed0_16(md->primaries[1][1]);
372 out_colors->hdr.prim.blue.x = pl_fixed0_16(md->primaries[2][0]);
373 out_colors->hdr.prim.blue.y = pl_fixed0_16(md->primaries[2][1]);
374 out_colors->hdr.prim.white.x = pl_fixed0_16(md->white_point[0]);
375 out_colors->hdr.prim.white.y = pl_fixed0_16(md->white_point[1]);
376 }
377 }
378
379 #define PL_MAGIC0 0x2c2a1269
380 #define PL_MAGIC1 0xc6d02577
381
382 struct pl_dav1dalloc {
383 uint32_t magic[2];
384 pl_gpu gpu;
385 pl_buf buf;
386 };
387
388 struct pl_dav1dref {
389 Dav1dPicture pic;
390 uint8_t count;
391 };
392
pl_dav1dpicture_unref(void * priv)393 static void pl_dav1dpicture_unref(void *priv)
394 {
395 struct pl_dav1dref *ref = priv;
396 if (--ref->count == 0) {
397 dav1d_picture_unref(&ref->pic);
398 free(ref);
399 }
400 }
401
pl_upload_dav1dpicture(pl_gpu gpu,struct pl_frame * out,pl_tex tex[3],const struct pl_dav1d_upload_params * params)402 static inline bool pl_upload_dav1dpicture(pl_gpu gpu,
403 struct pl_frame *out,
404 pl_tex tex[3],
405 const struct pl_dav1d_upload_params *params)
406 {
407 Dav1dPicture *pic = params->picture;
408 pl_frame_from_dav1dpicture(out, pic);
409 if (!params->film_grain)
410 out->av1_grain = (struct pl_av1_grain_data) {0};
411
412 const int bytes = (pic->p.bpc + 7) / 8; // rounded up
413 int sub_x = 0, sub_y = 0;
414 switch (pic->p.layout) {
415 case DAV1D_PIXEL_LAYOUT_I400:
416 case DAV1D_PIXEL_LAYOUT_I444:
417 break;
418 case DAV1D_PIXEL_LAYOUT_I420:
419 sub_x = sub_y = 1;
420 break;
421 case DAV1D_PIXEL_LAYOUT_I422:
422 sub_x = 1;
423 break;
424 }
425
426 struct pl_plane_data data[3] = {
427 {
428 // Y plane
429 .type = PL_FMT_UNORM,
430 .width = pic->p.w,
431 .height = pic->p.h,
432 .pixel_stride = bytes,
433 .row_stride = pic->stride[0],
434 .component_size = {bytes * 8},
435 .component_map = {0},
436 }, {
437 // U plane
438 .type = PL_FMT_UNORM,
439 .width = pic->p.w >> sub_x,
440 .height = pic->p.h >> sub_y,
441 .pixel_stride = bytes,
442 .row_stride = pic->stride[1],
443 .component_size = {bytes * 8},
444 .component_map = {1},
445 }, {
446 // V plane
447 .type = PL_FMT_UNORM,
448 .width = pic->p.w >> sub_x,
449 .height = pic->p.h >> sub_y,
450 .pixel_stride = bytes,
451 .row_stride = pic->stride[1],
452 .component_size = {bytes * 8},
453 .component_map = {2},
454 },
455 };
456
457 pl_buf buf = NULL;
458 struct pl_dav1dalloc *alloc = params->gpu_allocated ? pic->allocator_data : NULL;
459 struct pl_dav1dref *ref = NULL;
460
461 if (alloc && alloc->magic[0] == PL_MAGIC0 && alloc->magic[1] == PL_MAGIC1) {
462 // Re-use pre-allocated buffers directly
463 assert(alloc->gpu == gpu);
464 buf = alloc->buf;
465 } else if (params->asynchronous && gpu->limits.callbacks) {
466 ref = malloc(sizeof(*ref));
467 if (!ref)
468 return false;
469 memcpy(&ref->pic, pic, sizeof(Dav1dPicture));
470 ref->count = out->num_planes;
471 }
472
473 for (int p = 0; p < out->num_planes; p++) {
474 if (buf) {
475 data[p].buf = buf;
476 data[p].buf_offset = (uintptr_t) pic->data[p] - (uintptr_t) buf->data;
477 } else {
478 data[p].pixels = pic->data[p];
479 if (ref) {
480 data[p].priv = ref;
481 data[p].callback = pl_dav1dpicture_unref;
482 }
483 }
484
485 if (!pl_upload_plane(gpu, &out->planes[p], &tex[p], &data[p])) {
486 free(ref);
487 return false;
488 }
489 }
490
491 if (params->asynchronous) {
492 if (ref) {
493 *pic = (Dav1dPicture) {0};
494 } else {
495 dav1d_picture_unref(pic);
496 }
497 }
498
499 return true;
500 }
501
pl_allocate_dav1dpicture(Dav1dPicture * p,void * cookie)502 static inline int pl_allocate_dav1dpicture(Dav1dPicture *p, void *cookie)
503 {
504 pl_gpu gpu = cookie;
505 if (!gpu->limits.max_mapped_size || !gpu->limits.buf_transfer)
506 return DAV1D_ERR(ENOTSUP);
507
508 // Copied from dav1d_default_picture_alloc
509 const int hbd = p->p.bpc > 8;
510 const int aligned_w = PL_ALIGN2(p->p.w, 128);
511 const int aligned_h = PL_ALIGN2(p->p.h, 128);
512 const int has_chroma = p->p.layout != DAV1D_PIXEL_LAYOUT_I400;
513 const int ss_ver = p->p.layout == DAV1D_PIXEL_LAYOUT_I420;
514 const int ss_hor = p->p.layout != DAV1D_PIXEL_LAYOUT_I444;
515 p->stride[0] = aligned_w << hbd;
516 p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0;
517
518 // Align strides up to multiples of the GPU performance hints
519 p->stride[0] = PL_ALIGN2(p->stride[0], gpu->limits.align_tex_xfer_stride);
520 p->stride[1] = PL_ALIGN2(p->stride[1], gpu->limits.align_tex_xfer_stride);
521
522 // Aligning offsets to 4 also implicitly aligns to the texel size (1 or 2)
523 size_t off_align = PL_ALIGN2(gpu->limits.align_tex_xfer_offset, 4);
524 const size_t y_sz = PL_ALIGN2(p->stride[0] * aligned_h, off_align);
525 const size_t uv_sz = PL_ALIGN2(p->stride[1] * (aligned_h >> ss_ver), off_align);
526
527 // The extra DAV1D_PICTURE_ALIGNMENTs are to brute force plane alignment,
528 // even in the case that the driver gives us insane alignments
529 const size_t pic_size = y_sz + 2 * uv_sz;
530 const size_t total_size = pic_size + DAV1D_PICTURE_ALIGNMENT * 4;
531
532 // Validate size limitations
533 if (total_size > gpu->limits.max_mapped_size)
534 return DAV1D_ERR(ENOMEM);
535
536 pl_buf buf = pl_buf_create(gpu, &(struct pl_buf_params) {
537 .size = total_size,
538 .host_mapped = true,
539 .memory_type = PL_BUF_MEM_HOST,
540 });
541
542 if (!buf)
543 return DAV1D_ERR(ENOMEM);
544
545 struct pl_dav1dalloc *alloc = malloc(sizeof(struct pl_dav1dalloc));
546 if (!alloc) {
547 pl_buf_destroy(gpu, &buf);
548 return DAV1D_ERR(ENOMEM);
549 }
550
551 *alloc = (struct pl_dav1dalloc) {
552 .magic = { PL_MAGIC0, PL_MAGIC1 },
553 .gpu = gpu,
554 .buf = buf,
555 };
556
557 assert(buf->data);
558 uintptr_t base = (uintptr_t) buf->data, data[3];
559 data[0] = PL_ALIGN2(base, DAV1D_PICTURE_ALIGNMENT);
560 data[1] = PL_ALIGN2(data[0] + y_sz, DAV1D_PICTURE_ALIGNMENT);
561 data[2] = PL_ALIGN2(data[1] + uv_sz, DAV1D_PICTURE_ALIGNMENT);
562
563 p->allocator_data = alloc;
564 p->data[0] = (void *) data[0];
565 p->data[1] = (void *) data[1];
566 p->data[2] = (void *) data[2];
567 return 0;
568 }
569
pl_release_dav1dpicture(Dav1dPicture * p,void * cookie)570 static inline void pl_release_dav1dpicture(Dav1dPicture *p, void *cookie)
571 {
572 pl_gpu gpu = cookie;
573 struct pl_dav1dalloc *alloc = p->allocator_data;
574 if (!alloc)
575 return;
576
577 assert(alloc->magic[0] == PL_MAGIC0);
578 assert(alloc->magic[1] == PL_MAGIC1);
579 assert(alloc->gpu == gpu);
580 pl_buf_destroy(alloc->gpu, &alloc->buf);
581 free(alloc);
582
583 p->data[0] = p->data[1] = p->data[2] = p->allocator_data = NULL;
584 }
585
586 #undef PL_ALIGN2
587 #undef PL_MAGIC0
588 #undef PL_MAGIC1
589
590 #endif // LIBPLACEBO_DAV1D_H_
591