• 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     egl::Error lockSurface(const egl::Display *display,
82                            EGLint usageHint,
83                            bool preservePixels,
84                            uint8_t **bufferPtrOut,
85                            EGLint *bufferPitchOut) override;
86     egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
87     EGLint origin() const override;
88 
89   protected:
90     struct AttachmentImage final : angle::NonCopyable
91     {
92         AttachmentImage(SurfaceVk *surfaceVk);
93         ~AttachmentImage();
94 
95         angle::Result initialize(DisplayVk *displayVk,
96                                  EGLint width,
97                                  EGLint height,
98                                  const vk::Format &vkFormat,
99                                  GLint samples,
100                                  bool isRobustResourceInitEnabled,
101                                  bool hasProtectedContent);
102 
103         void destroy(const egl::Display *display);
104 
105         vk::ImageHelper image;
106         vk::ImageViewHelper imageViews;
107         angle::ObserverBinding imageObserverBinding;
108     };
109 
110     virtual angle::Result initializeImpl(DisplayVk *displayVk);
111 
112     EGLint mWidth;
113     EGLint mHeight;
114 
115     AttachmentImage mColorAttachment;
116     AttachmentImage mDepthStencilAttachment;
117 
118     // EGL_KHR_lock_surface3
119     vk::BufferHelper mLockBufferHelper;
120 };
121 
122 // Data structures used in WindowSurfaceVk
123 namespace impl
124 {
125 static constexpr size_t kSwapHistorySize = 2;
126 
127 // Old swapchain and associated present semaphores that need to be scheduled for destruction when
128 // appropriate.
129 struct SwapchainCleanupData : angle::NonCopyable
130 {
131     SwapchainCleanupData();
132     SwapchainCleanupData(SwapchainCleanupData &&other);
133     ~SwapchainCleanupData();
134 
135     void destroy(VkDevice device, vk::Recycler<vk::Semaphore> *semaphoreRecycler);
136 
137     // The swapchain to be destroyed.
138     VkSwapchainKHR swapchain = VK_NULL_HANDLE;
139     // Any present semaphores that were pending destruction at the time the swapchain was
140     // recreated will be scheduled for destruction at the same time as the swapchain.
141     std::vector<vk::Semaphore> semaphores;
142 };
143 
144 // A circular buffer per image stores the semaphores used for presenting that image.  Taking the
145 // swap history into account, only the oldest semaphore is guaranteed to be no longer in use by the
146 // presentation engine.  See doc/PresentSemaphores.md for details.
147 //
148 // Old swapchains are scheduled to be destroyed at the same time as the first semaphore used to
149 // present an image of the new swapchain.  This is to ensure that the presentation engine is no
150 // longer presenting an image from the old swapchain.
151 struct ImagePresentHistory : angle::NonCopyable
152 {
153     ImagePresentHistory();
154     ImagePresentHistory(ImagePresentHistory &&other);
155     ImagePresentHistory &operator=(ImagePresentHistory &&other);
156     ~ImagePresentHistory();
157 
158     vk::Semaphore semaphore;
159     std::vector<SwapchainCleanupData> oldSwapchains;
160 };
161 
162 // Swapchain images and their associated objects.
163 struct SwapchainImage : angle::NonCopyable
164 {
165     SwapchainImage();
166     SwapchainImage(SwapchainImage &&other);
167     ~SwapchainImage();
168 
169     vk::ImageHelper image;
170     vk::ImageViewHelper imageViews;
171     vk::Framebuffer framebuffer;
172     vk::Framebuffer fetchFramebuffer;
173     vk::Framebuffer framebufferResolveMS;
174 
175     // A circular array of semaphores used for presenting this image.
176     static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1;
177     angle::CircularBuffer<ImagePresentHistory, kPresentHistorySize> presentHistory;
178     uint64_t mFrameNumber = 0;
179 };
180 }  // namespace impl
181 
182 enum class FramebufferFetchMode
183 {
184     Disabled,
185     Enabled,
186 };
187 
188 enum class SwapchainResolveMode
189 {
190     Disabled,
191     Enabled,
192 };
193 
194 class WindowSurfaceVk : public SurfaceVk
195 {
196   public:
197     WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
198     ~WindowSurfaceVk() override;
199 
200     void destroy(const egl::Display *display) override;
201 
202     egl::Error initialize(const egl::Display *display) override;
203     angle::Result getAttachmentRenderTarget(const gl::Context *context,
204                                             GLenum binding,
205                                             const gl::ImageIndex &imageIndex,
206                                             GLsizei samples,
207                                             FramebufferAttachmentRenderTarget **rtOut) override;
208     FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
209                                               const gl::FramebufferState &state) override;
210     egl::Error prepareSwap(const gl::Context *context) override;
211     egl::Error swap(const gl::Context *context) override;
212     egl::Error swapWithDamage(const gl::Context *context,
213                               const EGLint *rects,
214                               EGLint n_rects) override;
215     egl::Error postSubBuffer(const gl::Context *context,
216                              EGLint x,
217                              EGLint y,
218                              EGLint width,
219                              EGLint height) override;
220     egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
221     egl::Error bindTexImage(const gl::Context *context,
222                             gl::Texture *texture,
223                             EGLint buffer) override;
224     egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
225     egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
226     egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
227     void setSwapInterval(EGLint interval) override;
228 
229     // width and height can change with client window resizing
230     EGLint getWidth() const override;
231     EGLint getHeight() const override;
232     EGLint getRotatedWidth() const;
233     EGLint getRotatedHeight() const;
234     // Note: windows cannot be resized on Android.  The approach requires
235     // calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR.  However, that is
236     // expensive; and there are troublesome timing issues for other parts of
237     // ANGLE (which cause test failures and crashes).  Therefore, a
238     // special-Android-only path is created just for the querying of EGL_WIDTH
239     // and EGL_HEIGHT.
240     // https://issuetracker.google.com/issues/153329980
241     egl::Error getUserWidth(const egl::Display *display, EGLint *value) const override;
242     egl::Error getUserHeight(const egl::Display *display, EGLint *value) const override;
243     angle::Result getUserExtentsImpl(DisplayVk *displayVk,
244                                      VkSurfaceCapabilitiesKHR *surfaceCaps) const;
245 
246     EGLint isPostSubBufferSupported() const override;
247     EGLint getSwapBehavior() const override;
248 
249     angle::Result initializeContents(const gl::Context *context,
250                                      const gl::ImageIndex &imageIndex) override;
251 
252     vk::Framebuffer &chooseFramebuffer(const SwapchainResolveMode swapchainResolveMode);
253 
254     angle::Result getCurrentFramebuffer(ContextVk *context,
255                                         FramebufferFetchMode fetchMode,
256                                         const vk::RenderPass &compatibleRenderPass,
257                                         const SwapchainResolveMode swapchainResolveMode,
258                                         vk::Framebuffer **framebufferOut);
259 
260     const vk::Semaphore *getAndResetAcquireImageSemaphore();
261 
getPreTransform()262     VkSurfaceTransformFlagBitsKHR getPreTransform() const
263     {
264         if (mEmulatedPreTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
265         {
266             return mEmulatedPreTransform;
267         }
268         return mPreTransform;
269     }
270 
271     egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
272 
273     egl::Error setRenderBuffer(EGLint renderBuffer) override;
274 
isSharedPresentMode()275     bool isSharedPresentMode() const
276     {
277         return (mSwapchainPresentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
278     }
279 
280     egl::Error lockSurface(const egl::Display *display,
281                            EGLint usageHint,
282                            bool preservePixels,
283                            uint8_t **bufferPtrOut,
284                            EGLint *bufferPitchOut) override;
285     egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
286     EGLint origin() const override;
287 
288     angle::Result onSharedPresentContextFlush(const gl::Context *context);
289 
290   protected:
291     angle::Result prepareSwapImpl(const gl::Context *context);
292     angle::Result swapImpl(const gl::Context *context,
293                            const EGLint *rects,
294                            EGLint n_rects,
295                            const void *pNextChain);
296 
297     EGLNativeWindowType mNativeWindowType;
298     VkSurfaceKHR mSurface;
299     VkSurfaceCapabilitiesKHR mSurfaceCaps;
300     VkBool32 mSupportsProtectedSwapchain;
301 
302   private:
303     virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)      = 0;
304     virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0;
305 
306     angle::Result initializeImpl(DisplayVk *displayVk);
307     angle::Result recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents);
308     angle::Result createSwapChain(vk::Context *context,
309                                   const gl::Extents &extents,
310                                   VkSwapchainKHR oldSwapchain);
311     angle::Result queryAndAdjustSurfaceCaps(ContextVk *contextVk,
312                                             VkSurfaceCapabilitiesKHR *surfaceCaps);
313     angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk, bool presentOutOfDate);
314     angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount);
315     void releaseSwapchainImages(ContextVk *contextVk);
316     void destroySwapChainImages(DisplayVk *displayVk);
317     // This method calls vkAcquireNextImageKHR() to acquire the next swapchain image.  It is called
318     // when the swapchain is initially created and when present() finds the swapchain out of date.
319     // Otherwise, it is scheduled to be called later by deferAcquireNextImage().
320     VkResult acquireNextSwapchainImage(vk::Context *context);
321     // This method is called when a swapchain image is presented.  It schedules
322     // acquireNextSwapchainImage() to be called later.
323     void deferAcquireNextImage(const gl::Context *context);
324     // Called when a swapchain image whose acquisition was deferred must be acquired.  This method
325     // will recreate the swapchain (if needed) and call the acquireNextSwapchainImage() method.
326     angle::Result doDeferredAcquireNextImage(const gl::Context *context, bool presentOutOfDate);
327     angle::Result computePresentOutOfDate(vk::Context *context,
328                                           VkResult result,
329                                           bool *presentOutOfDate);
330     angle::Result present(ContextVk *contextVk,
331                           const EGLint *rects,
332                           EGLint n_rects,
333                           const void *pNextChain,
334                           bool *presentOutOfDate);
335 
336     void updateOverlay(ContextVk *contextVk) const;
337     bool overlayHasEnabledWidget(ContextVk *contextVk) const;
338     angle::Result drawOverlay(ContextVk *contextVk, impl::SwapchainImage *image) const;
339 
340     angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut);
341 
342     bool isMultiSampled() const;
343 
344     std::vector<VkPresentModeKHR> mPresentModes;
345 
346     VkSwapchainKHR mSwapchain;
347     // Cached information used to recreate swapchains.
348     VkPresentModeKHR mSwapchainPresentMode;         // Current swapchain mode
349     VkPresentModeKHR mDesiredSwapchainPresentMode;  // Desired mode set through setSwapInterval()
350     uint32_t mMinImageCount;
351     VkSurfaceTransformFlagBitsKHR mPreTransform;
352     VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
353     VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
354 
355     // A circular buffer that stores the serial of the submission fence of the context on every
356     // swap. The CPU is throttled by waiting for the 2nd previous serial to finish.
357     angle::CircularBuffer<Serial, impl::kSwapHistorySize> mSwapHistory;
358 
359     // The previous swapchain which needs to be scheduled for destruction when appropriate.  This
360     // will be done when the first image of the current swapchain is presented.  If there were
361     // older swapchains pending destruction when the swapchain is recreated, they will accumulate
362     // and be destroyed with the previous swapchain.
363     //
364     // Note that if the user resizes the window such that the swapchain is recreated every frame,
365     // this array can go grow indefinitely.
366     std::vector<impl::SwapchainCleanupData> mOldSwapchains;
367 
368     std::vector<impl::SwapchainImage> mSwapchainImages;
369     std::vector<angle::ObserverBinding> mSwapchainImageBindings;
370     uint32_t mCurrentSwapchainImageIndex;
371 
372     // Given that the CPU is throttled after a number of swaps, there is an upper bound to the
373     // number of semaphores that are used to acquire swapchain images, and that is
374     // kSwapHistorySize+1:
375     //
376     //                    Unrelated submission in      Submission as part of
377     //                      the middle of frame            buffer swap
378     //                               |                          |
379     //                               V                          V
380     //     Frame i:     ... ANI ... QS (fence Fa) ... Wait(..) QS (Fence Fb) QP
381     //     Frame i+1:   ... ANI ... QS (fence Fc) ... Wait(..) QS (Fence Fd) QP
382     //     Frame i+2:   ... ANI ... QS (fence Fe) ... Wait(Fb) QS (Fence Ff) QP
383     //                                                 ^
384     //                                                 |
385     //                                          CPU throttling
386     //
387     // In frame i+2 (2 is kSwapHistorySize), ANGLE waits on fence Fb which means that the semaphore
388     // used for Frame i's ANI can be reused (because Fb-is-signalled implies Fa-is-signalled).
389     // Before this wait, there were three acquire semaphores in use corresponding to frames i, i+1
390     // and i+2.  Frame i+3 can reuse the semaphore of frame i.
391     angle::CircularBuffer<vk::Semaphore, impl::kSwapHistorySize + 1> mAcquireImageSemaphores;
392     // A pointer to mAcquireImageSemaphores.  This is set when an image is acquired and is waited on
393     // by the next submission (which uses this image), at which point it is reset so future
394     // submissions don't wait on it until the next acquire.
395     const vk::Semaphore *mAcquireImageSemaphore;
396 
397     // There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
398     // During window resizing when swapchains are recreated every frame, the number of in-flight
399     // present semaphores can grow indefinitely.  See doc/PresentSemaphores.md.
400     vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
401 
402     // Depth/stencil image.  Possibly multisampled.
403     vk::ImageHelper mDepthStencilImage;
404     vk::ImageViewHelper mDepthStencilImageViews;
405     angle::ObserverBinding mDepthStencilImageBinding;
406 
407     // Multisample color image, view and framebuffer, if multisampling enabled.
408     vk::ImageHelper mColorImageMS;
409     vk::ImageViewHelper mColorImageMSViews;
410     angle::ObserverBinding mColorImageMSBinding;
411     vk::Framebuffer mFramebufferMS;
412 
413     // True when acquiring the next image is deferred.
414     bool mNeedToAcquireNextSwapchainImage;
415 
416     // EGL_EXT_buffer_age: Track frame count.
417     uint64_t mFrameCount;
418 
419     // EGL_KHR_lock_surface3
420     vk::BufferHelper mLockBufferHelper;
421 
422     // EGL_KHR_partial_update
423     uint64_t mBufferAgeQueryFrameNumber;
424 
425     // GL_EXT_shader_framebuffer_fetch
426     FramebufferFetchMode mFramebufferFetchMode = FramebufferFetchMode::Disabled;
427 };
428 
429 }  // namespace rx
430 
431 #endif  // LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
432