• 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/SimpleMutex.h"
15 #include "common/vulkan/vk_headers.h"
16 #include "libANGLE/renderer/SurfaceImpl.h"
17 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
18 #include "libANGLE/renderer/vulkan/vk_helpers.h"
19 
20 namespace rx
21 {
22 class SurfaceVk : public SurfaceImpl, public angle::ObserverInterface, public vk::Resource
23 {
24   public:
25     angle::Result getAttachmentRenderTarget(const gl::Context *context,
26                                             GLenum binding,
27                                             const gl::ImageIndex &imageIndex,
28                                             GLsizei samples,
29                                             FramebufferAttachmentRenderTarget **rtOut) override;
30 
31   protected:
32     SurfaceVk(const egl::SurfaceState &surfaceState);
33     ~SurfaceVk() override;
34 
35     void destroy(const egl::Display *display) override;
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     // width and height can change with client window resizing
40     EGLint getWidth() const override;
41     EGLint getHeight() const override;
42 
43     EGLint mWidth;
44     EGLint mHeight;
45 
46     RenderTargetVk mColorRenderTarget;
47     RenderTargetVk mDepthStencilRenderTarget;
48 };
49 
50 class OffscreenSurfaceVk : public SurfaceVk
51 {
52   public:
53     OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, vk::Renderer *renderer);
54     ~OffscreenSurfaceVk() override;
55 
56     egl::Error initialize(const egl::Display *display) override;
57     void destroy(const egl::Display *display) override;
58 
59     egl::Error unMakeCurrent(const gl::Context *context) override;
getColorImage()60     const vk::ImageHelper *getColorImage() const { return &mColorAttachment.image; }
61 
62     egl::Error swap(const gl::Context *context, SurfaceSwapFeedback *feedback) override;
63     egl::Error postSubBuffer(const gl::Context *context,
64                              EGLint x,
65                              EGLint y,
66                              EGLint width,
67                              EGLint height) override;
68     egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
69     egl::Error bindTexImage(const gl::Context *context,
70                             gl::Texture *texture,
71                             EGLint buffer) override;
72     egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
73     egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
74     egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
75     void setSwapInterval(const egl::Display *display, EGLint interval) override;
76 
77     EGLint isPostSubBufferSupported() const override;
78     EGLint getSwapBehavior() const override;
79 
80     angle::Result initializeContents(const gl::Context *context,
81                                      GLenum binding,
82                                      const gl::ImageIndex &imageIndex) override;
83 
84     vk::ImageHelper *getColorAttachmentImage();
85 
86     egl::Error lockSurface(const egl::Display *display,
87                            EGLint usageHint,
88                            bool preservePixels,
89                            uint8_t **bufferPtrOut,
90                            EGLint *bufferPitchOut) override;
91     egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
92     EGLint origin() const override;
93 
94     egl::Error attachToFramebuffer(const gl::Context *context,
95                                    gl::Framebuffer *framebuffer) override;
96     egl::Error detachFromFramebuffer(const gl::Context *context,
97                                      gl::Framebuffer *framebuffer) override;
98 
99   protected:
100     struct AttachmentImage final : angle::NonCopyable
101     {
102         AttachmentImage(SurfaceVk *surfaceVk);
103         ~AttachmentImage();
104 
105         angle::Result initialize(DisplayVk *displayVk,
106                                  EGLint width,
107                                  EGLint height,
108                                  const vk::Format &vkFormat,
109                                  GLint samples,
110                                  bool isRobustResourceInitEnabled,
111                                  bool hasProtectedContent);
112 
113         void destroy(const egl::Display *display);
114 
115         vk::ImageHelper image;
116         vk::ImageViewHelper imageViews;
117         angle::ObserverBinding imageObserverBinding;
118     };
119 
120     virtual angle::Result initializeImpl(DisplayVk *displayVk);
121 
122     AttachmentImage mColorAttachment;
123     AttachmentImage mDepthStencilAttachment;
124 
125     // EGL_KHR_lock_surface3
126     vk::BufferHelper mLockBufferHelper;
127 };
128 
129 // Data structures used in WindowSurfaceVk
130 namespace impl
131 {
132 static constexpr size_t kSwapHistorySize = 2;
133 
134 // Old swapchain and associated present fences/semaphores that need to be scheduled for
135 // recycling/destruction when appropriate.
136 struct SwapchainCleanupData : angle::NonCopyable
137 {
138     SwapchainCleanupData();
139     SwapchainCleanupData(SwapchainCleanupData &&other);
140     ~SwapchainCleanupData();
141 
142     // Fences must not be empty (VK_EXT_swapchain_maintenance1 is supported).
143     VkResult getFencesStatus(VkDevice device) const;
144     // Waits fences if any. Use before force destroying the swapchain.
145     void waitFences(VkDevice device, uint64_t timeout) const;
146     void destroy(VkDevice device,
147                  vk::Recycler<vk::Fence> *fenceRecycler,
148                  vk::Recycler<vk::Semaphore> *semaphoreRecycler);
149 
150     // The swapchain to be destroyed.
151     VkSwapchainKHR swapchain = VK_NULL_HANDLE;
152     // Any present fences/semaphores that were pending recycle at the time the swapchain was
153     // recreated will be scheduled for recycling at the same time as the swapchain's destruction.
154     // fences must be in the present operation order.
155     std::vector<vk::Fence> fences;
156     std::vector<vk::Semaphore> semaphores;
157 };
158 
159 // Each present operation is associated with a wait semaphore.  To know when that semaphore can be
160 // recycled, a swapSerial is used.  When that swapSerial is finished, the semaphore used in the
161 // previous present operation involving imageIndex can be recycled.  See doc/PresentSemaphores.md
162 // for details.
163 // When VK_EXT_swapchain_maintenance1 is supported, present fence is used instead of the swapSerial.
164 //
165 // Old swapchains are scheduled to be destroyed at the same time as the last wait semaphore used to
166 // present an image to the old swapchains can be recycled (only relevant when
167 // VK_EXT_swapchain_maintenance1 is not supported).
168 struct ImagePresentOperation : angle::NonCopyable
169 {
170     ImagePresentOperation();
171     ImagePresentOperation(ImagePresentOperation &&other);
172     ImagePresentOperation &operator=(ImagePresentOperation &&other);
173     ~ImagePresentOperation();
174 
175     void destroy(VkDevice device,
176                  vk::Recycler<vk::Fence> *fenceRecycler,
177                  vk::Recycler<vk::Semaphore> *semaphoreRecycler);
178 
179     // fence is only used when VK_EXT_swapchain_maintenance1 is supported.
180     vk::Fence fence;
181     vk::Semaphore semaphore;
182 
183     // Below members only relevant when VK_EXT_swapchain_maintenance1 is not supported.
184     // Used to associate a swapSerial with the previous present operation of the image.
185     uint32_t imageIndex;
186     QueueSerial queueSerial;
187     std::deque<SwapchainCleanupData> oldSwapchains;
188 };
189 
190 // Swapchain images and their associated objects.
191 struct SwapchainImage : angle::NonCopyable
192 {
193     SwapchainImage();
194     SwapchainImage(SwapchainImage &&other);
195     ~SwapchainImage();
196 
197     std::unique_ptr<vk::ImageHelper> image;
198     vk::ImageViewHelper imageViews;
199     vk::Framebuffer framebuffer;
200     vk::Framebuffer fetchFramebuffer;
201 
202     uint64_t frameNumber = 0;
203 };
204 
205 enum class ImageAcquireState
206 {
207     Unacquired,
208     NeedToProcessResult,
209     Ready,
210 };
211 
212 // Associated data for a call to vkAcquireNextImageKHR without necessarily holding the share group
213 // and global locks but ONLY from a thread where Surface is current.
214 struct UnlockedAcquireData : angle::NonCopyable
215 {
216     // Given that the CPU is throttled after a number of swaps, there is an upper bound to the
217     // number of semaphores that are used to acquire swapchain images, and that is
218     // kSwapHistorySize+1:
219     //
220     //             Unrelated submission in     Submission as part of
221     //               the middle of frame          buffer swap
222     //                              |                 |
223     //                              V                 V
224     //     Frame i:     ... ANI ... QS (fence Fa) ... QS (Fence Fb) QP Wait(..)
225     //     Frame i+1:   ... ANI ... QS (fence Fc) ... QS (Fence Fd) QP Wait(..) <--\
226     //     Frame i+2:   ... ANI ... QS (fence Fe) ... QS (Fence Ff) QP Wait(Fb)    |
227     //                                                                  ^          |
228     //                                                                  |          |
229     //                                                           CPU throttling    |
230     //                                                                             |
231     //                               Note: app should throttle itself here (equivalent of Wait(Fb))
232     //
233     // In frame i+2 (2 is kSwapHistorySize), ANGLE waits on fence Fb which means that the semaphore
234     // used for Frame i's ANI can be reused (because Fb-is-signalled implies Fa-is-signalled).
235     // Before this wait, there were three acquire semaphores in use corresponding to frames i, i+1
236     // and i+2.  Frame i+3 can reuse the semaphore of frame i.
237     angle::CircularBuffer<vk::Semaphore, impl::kSwapHistorySize + 1> acquireImageSemaphores;
238 };
239 
240 struct UnlockedAcquireResult : angle::NonCopyable
241 {
242     // The result of the call to vkAcquireNextImageKHR.
243     VkResult result = VK_SUCCESS;
244 
245     // Semaphore to signal.
246     VkSemaphore acquireSemaphore = VK_NULL_HANDLE;
247 
248     // Image index that was acquired
249     uint32_t imageIndex = std::numeric_limits<uint32_t>::max();
250 };
251 
252 struct ImageAcquireOperation : angle::NonCopyable
253 {
254     // Initially image needs to be acquired.
255     ImageAcquireState state = ImageAcquireState::Unacquired;
256 
257     // No synchronization is necessary when making the vkAcquireNextImageKHR call since it is ONLY
258     // possible on a thread where Surface is current.
259     UnlockedAcquireData unlockedAcquireData;
260     UnlockedAcquireResult unlockedAcquireResult;
261 };
262 }  // namespace impl
263 
264 class WindowSurfaceVk : public SurfaceVk
265 {
266   public:
267     WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
268     ~WindowSurfaceVk() override;
269 
270     void destroy(const egl::Display *display) override;
271 
272     egl::Error initialize(const egl::Display *display) override;
273 
274     egl::Error unMakeCurrent(const gl::Context *context) override;
275 
276     angle::Result getAttachmentRenderTarget(const gl::Context *context,
277                                             GLenum binding,
278                                             const gl::ImageIndex &imageIndex,
279                                             GLsizei samples,
280                                             FramebufferAttachmentRenderTarget **rtOut) override;
281     egl::Error prepareSwap(const gl::Context *context) override;
282     egl::Error swap(const gl::Context *context, SurfaceSwapFeedback *feedback) override;
283     egl::Error swapWithDamage(const gl::Context *context,
284                               const EGLint *rects,
285                               EGLint n_rects,
286                               SurfaceSwapFeedback *feedback) override;
287     egl::Error postSubBuffer(const gl::Context *context,
288                              EGLint x,
289                              EGLint y,
290                              EGLint width,
291                              EGLint height) override;
292     egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
293     egl::Error bindTexImage(const gl::Context *context,
294                             gl::Texture *texture,
295                             EGLint buffer) override;
296     egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
297     egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
298     egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
299     void setSwapInterval(const egl::Display *display, EGLint interval) override;
300 
301     // Note: windows cannot be resized on Android.  The approach requires
302     // calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR.  However, that is
303     // expensive; and there are troublesome timing issues for other parts of
304     // ANGLE (which cause test failures and crashes).  Therefore, a
305     // special-Android-only path is created just for the querying of EGL_WIDTH
306     // and EGL_HEIGHT.
307     // https://issuetracker.google.com/issues/153329980
308     egl::Error getUserWidth(const egl::Display *display, EGLint *value) const override;
309     egl::Error getUserHeight(const egl::Display *display, EGLint *value) const override;
310     angle::Result getUserExtentsImpl(DisplayVk *displayVk,
311                                      VkSurfaceCapabilitiesKHR *surfaceCaps) const;
312 
313     EGLint isPostSubBufferSupported() const override;
314     EGLint getSwapBehavior() const override;
315 
316     angle::Result initializeContents(const gl::Context *context,
317                                      GLenum binding,
318                                      const gl::ImageIndex &imageIndex) override;
319 
320     vk::Framebuffer &chooseFramebuffer();
321 
322     angle::Result getCurrentFramebuffer(ContextVk *context,
323                                         vk::FramebufferFetchMode fetchMode,
324                                         const vk::RenderPass &compatibleRenderPass,
325                                         vk::Framebuffer *framebufferOut);
326 
getPreTransform()327     VkSurfaceTransformFlagBitsKHR getPreTransform() const
328     {
329         if (mEmulatedPreTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
330         {
331             return mEmulatedPreTransform;
332         }
333         return mPreTransform;
334     }
335 
336     egl::Error setAutoRefreshEnabled(bool enabled) override;
337 
338     egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
339 
340     egl::Error setRenderBuffer(EGLint renderBuffer) override;
341 
isSharedPresentMode()342     bool isSharedPresentMode() const { return IsSharedPresentMode(mSwapchainPresentMode); }
343 
isSharedPresentModeDesired()344     bool isSharedPresentModeDesired() const
345     {
346         return IsSharedPresentMode(getDesiredSwapchainPresentMode());
347     }
348 
349     egl::Error lockSurface(const egl::Display *display,
350                            EGLint usageHint,
351                            bool preservePixels,
352                            uint8_t **bufferPtrOut,
353                            EGLint *bufferPitchOut) override;
354     egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
355     EGLint origin() const override;
356 
357     egl::Error attachToFramebuffer(const gl::Context *context,
358                                    gl::Framebuffer *framebuffer) override;
359     egl::Error detachFromFramebuffer(const gl::Context *context,
360                                      gl::Framebuffer *framebuffer) override;
361 
362     angle::Result onSharedPresentContextFlush(ContextVk *contextVk);
363 
364     bool hasStagedUpdates() const;
365 
366     void setTimestampsEnabled(bool enabled) override;
367 
368     EGLint getCompressionRate(const egl::Display *display) const override;
369 
370   protected:
371     angle::Result swapImpl(ContextVk *contextVk,
372                            const EGLint *rects,
373                            EGLint n_rects,
374                            const void *pNextChain,
375                            SurfaceSwapFeedback *feedback);
376 
377     EGLNativeWindowType mNativeWindowType;
378     VkSurfaceKHR mSurface;
379     VkBool32 mSupportsProtectedSwapchain;
380 
381   private:
382     // Present modes that are compatible with the current mode.  If mDesiredSwapchainPresentMode is
383     // in this list, mode switch can happen without the need to recreate the swapchain.
384     // There are currently only 6 possible present modes but vector is bigger for a workaround.
385     static constexpr uint32_t kCompatiblePresentModesSize = 10;
386     using CompatiblePresentModes =
387         angle::FixedVector<VkPresentModeKHR, kCompatiblePresentModesSize>;
388 
IsSharedPresentMode(vk::PresentMode presentMode)389     static bool IsSharedPresentMode(vk::PresentMode presentMode)
390     {
391         return (presentMode == vk::PresentMode::SharedDemandRefreshKHR ||
392                 presentMode == vk::PresentMode::SharedContinuousRefreshKHR);
393     }
394 
395     virtual angle::Result createSurfaceVk(vk::ErrorContext *context)          = 0;
396     virtual angle::Result getCurrentWindowSize(vk::ErrorContext *context,
397                                                gl::Extents *extentsOut) const = 0;
398 
399     vk::PresentMode getDesiredSwapchainPresentMode() const;
400     void setDesiredSwapchainPresentMode(vk::PresentMode presentMode);
401     void setDesiredSwapInterval(EGLint interval);
402 
403     angle::Result initializeImpl(DisplayVk *displayVk, bool *anyMatchesOut);
404     void invalidateSwapchain(vk::ErrorContext *context);
405     angle::Result recreateSwapchain(vk::ErrorContext *context);
406     angle::Result createSwapChain(vk::ErrorContext *context);
407     angle::Result collectOldSwapchain(vk::ErrorContext *context, VkSwapchainKHR swapchain);
408     angle::Result queryAndAdjustSurfaceCaps(
409         vk::ErrorContext *context,
410         vk::PresentMode presentMode,
411         VkSurfaceCapabilitiesKHR *surfaceCapsOut,
412         CompatiblePresentModes *compatiblePresentModesOut) const;
413     void adjustSurfaceExtent(VkExtent2D *extent) const;
414     angle::Result checkForOutOfDateSwapchain(vk::ErrorContext *context, bool forceRecreate);
415     angle::Result resizeSwapchainImages(vk::ErrorContext *context, uint32_t imageCount);
416     void releaseSwapchainImages(vk::Renderer *renderer);
417     void destroySwapChainImages(DisplayVk *displayVk);
418     angle::Result prepareForAcquireNextSwapchainImage(vk::ErrorContext *context);
419     // Called when a swapchain image whose acquisition was deferred must be acquired.  This method
420     // will recreate the swapchain (if needed due to present returning OUT_OF_DATE, swap interval
421     // changing, surface size changing etc, by calling prepareForAcquireNextSwapchainImage()) and
422     // call the doDeferredAcquireNextImageWithUsableSwapchain() method.
423     angle::Result doDeferredAcquireNextImage(vk::ErrorContext *context);
424     // Calls acquireNextSwapchainImage() and sets up the acquired image.  On some platforms,
425     // vkAcquireNextImageKHR returns OUT_OF_DATE instead of present, so this function may still
426     // recreate the swapchain.  The main difference with doDeferredAcquireNextImage is that it does
427     // not check for surface property changes for the purposes of swapchain recreation (because
428     // that's already done by prepareForAcquireNextSwapchainImage.
429     angle::Result doDeferredAcquireNextImageWithUsableSwapchain(vk::ErrorContext *context);
430     // This method calls vkAcquireNextImageKHR() to acquire the next swapchain image or to process
431     // unlocked ANI result.  It is scheduled to be called later by deferAcquireNextImage().
432     VkResult acquireNextSwapchainImage(vk::ErrorContext *context);
433     // Process the result of vkAcquireNextImageKHR.
434     VkResult postProcessUnlockedAcquire(vk::ErrorContext *context);
435     // This method is called when a swapchain image is presented.  It schedules
436     // acquireNextSwapchainImage() to be called later.
437     void deferAcquireNextImage();
438     bool skipAcquireNextSwapchainImageForSharedPresentMode() const;
439 
440     angle::Result computePresentOutOfDate(vk::ErrorContext *context,
441                                           VkResult result,
442                                           bool *presentOutOfDate);
443     angle::Result prePresentSubmit(ContextVk *contextVk, const vk::Semaphore &presentSemaphore);
444     angle::Result recordPresentLayoutBarrierIfNecessary(ContextVk *contextVk);
445     angle::Result present(ContextVk *contextVk,
446                           const EGLint *rects,
447                           EGLint n_rects,
448                           const void *pNextChain,
449                           bool *presentOutOfDate);
450 
451     angle::Result cleanUpPresentHistory(vk::ErrorContext *context);
452     angle::Result cleanUpOldSwapchains(vk::ErrorContext *context);
453 
454     // Throttle the CPU such that application's logic and command buffer recording doesn't get more
455     // than two frame ahead of the frame being rendered (and three frames ahead of the one being
456     // presented).  This is a failsafe, as the application should ensure command buffer recording is
457     // not ahead of the frame being rendered by *one* frame.
458     angle::Result throttleCPU(vk::ErrorContext *context, const QueueSerial &currentSubmitSerial);
459 
460     void mergeImageResourceUses();
461     // Finish all GPU operations on the surface
462     angle::Result finish(vk::ErrorContext *context);
463 
464     void updateOverlay(ContextVk *contextVk) const;
465     bool overlayHasEnabledWidget(ContextVk *contextVk) const;
466     angle::Result drawOverlay(ContextVk *contextVk, impl::SwapchainImage *image) const;
467 
468     bool isMultiSampled() const;
469 
470     bool supportsPresentMode(vk::PresentMode presentMode) const;
471 
472     bool updateColorSpace(DisplayVk *displayVk);
473 
474     angle::FormatID getIntendedFormatID(vk::Renderer *renderer);
475     angle::FormatID getActualFormatID(vk::Renderer *renderer);
476 
477     bool mIsSurfaceSizedBySwapchain;
478 
479     std::vector<vk::PresentMode> mPresentModes;
480 
481     VkSwapchainKHR mSwapchain;      // Current swapchain (same as last created or NULL)
482     VkSwapchainKHR mLastSwapchain;  // Last created non retired swapchain (or NULL if retired)
483     // Cached information used to recreate swapchains.
484     vk::PresentMode mSwapchainPresentMode;                      // Current swapchain mode
485     std::atomic<vk::PresentMode> mDesiredSwapchainPresentMode;  // Desired swapchain mode
486     uint32_t mMinImageCount;
487     VkSurfaceTransformFlagBitsKHR mPreTransform;
488     VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
489     VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
490     VkColorSpaceKHR mSurfaceColorSpace;
491     VkImageCompressionFlagBitsEXT mCompressionFlags;
492     VkImageCompressionFixedRateFlagsEXT mFixedRateFlags;
493 
494     CompatiblePresentModes mCompatiblePresentModes;
495 
496     // A circular buffer that stores the serial of the submission fence of the context on every
497     // swap. The CPU is throttled by waiting for the 2nd previous serial to finish.  This should
498     // normally be a no-op, as the application should pace itself to avoid input lag, and is
499     // implemented in ANGLE as a fail safe.  Removing this throttling requires untangling it from
500     // acquire semaphore recycling (see mAcquireImageSemaphores above)
501     angle::CircularBuffer<QueueSerial, impl::kSwapHistorySize> mSwapHistory;
502 
503     // The previous swapchain which needs to be scheduled for destruction when appropriate.  This
504     // will be done when the first image of the current swapchain is presented or when fences are
505     // signaled (when VK_EXT_swapchain_maintenance1 is supported).  If there were older swapchains
506     // pending destruction when the swapchain is recreated, they will accumulate and be destroyed
507     // with the previous swapchain.
508     //
509     // Note that if the user resizes the window such that the swapchain is recreated every frame,
510     // this array can go grow indefinitely.
511     std::deque<impl::SwapchainCleanupData> mOldSwapchains;
512 
513     std::vector<impl::SwapchainImage> mSwapchainImages;
514     std::vector<angle::ObserverBinding> mSwapchainImageBindings;
515     uint32_t mCurrentSwapchainImageIndex;
516 
517     // There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
518     // During window resizing when swapchains are recreated every frame, the number of in-flight
519     // present semaphores can grow indefinitely.  See doc/PresentSemaphores.md.
520     vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
521     // Fences are associated with present semaphores to know when they can be recycled.
522     vk::Recycler<vk::Fence> mPresentFenceRecycler;
523 
524     // The presentation history, used to recycle semaphores and destroy old swapchains.
525     std::deque<impl::ImagePresentOperation> mPresentHistory;
526 
527     // Depth/stencil image.  Possibly multisampled.
528     vk::ImageHelper mDepthStencilImage;
529     vk::ImageViewHelper mDepthStencilImageViews;
530     angle::ObserverBinding mDepthStencilImageBinding;
531 
532     // Multisample color image, view and framebuffer, if multisampling enabled.
533     vk::ImageHelper mColorImageMS;
534     vk::ImageViewHelper mColorImageMSViews;
535     angle::ObserverBinding mColorImageMSBinding;
536     vk::Framebuffer mFramebufferMS;
537 
538     impl::ImageAcquireOperation mAcquireOperation;
539 
540     // EGL_EXT_buffer_age: Track frame count.
541     uint64_t mFrameCount;
542 
543     // EGL_KHR_lock_surface3
544     vk::BufferHelper mLockBufferHelper;
545 
546     // EGL_KHR_partial_update
547     uint64_t mBufferAgeQueryFrameNumber;
548 
549     // GL_EXT_shader_framebuffer_fetch
550     vk::FramebufferFetchMode mFramebufferFetchMode = vk::FramebufferFetchMode::None;
551 };
552 
553 }  // namespace rx
554 
555 #endif  // LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
556