1 /// Presentation module
2 module gfx.graal.presentation;
3 
4 import core.time : Duration;
5 
6 import gfx.core.rc;
7 import gfx.graal.format;
8 import gfx.graal.image;
9 import gfx.graal.sync;
10 
11 import std.typecons : Tuple;
12 
13 /// Surface capabilities
14 /// See_Also: PhysicalDevice.surfaceCaps
15 struct SurfaceCaps
16 {
17     // TODO: currentSize
18     /// Minimum number of images necessary in a swapchain created for the
19     /// surface these caps where queried for.
20     uint minImages;
21     /// Maximum number of images supported by swapchains created for the surface
22     /// these caps where queried for.
23     uint maxImages;
24     /// Minimum size of the surface
25     uint[2] minSize;
26     /// Maximum size of the surface
27     uint[2] maxSize;
28     /// Maximum number of array layers for this surface. At least one.
29     uint maxLayers;
30     /// Possible usages bits of the images of swapchains created for this image.
31     /// At least `ImageUsage.colorAttachment` is included.
32     ImageUsage usage;
33     /// Supported composition mode for the surface.
34     /// At least one bit is always included. Opaque composition is always
35     /// feasible by having no alpha channel or with alpha channel equals to 1.0.
36     CompositeAlpha supportedAlpha;
37 }
38 
39 /// Composition mode for a presentation engine
40 enum CompositeAlpha {
41     /// The alpha channel of presented surface is discarded and no composition
42     /// is performed.
43     opaque          = 0x01,
44     /// Composition is enabled and the color channels of presented surface are
45     /// treated as pre-multiplied by the alpha channel.
46     preMultiplied   = 0x02,
47     /// Composition is enabled and the color channels of presented surface must
48     /// multiplied by the alpha channel by the presentation engine.
49     postMultiplied  = 0x04,
50     /// The Graal implementation has no clue on how the compositor will
51     /// treat the alpha channel.
52     inherit         = 0x08,
53 }
54 
55 /// PresentMode is the algorithm driving a swapchain
56 enum PresentMode
57 {
58     /// Image is presented immediately, without waiting for V-blank.
59     /// This mode may cause tearing.
60     immediate,
61     /// First-in, first-out. The presentation engine waits for the next V-blank
62     /// to present image, such as tearing cannot be observed. Images are
63     /// appended at the end of an internal queue and the images are retrieved at
64     /// the beginning of the queue at each V-Blank. This mode is always
65     /// available, and should be used for steady throughput of presentation.
66     fifo,
67     /// This is similar to fifo, with the exception that the internal queue
68     /// has only one entry, such as if an image is waiting to be presented,
69     /// and another comes before V-blank, the new image replaces the previous
70     /// one, such as only the latest image is presented. Tearing cannot be
71     /// observed. This mode can increase reactivity of application.
72     mailbox,
73 }
74 
75 /// Handle to a native surface
76 interface Surface : IAtomicRefCounted
77 {}
78 
79 /// Result of Image acquisition from a Swapchain.
80 /// See_Also: Swapchain.acquireNextImage
81 struct ImageAcquisition
82 {
83     /// An Image Acquisition can have one of the 4 following states.
84     enum State : uint
85     {
86         /// The image could be acquired in optimal condition
87         ok          = 0x00000000,
88         /// An image could be acquired but its use is suboptimal.
89         /// This is an indication that the swapchain should be re-generated when
90         /// practicable. This can happen e.g. if the window is being resized but
91         /// the presentation engine is able to scale the image to the surface.
92         suboptimal  = 0x01000000,
93         /// The swapchain could is out of date and MUST be re-generated.
94         /// This can happen for example during resize of the window behind
95         /// the swapchain's surface, or if the window properties have changed
96         /// in some way.
97         outOfDate   = 0x02000000,
98         /// Swapchain.acquireNextImage timed-out, or was called with null
99         /// timeout and no image was ready.
100         notReady    = 0x03000000,
101 
102         /// Value used to mask out the index from the state.
103         mask        = 0xff000000,
104     }
105 
106     /// Make an ImageAcquisition in OK state with the given image index.
107     static ImageAcquisition makeOk(uint index)
108     {
109         assert(indexValid(index));
110         return ImageAcquisition(index);
111     }
112 
113     /// Make an ImageAcquisition in Suboptimal state with the given image index.
114     static ImageAcquisition makeSuboptimal(uint index)
115     {
116         assert(indexValid(index));
117         return ImageAcquisition(cast(uint)State.suboptimal | index);
118     }
119 
120     /// Make an ImageAcquisition in out-of-date state.
121     static ImageAcquisition makeOutOfDate()
122     {
123         return ImageAcquisition(cast(uint)State.outOfDate);
124     }
125 
126     /// Make an ImageAcquisition in notReady state.
127     static ImageAcquisition makeNotReady()
128     {
129         return ImageAcquisition(cast(uint)State.notReady);
130     }
131 
132     /// Get the state of the acquisition
133     @property State state() const
134     {
135         return cast(State)(rep & State.mask);
136     }
137 
138     /// Get the index of the acquired image
139     @property uint index() const
140     in (!outOfDate)
141     {
142         return rep & ~State.mask;
143     }
144 
145     /// Whether the acquisition is in OK state
146     @property bool ok() const
147     {
148         return state == State.ok;
149     }
150 
151     /// Whether the acquisition is in suboptimal state
152     @property bool suboptimal() const
153     {
154         return state == State.suboptimal;
155     }
156 
157     /// Whether the acquisition is in out-of-date state
158     @property bool outOfDate() const
159     {
160         return state == State.outOfDate;
161     }
162 
163     /// Whether the acquisition is in not-ready state
164     @property bool notReady() const
165     {
166         return state == State.notReady;
167     }
168 
169     /// Whether an image could be acquired
170     @property bool hasIndex() const
171     {
172         return ok || suboptimal;
173     }
174 
175     /// Whether the Swapchain should be reconstructed
176     @property bool swapchainNeedsRebuild() const
177     {
178         return suboptimal || outOfDate;
179     }
180 
181     private uint rep;
182 
183     private this (uint rep) { this.rep = rep; }
184 
185     private static bool indexValid(in uint index)
186     {
187         return (index & cast(uint)State.mask) == 0;
188     }
189 }
190 
191 /// Handle to a swapchain engine
192 interface Swapchain : IAtomicRefCounted
193 {
194     import gfx.graal.device : Device;
195     import core.time : dur;
196 
197     /// Get the parent device
198     @property Device device();
199 
200     /// Get the Surface that this swapchain is bound to.
201     @property Surface surface();
202 
203     /// The image format of this swapchain
204     @property Format format();
205 
206     /// Get the list of images owned by this swapchain.
207     /// The index of each image is meaningful and is often used to reference
208     /// the image (such as the index returned by acquireNextImage)
209     @property ImageBase[] images();
210 
211     /// Acquire the next image in the swapchain. This function may block until
212     /// the next image is available.
213     /// Params:
214     ///     semaphore   = A semaphore that is signaled when the image is
215     ///                   ready to be written to. Use it to synchronize with
216     ///                   the first submission that will write to the image.
217     ///     timeout     = The maximum time to wait until the call returns.
218     ///                   Use negative timeout to specify infinite waiting time.
219     ///                   Use null timeout to specify no wait at all.
220     /// Returns: ImageAcquisition representing the result of the operation.
221     /// See_Also: ImageAcquisition
222     ImageAcquisition acquireNextImage(Semaphore semaphore,
223                                       Duration timeout=dur!"seconds"(-1));
224 }