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_UPLOAD_H_
19 #define LIBPLACEBO_UPLOAD_H_
20 
21 #include <stdint.h>
22 
23 #include <libplacebo/gpu.h>
24 #include <libplacebo/renderer.h>
25 
26 PL_API_BEGIN
27 
28 // This file contains a utility function to assist in uploading data from host
29 // memory to a texture. In particular, the texture will be suitable for use as
30 // a `pl_plane`.
31 
32 // Description of the host representation of an image plane
33 struct pl_plane_data {
34     enum pl_fmt_type type;  // meaning of the data (must not be UINT or SINT)
35     int width, height;      // dimensions of the plane
36     int component_size[4];  // size in bits of each coordinate
37     int component_pad[4];   // ignored bits preceding each component
38     int component_map[4];   // semantic meaning of each component (pixel order)
39     size_t pixel_stride;    // offset in bytes between pixels (required)
40     size_t row_stride;      // offset in bytes between rows (optional)
41 
42     // Similar to `pl_tex_transfer_params`, you can either upload from a raw
43     // pointer address, or a buffer + offset. Again, the use of these two
44     // mechanisms is mutually exclusive.
45     //
46     // 1. Uploading from host memory
47     const void *pixels;     // the actual data underlying this plane
48 
49     // 2. Uploading from a buffer (requires `pl_gpu_limits.buf_transfer`)
50     pl_buf buf;             // the buffer to use
51     size_t buf_offset;      // offset of data within buffer, must be a
52                             // multiple of `pixel_stride` as well as of 4
53 
54     // Similar to `pl_tex_transfer_params.callback`, this allows turning the
55     // upload of a plane into an asynchronous upload. The same notes apply.
56     void (*callback)(void *priv);
57     void *priv;
58 
59     // Note: When using this together with `pl_frame`, there is some amount of
60     // overlap between `component_pad` and `pl_color_repr.bits`. Some key
61     // differences between the two:
62     //
63     // - the bits from `component_pad` are ignored; whereas the superfluous bits
64     //   in a `pl_color_repr` must be 0.
65     // - the `component_pad` exists to align the component size and placement
66     //   with the capabilities of GPUs; the `pl_color_repr` exists to control
67     //   the semantics of the color samples on a finer granularity.
68     // - the `pl_color_repr` applies to the color sample as a whole, and
69     //   therefore applies to all planes; the `component_pad` can be different
70     //   for each plane.
71     // - `component_pad` interacts with float textures by moving the actual
72     //   float in memory. `pl_color_repr` interacts with float data as if
73     //   the float was converted from an integer under full range semantics.
74     //
75     // To help establish the motivating difference, a typical example of a use
76     // case would be yuv420p10. Since 10-bit GPU texture support is limited,
77     // and working with non-byte-aligned pixels is awkward in general, the
78     // convention is to represent yuv420p10 as 16-bit samples with either the
79     // high or low bits set to 0. In this scenario, the `component_size` of the
80     // `pl_plane_repr` and `pl_bit_encoding.sample_depth` would be 16, while
81     // the `pl_bit_encoding.color_depth` would be 10 (and additionally, the
82     // `pl_bit_encoding.bit_shift` would be either 0 or  6, depending on
83     // whether the low or the high bits are used).
84     //
85     // On the contrary, something like a packed, 8-bit XBGR format (where the
86     // X bits are ignored and may contain garbage) would set `component_pad[0]`
87     // to 8, and the component_size[0:2] (respectively) to 8 as well.
88     //
89     // As a general rule of thumb, for maximum compatibility, you should try
90     // and align component_size/component_pad to multiples of 8 and explicitly
91     // clear any remaining superfluous bits (+ use `pl_color_repr.bits` to
92     // ensure they're decoded correctly). You should also try to align the
93     // `pixel_stride` to a power of two.
94 };
95 
96 // Fills in the `component_size`, `component_pad` and `component_map` fields
97 // based on the supplied mask for each component (in semantic order, i.e.
98 // RGBA). Each element of `mask` must have a contiguous range of set bits.
99 void pl_plane_data_from_mask(struct pl_plane_data *data, uint64_t mask[4]);
100 
101 // Helper function to take a `pl_plane_data` struct and try and improve its
102 // alignment to make it more likely to correspond to a real `pl_fmt`. It does
103 // this by attempting to round each component up to the nearest byte boundary.
104 // This relies on the assumption (true in practice) that superfluous bits of
105 // byte-misaligned formats are explicitly set to 0.
106 //
107 // The resulting shift must be consistent across all components, in which case
108 // it's returned in `out_bits`. If no alignment was possible, `out_bits` is set
109 // to {0}, and this function returns false.
110 bool pl_plane_data_align(struct pl_plane_data *data, struct pl_bit_encoding *out_bits);
111 
112 // Helper function to find a suitable `pl_fmt` based on a pl_plane_data's
113 // requirements. This is called internally by `pl_upload_plane`, but it's
114 // exposed to users both as a convenience and so they may pre-emptively check
115 // if a format would be supported without actually having to attempt the upload.
116 pl_fmt pl_plane_find_fmt(pl_gpu gpu, int out_map[4], const struct pl_plane_data *data);
117 
118 // Upload an image plane to a texture, and output the resulting `pl_plane`
119 // struct to `out_plane` (optional). `tex` must be a valid pointer to a texture
120 // (or NULL), which will be destroyed and reinitialized if it does not already
121 // exist or is incompatible. Returns whether successful.
122 //
123 // The resulting texture is guaranteed to be `sampleable`, and it will also try
124 // and maximize compatibility with the other `pl_renderer` requirements
125 // (blittable, linear filterable, etc.).
126 //
127 // Note: `out_plane->shift_x/y` are left uninitialized, and should be set
128 // explicitly by the user.
129 bool pl_upload_plane(pl_gpu gpu, struct pl_plane *out_plane,
130                      pl_tex *tex, const struct pl_plane_data *data);
131 
132 // Like `pl_upload_plane`, but only creates an uninitialized texture object
133 // rather than actually performing an upload. This can be useful to, for
134 // example, prepare textures to be used as the target of rendering.
135 //
136 // The resulting texture is guaranteed to be `renderable`, and it will also try
137 // to maximize compatibility with the other `pl_renderer` reequirements
138 // (blittable, storable, etc.).
139 bool pl_recreate_plane(pl_gpu gpu, struct pl_plane *out_plane,
140                        pl_tex *tex, const struct pl_plane_data *data);
141 
142 PL_API_END
143 
144 #endif // LIBPLACEBO_UPLOAD_H_
145