blob: 476edbd5e0d342342aab9830891e2dacfe4ced77 [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SurfaceVk.h:
// Defines the class interface for SurfaceVk, implementing SurfaceImpl.
//
#ifndef LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#define LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/SurfaceImpl.h"
#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx
{
class RendererVk;
class SurfaceVk : public SurfaceImpl
{
public:
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
protected:
SurfaceVk(const egl::SurfaceState &surfaceState);
~SurfaceVk() override;
RenderTargetVk mColorRenderTarget;
RenderTargetVk mDepthStencilRenderTarget;
};
class OffscreenSurfaceVk : public SurfaceVk
{
public:
OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, EGLint width, EGLint height);
~OffscreenSurfaceVk() override;
egl::Error initialize(const egl::Display *display) override;
void destroy(const egl::Display *display) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
egl::Error swap(const gl::Context *context) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
void setSwapInterval(EGLint interval) override;
// width and height can change with client window resizing
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
vk::ImageHelper *getColorAttachmentImage();
private:
struct AttachmentImage final : angle::NonCopyable
{
AttachmentImage();
~AttachmentImage();
angle::Result initialize(DisplayVk *displayVk,
EGLint width,
EGLint height,
const vk::Format &vkFormat,
GLint samples);
void destroy(const egl::Display *display);
vk::ImageHelper image;
vk::ImageView imageView;
};
angle::Result initializeImpl(DisplayVk *displayVk);
EGLint mWidth;
EGLint mHeight;
AttachmentImage mColorAttachment;
AttachmentImage mDepthStencilAttachment;
};
// Data structures used in WindowSurfaceVk
namespace impl
{
// The submission fence of the context used to throttle the CPU.
struct SwapHistory : angle::NonCopyable
{
SwapHistory();
SwapHistory(SwapHistory &&other) = delete;
SwapHistory &operator=(SwapHistory &&other) = delete;
~SwapHistory();
void destroy(RendererVk *renderer);
angle::Result waitFence(ContextVk *contextVk);
// Fence associated with the last submitted work to render to this swapchain image.
vk::Shared<vk::Fence> sharedFence;
};
static constexpr size_t kSwapHistorySize = 2;
// Old swapchain and associated present semaphores that need to be scheduled for destruction when
// appropriate.
struct SwapchainCleanupData : angle::NonCopyable
{
SwapchainCleanupData();
SwapchainCleanupData(SwapchainCleanupData &&other);
~SwapchainCleanupData();
void destroy(VkDevice device, vk::Recycler<vk::Semaphore> *semaphoreRecycler);
// The swapchain to be destroyed.
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
// Any present semaphores that were pending destruction at the time the swapchain was
// recreated will be scheduled for destruction at the same time as the swapchain.
std::vector<vk::Semaphore> semaphores;
};
// A circular buffer per image stores the semaphores used for presenting that image. Taking the
// swap history into account, only the oldest semaphore is guaranteed to be no longer in use by the
// presentation engine. See doc/PresentSemaphores.md for details.
//
// Old swapchains are scheduled to be destroyed at the same time as the first semaphore used to
// present an image of the new swapchain. This is to ensure that the presentation engine is no
// longer presenting an image from the old swapchain.
struct ImagePresentHistory : angle::NonCopyable
{
ImagePresentHistory();
ImagePresentHistory(ImagePresentHistory &&other);
~ImagePresentHistory();
vk::Semaphore semaphore;
std::vector<SwapchainCleanupData> oldSwapchains;
};
// Swapchain images and their associated objects.
struct SwapchainImage : angle::NonCopyable
{
SwapchainImage();
SwapchainImage(SwapchainImage &&other);
~SwapchainImage();
vk::ImageHelper image;
vk::ImageView imageView;
vk::Framebuffer framebuffer;
// A circular array of semaphores used for presenting this image.
static constexpr size_t kPresentHistorySize = kSwapHistorySize + 1;
std::array<ImagePresentHistory, kPresentHistorySize> presentHistory;
size_t currentPresentHistoryIndex = 0;
};
} // namespace impl
class WindowSurfaceVk : public SurfaceVk
{
public:
WindowSurfaceVk(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window,
EGLint width,
EGLint height);
~WindowSurfaceVk() override;
void destroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
egl::Error swap(const gl::Context *context) override;
egl::Error swapWithDamage(const gl::Context *context, EGLint *rects, EGLint n_rects) override;
egl::Error postSubBuffer(const gl::Context *context,
EGLint x,
EGLint y,
EGLint width,
EGLint height) override;
egl::Error querySurfacePointerANGLE(EGLint attribute, void **value) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
void setSwapInterval(EGLint interval) override;
// width and height can change with client window resizing
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
angle::Result getCurrentFramebuffer(vk::Context *context,
const vk::RenderPass &compatibleRenderPass,
vk::Framebuffer **framebufferOut);
vk::Semaphore getAcquireImageSemaphore();
protected:
EGLNativeWindowType mNativeWindowType;
VkSurfaceKHR mSurface;
VkInstance mInstance;
private:
virtual angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) = 0;
virtual angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) = 0;
angle::Result initializeImpl(DisplayVk *displayVk);
angle::Result recreateSwapchain(ContextVk *contextVk,
const gl::Extents &extents,
uint32_t swapHistoryIndex);
angle::Result createSwapChain(vk::Context *context,
const gl::Extents &extents,
VkSwapchainKHR oldSwapchain);
angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk,
uint32_t swapHistoryIndex,
bool presentOutOfDate);
angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount);
void releaseSwapchainImages(ContextVk *contextVk);
void destroySwapChainImages(DisplayVk *displayVk);
VkResult nextSwapchainImage(vk::Context *context);
angle::Result present(ContextVk *contextVk,
EGLint *rects,
EGLint n_rects,
bool *presentOutOfDate);
angle::Result updateAndDrawOverlay(ContextVk *contextVk, impl::SwapchainImage *image) const;
angle::Result swapImpl(const gl::Context *context, EGLint *rects, EGLint n_rects);
angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut);
bool isMultiSampled() const;
VkSurfaceCapabilitiesKHR mSurfaceCaps;
std::vector<VkPresentModeKHR> mPresentModes;
VkSwapchainKHR mSwapchain;
// Cached information used to recreate swapchains.
VkPresentModeKHR mSwapchainPresentMode; // Current swapchain mode
VkPresentModeKHR mDesiredSwapchainPresentMode; // Desired mode set through setSwapInterval()
uint32_t mMinImageCount;
VkSurfaceTransformFlagBitsKHR mPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
// A circular buffer that stores the submission fence of the context on every swap. The CPU is
// throttled by waiting for the 2nd previous serial to finish.
std::array<impl::SwapHistory, impl::kSwapHistorySize> mSwapHistory;
size_t mCurrentSwapHistoryIndex;
// The previous swapchain which needs to be scheduled for destruction when appropriate. This
// will be done when the first image of the current swapchain is presented. If there were
// older swapchains pending destruction when the swapchain is recreated, they will accumulate
// and be destroyed with the previous swapchain.
//
// Note that if the user resizes the window such that the swapchain is recreated every frame,
// this array can go grow indefinitely.
std::vector<impl::SwapchainCleanupData> mOldSwapchains;
std::vector<impl::SwapchainImage> mSwapchainImages;
vk::Semaphore mAcquireImageSemaphore;
uint32_t mCurrentSwapchainImageIndex;
vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
// Depth/stencil image. Possibly multisampled.
vk::ImageHelper mDepthStencilImage;
vk::ImageView mDepthStencilImageView;
// Multisample color image, view and framebuffer, if multisampling enabled.
vk::ImageHelper mColorImageMS;
vk::ImageView mColorImageViewMS;
vk::Framebuffer mFramebufferMS;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_SURFACEVK_H_