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