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