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