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