• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SurfaceVk.h:
7 //    Defines the class interface for SurfaceVk, implementing SurfaceImpl.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
11 #define LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
12 
13 #include "common/CircularBuffer.h"
14 #include "common/vulkan/vk_headers.h"
15 #include "libANGLE/renderer/SurfaceImpl.h"
16 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
17 #include "libANGLE/renderer/vulkan/vk_helpers.h"
18 
19 namespace rx
20 {
21 class RendererVk;
22 
23 class SurfaceVk : public SurfaceImpl, public angle::ObserverInterface
24 {
25   public:
26     angle::Result getAttachmentRenderTarget(const gl::Context *context,
27                                             GLenum binding,
28                                             const gl::ImageIndex &imageIndex,
29                                             GLsizei samples,
30                                             FramebufferAttachmentRenderTarget **rtOut) override;
31 
32   protected:
33     SurfaceVk(const egl::SurfaceState &surfaceState);
34     ~SurfaceVk() override;
35 
36     // We monitor the staging buffer for changes. This handles staged data from outside this class.
37     void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
38 
39     RenderTargetVk mColorRenderTarget;
40     RenderTargetVk mDepthStencilRenderTarget;
41 };
42 
43 class OffscreenSurfaceVk : public SurfaceVk
44 {
45   public:
46     OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, RendererVk *renderer);
47     ~OffscreenSurfaceVk() override;
48 
49     egl::Error initialize(const egl::Display *display) override;
50     void destroy(const egl::Display *display) override;
51 
52     FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
53                                               const gl::FramebufferState &state) override;
54     egl::Error swap(const gl::Context *context) override;
55     egl::Error postSubBuffer(const gl::Context *context,
56                              EGLint x,
57                              EGLint y,
58                              EGLint width,
59                              EGLint height) override;
60     egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
61     egl::Error bindTexImage(const gl::Context *context,
62                             gl::Texture *texture,
63                             EGLint buffer) override;
64     egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
65     egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
66     egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
67     void setSwapInterval(EGLint interval) override;
68 
69     // width and height can change with client window resizing
70     EGLint getWidth() const override;
71     EGLint getHeight() const override;
72 
73     EGLint isPostSubBufferSupported() const override;
74     EGLint getSwapBehavior() const override;
75 
76     angle::Result initializeContents(const gl::Context *context,
77                                      const gl::ImageIndex &imageIndex) override;
78 
79     vk::ImageHelper *getColorAttachmentImage();
80 
81   protected:
82     struct AttachmentImage final : angle::NonCopyable
83     {
84         AttachmentImage(SurfaceVk *surfaceVk);
85         ~AttachmentImage();
86 
87         angle::Result initialize(DisplayVk *displayVk,
88                                  EGLint width,
89                                  EGLint height,
90                                  const vk::Format &vkFormat,
91                                  GLint samples,
92                                  bool isRobustResourceInitEnabled,
93                                  bool hasProtectedContent);
94 
95         void destroy(const egl::Display *display);
96 
97         vk::ImageHelper image;
98         vk::ImageViewHelper imageViews;
99         angle::ObserverBinding imageObserverBinding;
100     };
101 
102     virtual angle::Result initializeImpl(DisplayVk *displayVk);
103 
104     EGLint mWidth;
105     EGLint mHeight;
106 
107     AttachmentImage mColorAttachment;
108     AttachmentImage mDepthStencilAttachment;
109 };
110 
111 // Data structures used in WindowSurfaceVk
112 namespace impl
113 {
114 static constexpr size_t kSwapHistorySize = 2;
115 
116 // Old swapchain and associated present semaphores that need to be scheduled for destruction when
117 // appropriate.
118 struct SwapchainCleanupData : angle::NonCopyable
119 {
120     SwapchainCleanupData();
121     SwapchainCleanupData(SwapchainCleanupData &&other);
122     ~SwapchainCleanupData();
123 
124     void destroy(VkDevice device, vk::Recycler<vk::Semaphore> *semaphoreRecycler);
125 
126     // The swapchain to be destroyed.
127     VkSwapchainKHR swapchain = VK_NULL_HANDLE;
128     // Any present semaphores that were pending destruction at the time the swapchain was
129     // recreated will be scheduled for destruction at the same time as the swapchain.
130     std::vector<vk::Semaphore> semaphores;
131 };
132 
133 // A circular buffer per image stores the semaphores used for presenting that image.  Taking the
134 // swap history into account, only the oldest semaphore is guaranteed to be no longer in use by the
135 // presentation engine.  See doc/PresentSemaphores.md for details.
136 //
137 // Old swapchains are scheduled to be destroyed at the same time as the first semaphore used to
138 // present an image of the new swapchain.  This is to ensure that the presentation engine is no
139 // longer presenting an image from the old swapchain.
140 struct ImagePresentHistory : angle::NonCopyable
141 {
142     ImagePresentHistory();
143     ImagePresentHistory(ImagePresentHistory &&other);
144     ImagePresentHistory &operator=(ImagePresentHistory &&other);
145     ~ImagePresentHistory();
146 
147     vk::Semaphore semaphore;
148     std::vector<SwapchainCleanupData> oldSwapchains;
149 };
150 
151 // Swapchain images and their associated objects.
152 struct SwapchainImage : angle::NonCopyable
153 {
154     SwapchainImage();
155     SwapchainImage(SwapchainImage &&other);
156     ~SwapchainImage();
157 
158     vk::ImageHelper image;
159     vk::ImageViewHelper imageViews;
160     vk::Framebuffer framebuffer;
161 
162     // A circular array of semaphores used for presenting this image.
163     static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1;
164     angle::CircularBuffer<ImagePresentHistory, kPresentHistorySize> presentHistory;
165     uint64_t mFrameNumber = 0;
166 };
167 }  // namespace impl
168 
169 class WindowSurfaceVk : public SurfaceVk
170 {
171   public:
172     WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
173     ~WindowSurfaceVk() override;
174 
175     void destroy(const egl::Display *display) override;
176 
177     egl::Error initialize(const egl::Display *display) override;
178     angle::Result getAttachmentRenderTarget(const gl::Context *context,
179                                             GLenum binding,
180                                             const gl::ImageIndex &imageIndex,
181                                             GLsizei samples,
182                                             FramebufferAttachmentRenderTarget **rtOut) override;
183     FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
184                                               const gl::FramebufferState &state) override;
185     egl::Error swap(const gl::Context *context) override;
186     egl::Error swapWithDamage(const gl::Context *context,
187                               const EGLint *rects,
188                               EGLint n_rects) override;
189     egl::Error postSubBuffer(const gl::Context *context,
190                              EGLint x,
191                              EGLint y,
192                              EGLint width,
193                              EGLint height) override;
194     egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
195     egl::Error bindTexImage(const gl::Context *context,
196                             gl::Texture *texture,
197                             EGLint buffer) override;
198     egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
199     egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
200     egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
201     void setSwapInterval(EGLint interval) override;
202 
203     // width and height can change with client window resizing
204     EGLint getWidth() const override;
205     EGLint getHeight() const override;
206     EGLint getRotatedWidth() const;
207     EGLint getRotatedHeight() const;
208     // Note: windows cannot be resized on Android.  The approach requires
209     // calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR.  However, that is
210     // expensive; and there are troublesome timing issues for other parts of
211     // ANGLE (which cause test failures and crashes).  Therefore, a
212     // special-Android-only path is created just for the querying of EGL_WIDTH
213     // and EGL_HEIGHT.
214     // https://issuetracker.google.com/issues/153329980
215     egl::Error getUserWidth(const egl::Display *display, EGLint *value) const override;
216     egl::Error getUserHeight(const egl::Display *display, EGLint *value) const override;
217     angle::Result getUserExtentsImpl(DisplayVk *displayVk,
218                                      VkSurfaceCapabilitiesKHR *surfaceCaps) const;
219 
220     EGLint isPostSubBufferSupported() const override;
221     EGLint getSwapBehavior() const override;
222 
223     angle::Result initializeContents(const gl::Context *context,
224                                      const gl::ImageIndex &imageIndex) override;
225 
226     angle::Result getCurrentFramebuffer(ContextVk *context,
227                                         const vk::RenderPass &compatibleRenderPass,
228                                         vk::Framebuffer **framebufferOut);
229 
230     const vk::Semaphore *getAndResetAcquireImageSemaphore();
231 
getPreTransform()232     VkSurfaceTransformFlagBitsKHR getPreTransform() const
233     {
234         if (mEmulatedPreTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
235         {
236             return mEmulatedPreTransform;
237         }
238         return mPreTransform;
239     }
240 
241     egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
242 
243     egl::Error setRenderBuffer(EGLint renderBuffer) override;
244 
isSharedPresentMode()245     bool isSharedPresentMode() const
246     {
247         return (mSwapchainPresentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
248     }
249 
250   protected:
251     angle::Result swapImpl(const gl::Context *context,
252                            const EGLint *rects,
253                            EGLint n_rects,
254                            const void *pNextChain);
255 
256     EGLNativeWindowType mNativeWindowType;
257     VkSurfaceKHR mSurface;
258     VkSurfaceCapabilitiesKHR mSurfaceCaps;
259     VkBool32 mSupportsProtectedSwapchain;
260 
261   private:
262     virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)      = 0;
263     virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0;
264 
265     angle::Result initializeImpl(DisplayVk *displayVk);
266     angle::Result recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents);
267     angle::Result createSwapChain(vk::Context *context,
268                                   const gl::Extents &extents,
269                                   VkSwapchainKHR oldSwapchain);
270     angle::Result queryAndAdjustSurfaceCaps(ContextVk *contextVk,
271                                             VkSurfaceCapabilitiesKHR *surfaceCaps);
272     angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk, bool presentOutOfDate);
273     angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount);
274     void releaseSwapchainImages(ContextVk *contextVk);
275     void destroySwapChainImages(DisplayVk *displayVk);
276     // This method calls vkAcquireNextImageKHR() to acquire the next swapchain image.  It is called
277     // when the swapchain is initially created and when present() finds the swapchain out of date.
278     // Otherwise, it is scheduled to be called later by deferAcquireNextImage().
279     VkResult acquireNextSwapchainImage(vk::Context *context);
280     // This method is called when a swapchain image is presented.  It schedules
281     // acquireNextSwapchainImage() to be called later.
282     void deferAcquireNextImage(const gl::Context *context);
283     // Called when a swapchain image whose acquisition was deferred must be acquired.  This method
284     // will recreate the swapchain (if needed) and call the acquireNextSwapchainImage() method.
285     angle::Result doDeferredAcquireNextImage(const gl::Context *context, bool presentOutOfDate);
286     angle::Result computePresentOutOfDate(vk::Context *context,
287                                           VkResult result,
288                                           bool *presentOutOfDate);
289     angle::Result present(ContextVk *contextVk,
290                           const EGLint *rects,
291                           EGLint n_rects,
292                           const void *pNextChain,
293                           bool *presentOutOfDate);
294 
295     void updateOverlay(ContextVk *contextVk) const;
296     bool overlayHasEnabledWidget(ContextVk *contextVk) const;
297     angle::Result drawOverlay(ContextVk *contextVk, impl::SwapchainImage *image) const;
298 
299     angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut);
300 
301     bool isMultiSampled() const;
302 
303     std::vector<VkPresentModeKHR> mPresentModes;
304 
305     VkSwapchainKHR mSwapchain;
306     // Cached information used to recreate swapchains.
307     VkPresentModeKHR mSwapchainPresentMode;         // Current swapchain mode
308     VkPresentModeKHR mDesiredSwapchainPresentMode;  // Desired mode set through setSwapInterval()
309     uint32_t mMinImageCount;
310     VkSurfaceTransformFlagBitsKHR mPreTransform;
311     VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
312     VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
313 
314     // A circular buffer that stores the serial of the submission fence of the context on every
315     // swap. The CPU is throttled by waiting for the 2nd previous serial to finish.
316     angle::CircularBuffer<Serial, impl::kSwapHistorySize> mSwapHistory;
317 
318     // The previous swapchain which needs to be scheduled for destruction when appropriate.  This
319     // will be done when the first image of the current swapchain is presented.  If there were
320     // older swapchains pending destruction when the swapchain is recreated, they will accumulate
321     // and be destroyed with the previous swapchain.
322     //
323     // Note that if the user resizes the window such that the swapchain is recreated every frame,
324     // this array can go grow indefinitely.
325     std::vector<impl::SwapchainCleanupData> mOldSwapchains;
326 
327     std::vector<impl::SwapchainImage> mSwapchainImages;
328     std::vector<angle::ObserverBinding> mSwapchainImageBindings;
329     uint32_t mCurrentSwapchainImageIndex;
330 
331     // Given that the CPU is throttled after a number of swaps, there is an upper bound to the
332     // number of semaphores that are used to acquire swapchain images, and that is
333     // kSwapHistorySize+1:
334     //
335     //                    Unrelated submission in      Submission as part of
336     //                      the middle of frame            buffer swap
337     //                               |                          |
338     //                               V                          V
339     //     Frame i:     ... ANI ... QS (fence Fa) ... Wait(..) QS (Fence Fb) QP
340     //     Frame i+1:   ... ANI ... QS (fence Fc) ... Wait(..) QS (Fence Fd) QP
341     //     Frame i+2:   ... ANI ... QS (fence Fe) ... Wait(Fb) QS (Fence Ff) QP
342     //                                                 ^
343     //                                                 |
344     //                                          CPU throttling
345     //
346     // In frame i+2 (2 is kSwapHistorySize), ANGLE waits on fence Fb which means that the semaphore
347     // used for Frame i's ANI can be reused (because Fb-is-signalled implies Fa-is-signalled).
348     // Before this wait, there were three acquire semaphores in use corresponding to frames i, i+1
349     // and i+2.  Frame i+3 can reuse the semaphore of frame i.
350     angle::CircularBuffer<vk::Semaphore, impl::kSwapHistorySize + 1> mAcquireImageSemaphores;
351     // A pointer to mAcquireImageSemaphores.  This is set when an image is acquired and is waited on
352     // by the next submission (which uses this image), at which point it is reset so future
353     // submissions don't wait on it until the next acquire.
354     const vk::Semaphore *mAcquireImageSemaphore;
355 
356     // There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
357     // During window resizing when swapchains are recreated every frame, the number of in-flight
358     // present semaphores can grow indefinitely.  See doc/PresentSemaphores.md.
359     vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
360 
361     // Depth/stencil image.  Possibly multisampled.
362     vk::ImageHelper mDepthStencilImage;
363     vk::ImageViewHelper mDepthStencilImageViews;
364     angle::ObserverBinding mDepthStencilImageBinding;
365 
366     // Multisample color image, view and framebuffer, if multisampling enabled.
367     vk::ImageHelper mColorImageMS;
368     vk::ImageViewHelper mColorImageMSViews;
369     angle::ObserverBinding mColorImageMSBinding;
370     vk::Framebuffer mFramebufferMS;
371 
372     // True when acquiring the next image is deferred.
373     bool mNeedToAcquireNextSwapchainImage;
374 
375     // EGL_EXT_buffer_age: Track frame count.
376     uint64_t mFrameCount;
377 };
378 
379 }  // namespace rx
380 
381 #endif  // LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
382