summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/swapchain.h
blob: b53aa5c1b14beebd4144390f778672416e5c37fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * This file is part of libplacebo.
 *
 * libplacebo is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * libplacebo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBPLACEBO_SWAPCHAIN_H_
#define LIBPLACEBO_SWAPCHAIN_H_

#include <libplacebo/common.h>
#include <libplacebo/colorspace.h>
#include <libplacebo/gpu.h>

PL_API_BEGIN

// This abstraction represents a low-level interface to visible surfaces
// exposed by a graphics API (and accompanying GPU instance), allowing users to
// directly present frames to the screen (or window, typically). This is a
// sister API to gpu.h and follows the same convention w.r.t undefined behavior.
//
// Thread-safety: Safe
typedef const struct pl_swapchain_t {
    pl_log log;
    pl_gpu gpu;
} *pl_swapchain;

// Destroys this swapchain. May be used at any time, and may block until the
// completion of all outstanding rendering commands. The swapchain and any
// resources retrieved from it must not be used afterwards.
PL_API void pl_swapchain_destroy(pl_swapchain *sw);

// Returns the approximate current swapchain latency in vsyncs, or 0 if
// unknown. A latency of 1 means that `submit_frame` followed by `swap_buffers`
// will block until the just-submitted frame has finished rendering. Typical
// values are 2 or 3, which enable better pipelining by allowing the GPU to be
// processing one or two frames at the same time as the user is preparing the
// next for submission.
PL_API int pl_swapchain_latency(pl_swapchain sw);

// Update/query the swapchain size. This function performs both roles: it tries
// setting the swapchain size to the values requested by the user, and returns
// in the same variables what width/height the swapchain was actually set to -
// which may be (substantially) different from the values requested by the
// user. A value of 0 means "unknown/none" (in which case, libplacebo won't try
// updating the size - it will simply return the current state of the
// swapchain). It's also possible for libplacebo to return values of 0, such as
// in the case that the swapchain doesn't exist yet.
//
// Returns false on significant errors (e.g. dead surface). This function can
// effectively be used to probe if creating a swapchain works.
PL_API bool pl_swapchain_resize(pl_swapchain sw, int *width, int *height);

// Backwards compatibility
#define pl_swapchain_colors pl_color_space

// Inform the swapchain about the input color space. This API deliberately
// provides no feedback, because the swapchain can internally decide what to do
// with this information, including ignoring it entirely, or applying it
// asynchronously. Users must still base their rendering on the value of
// `pl_swapchain_frame.color_space`.
//
// Note: Calling this function a second time completely overrides any
// previously specified hint. So calling this on {0} or NULL resets the
// swapchain back to its initial/preferred colorspace.
//
// Note: If `csp->transfer` is a HDR transfer curve but HDR metadata is left
// unspecified, the HDR metadata defaults to `pl_hdr_metadata_hdr10`.
// Conversely, if the HDR metadata is non-empty but `csp->transfer` is left as
// PL_COLOR_TRC_UNKNOWN, then it instead defaults to PL_COLOR_TRC_PQ.
PL_API void pl_swapchain_colorspace_hint(pl_swapchain sw, const struct pl_color_space *csp);

// The struct used to hold the results of `pl_swapchain_start_frame`
struct pl_swapchain_frame {
    // A texture representing the framebuffer users should use for rendering.
    // It's guaranteed that `fbo->params.renderable` and `fbo->params.blit_dst`
    // will be true, but no other guarantees are made - not even that
    // `fbo->params.format` is a real format.
    pl_tex fbo;

    // If true, the user should assume that this framebuffer will be flipped
    // as a result of presenting it on-screen. If false, nothing special needs
    // to be done - but if true, users should flip the coordinate system of
    // the `pl_pass` that is rendering to this framebuffer.
    //
    // Note: Normally, libplacebo follows the convention that (0,0) represents
    // the top left of the image/screen. So when flipped is true, this means
    // (0,0) on this framebuffer gets displayed as the bottom left of the image.
    bool flipped;

    // Indicates the color representation this framebuffer will be interpreted
    // as by the host system / compositor / display, including the bit depth
    // and alpha handling (where available).
    struct pl_color_repr color_repr;
    struct pl_color_space color_space;
};

// Retrieve a new frame from the swapchain. Returns whether successful. It's
// worth noting that this function can fail sporadically for benign reasons,
// for example the window being invisible or inaccessible. This function may
// block until an image is available, which may be the case if the GPU is
// rendering frames significantly faster than the display can output them. It
// may also be non-blocking, so users shouldn't rely on this call alone in
// order to meter rendering speed. (Specifics depend on the underlying graphics
// API)
PL_API bool pl_swapchain_start_frame(pl_swapchain sw, struct pl_swapchain_frame *out_frame);

// Submits the previously started frame. Non-blocking. This must be issued in
// lockstep with pl_swapchain_start_frame - there is no way to start multiple
// frames and submit them out-of-order. The frames submitted this way will
// generally be made visible in a first-in first-out fashion, although
// specifics depend on the mechanism used to create the pl_swapchain. (See the
// platform-specific APIs for more info).
//
// Returns whether successful. This should normally never fail, unless the
// GPU/surface has been lost or some other critical error has occurred. The
// "started" frame is consumed even in the event of failure.
//
// Note that `start_frame` and `submit_frame` form a lock pair, i.e. trying to
// call e.g. `pl_swapchain_resize` from another thread will block until
// `pl_swapchain_submit_frame` is finished.
PL_API bool pl_swapchain_submit_frame(pl_swapchain sw);

// Performs a "buffer swap", or some generalization of the concept. In layman's
// terms, this blocks until the execution of the Nth previously submitted frame
// has been "made complete" in some sense. (The N derives from the swapchain's
// built-in latency. See `pl_swapchain_latency` for more information).
//
// Users should include this call in their rendering loops in order to make
// sure they aren't submitting rendering commands faster than the GPU can
// process them, which would potentially lead to a queue overrun or exhaust
// memory.
//
// An example loop might look like this:
//
//     while (rendering) {
//         struct pl_swapchain_frame frame;
//         bool ok = pl_swapchain_start_frame(swapchain, &frame);
//         if (!ok) {
//             /* wait some time, or decide to stop rendering */
//             continue;
//         }
//
//         /* do some rendering with frame.fbo */
//
//         ok = pl_swapchain_submit_frame(swapchain);
//         if (!ok)
//             break;
//
//         pl_swapchain_swap_buffers(swapchain);
//     }
//
// The duration this function blocks for, if at all, may be very inconsistent
// and should not be used as an authoritative source of vsync timing
// information without sufficient smoothing/filtering (and if so, the time that
// `start_frame` blocked for should also be included).
PL_API void pl_swapchain_swap_buffers(pl_swapchain sw);

PL_API_END

#endif // LIBPLACEBO_SWAPCHAIN_H_