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