Commit 4ad591ed authored by Constantine Shablya's avatar Constantine Shablya Committed by Antonio Caggiano
Browse files

Vulkan: GBM surface



Add support for GBM platform window surface. Duplicate dmabuf image file
descriptor when importing it in Vulkan. Present GBM surface after
throttling submissions and flushing ANGLE context.

Simplify WindowSurfaceVk and move that part of the interface and members
related to VkSurfaceKHR and VkSwapchainKHR into another subclass.
Swapchain images remain in WindowSurfaceVk so they could be used by this
platform, even if it is not using VkSwapchainKHR.

Bug: angleproject:7217
Change-Id: I45b33533983296dbad29d9c56c9dc2fab41b9178
Signed-off-by: Constantine Shablya's avatarConstantine Shablya <constantine.shablya@collabora.com>
Signed-off-by: Antonio Caggiano's avatarAntonio Caggiano <antonio.caggiano@collabora.com>
parent 0b7e347a
......@@ -8,6 +8,10 @@ import("//build/config/dcheck_always_on.gni")
import("//build_overrides/swiftshader.gni")
import("../../../../gni/angle.gni")
if (angle_use_gbm) {
import("//build/config/linux/pkg_config.gni")
}
assert(angle_enable_vulkan)
declare_args() {
......@@ -212,7 +216,13 @@ if (angle_use_gbm) {
_vulkan_backend_sources += [
"linux/gbm/DisplayVkGbm.cpp",
"linux/gbm/DisplayVkGbm.h",
"linux/gbm/SurfaceVkGbm.cpp",
"linux/gbm/SurfaceVkGbm.h",
]
pkg_config("libdrm") {
packages = [ "libdrm" ]
}
}
if (is_fuchsia) {
......@@ -328,6 +338,7 @@ angle_source_set("angle_vulkan_backend") {
if (is_linux || is_chromeos) {
deps += [ "$angle_root/src/common/linux:angle_dma_buf" ]
if (angle_use_gbm) {
public_configs += [ ":libdrm" ]
deps += [ "//third_party/minigbm" ]
}
}
......
......@@ -3996,7 +3996,7 @@ angle::Result ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferH
}
// Use finalLayout instead of extra barrier for layout change to present
if (colorImage != nullptr)
if (colorImage != nullptr && presentMode != vk::PresentMode::GbmANGLE)
{
mRenderPassCommands->setImageOptimizeForPresent(colorImage);
}
......@@ -4032,7 +4032,8 @@ angle::Result ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferH
// Invalidate the surface. See comment in WindowSurfaceVk::doDeferredAcquireNextImage on
// why this is not done when in DEMAND_REFRESH mode.
if (presentMode != vk::PresentMode::SharedDemandRefreshKHR)
if (presentMode != vk::PresentMode::SharedDemandRefreshKHR &&
presentMode != vk::PresentMode::GbmANGLE)
{
commandBufferHelper.invalidateRenderPassColorAttachment(
mState, 0, vk::PackedAttachmentIndex(0), invalidateArea);
......
This diff is collapsed.
......@@ -20,6 +20,8 @@ namespace rx
{
class RendererVk;
VkImageUsageFlags GetSwapchainImageUsageFlags(const angle::FeaturesVk &features);
class SurfaceVk : public SurfaceImpl, public angle::ObserverInterface
{
public:
......@@ -167,6 +169,9 @@ struct SwapchainImage : angle::NonCopyable
SwapchainImage(SwapchainImage &&other);
~SwapchainImage();
void destroy(DisplayVk *displayVk, vk::Recycler<vk::Semaphore> *presentSemaphoreRecycler);
bool weakReference = false;
vk::ImageHelper image;
vk::ImageViewHelper imageViews;
vk::Framebuffer framebuffer;
......@@ -201,14 +206,8 @@ class WindowSurfaceVk : public SurfaceVk
void destroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
FramebufferImpl *createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) override;
egl::Error prepareSwap(const gl::Context *context) override;
egl::Error swap(const gl::Context *context) override;
egl::Error swapWithDamage(const gl::Context *context,
const EGLint *rects,
......@@ -225,32 +224,16 @@ class WindowSurfaceVk : public SurfaceVk
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
egl::Error getSyncValues(EGLuint64KHR *ust, EGLuint64KHR *msc, EGLuint64KHR *sbc) override;
egl::Error getMscRate(EGLint *numerator, EGLint *denominator) override;
void setSwapInterval(EGLint interval) override;
// width and height can change with client window resizing
EGLint getWidth() const override;
EGLint getHeight() const override;
EGLint getRotatedWidth() const;
EGLint getRotatedHeight() const;
// Note: windows cannot be resized on Android. The approach requires
// calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR. However, that is
// expensive; and there are troublesome timing issues for other parts of
// ANGLE (which cause test failures and crashes). Therefore, a
// special-Android-only path is created just for the querying of EGL_WIDTH
// and EGL_HEIGHT.
// https://issuetracker.google.com/issues/153329980
egl::Error getUserWidth(const egl::Display *display, EGLint *value) const override;
egl::Error getUserHeight(const egl::Display *display, EGLint *value) const override;
angle::Result getUserExtentsImpl(DisplayVk *displayVk,
VkSurfaceCapabilitiesKHR *surfaceCaps) const;
EGLint isPostSubBufferSupported() const override;
EGLint getSwapBehavior() const override;
angle::Result initializeContents(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex) override;
vk::Framebuffer &chooseFramebuffer(const SwapchainResolveMode swapchainResolveMode);
angle::Result getCurrentFramebuffer(ContextVk *context,
......@@ -259,7 +242,7 @@ class WindowSurfaceVk : public SurfaceVk
const SwapchainResolveMode swapchainResolveMode,
vk::Framebuffer **framebufferOut);
const vk::Semaphore *getAndResetAcquireImageSemaphore();
virtual const vk::Semaphore *getAndResetAcquireImageSemaphore() = 0;
VkSurfaceTransformFlagBitsKHR getPreTransform() const
{
......@@ -270,12 +253,141 @@ class WindowSurfaceVk : public SurfaceVk
return mPreTransform;
}
egl::Error setRenderBuffer(EGLint renderBuffer) override;
bool isSharedPresentMode() const
{
return (mSwapchainPresentMode == vk::PresentMode::SharedDemandRefreshKHR);
}
EGLint origin() const override;
angle::Result onSharedPresentContextFlush(const gl::Context *context);
bool hasStagedUpdates() const;
protected:
angle::Result initColor(vk::Context *context,
const VkExtent3D &vkExtents,
const vk::Format &format);
angle::Result initDepthStencil(vk::Context *context, const VkExtent3D &vkExtents);
angle::Result present(ContextVk *contextVk,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain,
bool *presentOutOfDate);
virtual angle::Result presentImpl(ContextVk *contextVk,
vk::OutsideRenderPassCommandBuffer *commandBuffer,
Serial *swapSerial,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain,
bool *presentOutOfDate) = 0;
bool isMultiSampled() const;
void releaseSwapchainImages(ContextVk *contextVk);
bool supportsPresentMode(vk::PresentMode presentMode) const;
EGLNativeWindowType mNativeWindowType;
std::vector<vk::PresentMode> mPresentModes;
// Cached information used to recreate swapchains.
vk::PresentMode mSwapchainPresentMode; // Current swapchain mode
vk::PresentMode mDesiredSwapchainPresentMode; // Desired mode set through setSwapInterval()
VkSurfaceTransformFlagBitsKHR mPreTransform;
VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
std::vector<impl::SwapchainImage> mSwapchainImages;
std::vector<angle::ObserverBinding> mSwapchainImageBindings;
uint32_t mCurrentSwapchainImageIndex;
// There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
// During window resizing when swapchains are recreated every frame, the number of in-flight
// present semaphores can grow indefinitely. See doc/PresentSemaphores.md.
vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
// Depth/stencil image. Possibly multisampled.
vk::ImageHelper mDepthStencilImage;
vk::ImageViewHelper mDepthStencilImageViews;
angle::ObserverBinding mDepthStencilImageBinding;
// Multisample color image, view and framebuffer, if multisampling enabled.
vk::ImageHelper mColorImageMS;
vk::ImageViewHelper mColorImageMSViews;
angle::ObserverBinding mColorImageMSBinding;
vk::Framebuffer mFramebufferMS;
// True when acquiring the next image is deferred.
bool mNeedToAcquireNextSwapchainImage;
// EGL_EXT_buffer_age: Track frame count.
uint64_t mFrameCount;
// EGL_KHR_partial_update
uint64_t mBufferAgeQueryFrameNumber;
private:
virtual angle::Result initializeImpl(DisplayVk *displayVk) = 0;
virtual angle::Result swapImpl(const gl::Context *context,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain) = 0;
void destroySwapChainImages(DisplayVk *displayVk);
// A circular buffer that stores the serial of the submission fence of the context on every
// swap. The CPU is throttled by waiting for the 2nd previous serial to finish.
angle::CircularBuffer<Serial, impl::kSwapHistorySize> mSwapHistory;
// GL_EXT_shader_framebuffer_fetch
FramebufferFetchMode mFramebufferFetchMode = FramebufferFetchMode::Disabled;
};
class WindowSurfaceVkSwapchain : public WindowSurfaceVk
{
public:
WindowSurfaceVkSwapchain(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
~WindowSurfaceVkSwapchain() override;
void destroy(const egl::Display *display) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
egl::Error prepareSwap(const gl::Context *context) override;
void setSwapInterval(EGLint interval) override;
// Note: windows cannot be resized on Android. The approach requires
// calling vkGetPhysicalDeviceSurfaceCapabilitiesKHR. However, that is
// expensive; and there are troublesome timing issues for other parts of
// ANGLE (which cause test failures and crashes). Therefore, a
// special-Android-only path is created just for the querying of EGL_WIDTH
// and EGL_HEIGHT.
// https://issuetracker.google.com/issues/153329980
egl::Error getUserWidth(const egl::Display *display, EGLint *value) const override;
egl::Error getUserHeight(const egl::Display *display, EGLint *value) const override;
angle::Result getUserExtentsImpl(DisplayVk *displayVk,
VkSurfaceCapabilitiesKHR *surfaceCaps) const;
angle::Result initializeContents(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex) override;
const vk::Semaphore *getAndResetAcquireImageSemaphore() override;
egl::Error setAutoRefreshEnabled(bool enabled) override;
egl::Error getBufferAge(const gl::Context *context, EGLint *age) override;
egl::Error setRenderBuffer(EGLint renderBuffer) override;
bool isSharedPresentMode() const
{
return (mSwapchainPresentMode == vk::PresentMode::SharedDemandRefreshKHR ||
......@@ -294,23 +406,18 @@ class WindowSurfaceVk : public SurfaceVk
uint8_t **bufferPtrOut,
EGLint *bufferPitchOut) override;
egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
EGLint origin() const override;
angle::Result onSharedPresentContextFlush(const gl::Context *context);
bool hasStagedUpdates() const;
protected:
angle::Result prepareSwapImpl(const gl::Context *context);
angle::Result swapImpl(const gl::Context *context,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain);
const void *pNextChain) override;
// Called when a swapchain image whose acquisition was deferred must be acquired. This method
// will recreate the swapchain (if needed) and call the acquireNextSwapchainImage() method.
angle::Result doDeferredAcquireNextImage(const gl::Context *context, bool presentOutOfDate);
EGLNativeWindowType mNativeWindowType;
VkSurfaceKHR mSurface;
VkSurfaceCapabilitiesKHR mSurfaceCaps;
VkBool32 mSupportsProtectedSwapchain;
......@@ -319,7 +426,7 @@ class WindowSurfaceVk : public SurfaceVk
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 initializeImpl(DisplayVk *displayVk) override;
angle::Result recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents);
angle::Result createSwapChain(vk::Context *context,
const gl::Extents &extents,
......@@ -328,8 +435,6 @@ class WindowSurfaceVk : public SurfaceVk
VkSurfaceCapabilitiesKHR *surfaceCaps);
angle::Result checkForOutOfDateSwapchain(ContextVk *contextVk, bool presentOutOfDate);
angle::Result resizeSwapchainImages(vk::Context *context, uint32_t imageCount);
void releaseSwapchainImages(ContextVk *contextVk);
void destroySwapChainImages(DisplayVk *displayVk);
// This method calls vkAcquireNextImageKHR() to acquire the next swapchain image. It is called
// when the swapchain is initially created and when present() finds the swapchain out of date.
// Otherwise, it is scheduled to be called later by deferAcquireNextImage().
......@@ -341,11 +446,6 @@ class WindowSurfaceVk : public SurfaceVk
angle::Result computePresentOutOfDate(vk::Context *context,
VkResult result,
bool *presentOutOfDate);
angle::Result present(ContextVk *contextVk,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain,
bool *presentOutOfDate);
void updateOverlay(ContextVk *contextVk) const;
bool overlayHasEnabledWidget(ContextVk *contextVk) const;
......@@ -353,24 +453,16 @@ class WindowSurfaceVk : public SurfaceVk
angle::Result newPresentSemaphore(vk::Context *context, vk::Semaphore *semaphoreOut);
bool isMultiSampled() const;
bool supportsPresentMode(vk::PresentMode presentMode) const;
std::vector<vk::PresentMode> mPresentModes;
angle::Result presentImpl(ContextVk *contextVk,
vk::OutsideRenderPassCommandBuffer *commandBuffer,
Serial *swapSerial,
const EGLint *rects,
EGLint n_rects,
const void *pNextChain,
bool *presentOutOfDate) override;
VkSwapchainKHR mSwapchain;
// Cached information used to recreate swapchains.
vk::PresentMode mSwapchainPresentMode; // Current swapchain mode
vk::PresentMode mDesiredSwapchainPresentMode; // Desired mode set through setSwapInterval()
uint32_t mMinImageCount;
VkSurfaceTransformFlagBitsKHR mPreTransform;
VkSurfaceTransformFlagBitsKHR mEmulatedPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
// A circular buffer that stores the serial of the submission fence of the context on every
// swap. The CPU is throttled by waiting for the 2nd previous serial to finish.
angle::CircularBuffer<Serial, impl::kSwapHistorySize> mSwapHistory;
// 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
......@@ -381,10 +473,6 @@ class WindowSurfaceVk : public SurfaceVk
// this array can go grow indefinitely.
std::vector<impl::SwapchainCleanupData> mOldSwapchains;
std::vector<impl::SwapchainImage> mSwapchainImages;
std::vector<angle::ObserverBinding> mSwapchainImageBindings;
uint32_t mCurrentSwapchainImageIndex;
// Given that the CPU is throttled after a number of swaps, there is an upper bound to the
// number of semaphores that are used to acquire swapchain images, and that is
// kSwapHistorySize+1:
......@@ -410,36 +498,8 @@ class WindowSurfaceVk : public SurfaceVk
// submissions don't wait on it until the next acquire.
const vk::Semaphore *mAcquireImageSemaphore;
// There is no direct signal from Vulkan regarding when a Present semaphore can be be reused.
// During window resizing when swapchains are recreated every frame, the number of in-flight
// present semaphores can grow indefinitely. See doc/PresentSemaphores.md.
vk::Recycler<vk::Semaphore> mPresentSemaphoreRecycler;
// Depth/stencil image. Possibly multisampled.
vk::ImageHelper mDepthStencilImage;
vk::ImageViewHelper mDepthStencilImageViews;
angle::ObserverBinding mDepthStencilImageBinding;
// Multisample color image, view and framebuffer, if multisampling enabled.
vk::ImageHelper mColorImageMS;
vk::ImageViewHelper mColorImageMSViews;
angle::ObserverBinding mColorImageMSBinding;
vk::Framebuffer mFramebufferMS;
// True when acquiring the next image is deferred.
bool mNeedToAcquireNextSwapchainImage;
// EGL_EXT_buffer_age: Track frame count.
uint64_t mFrameCount;
// EGL_KHR_lock_surface3
vk::BufferHelper mLockBufferHelper;
// EGL_KHR_partial_update
uint64_t mBufferAgeQueryFrameNumber;
// GL_EXT_shader_framebuffer_fetch
FramebufferFetchMode mFramebufferFetchMode = FramebufferFetchMode::Disabled;
};
} // namespace rx
......
......@@ -18,7 +18,7 @@ namespace rx
WindowSurfaceVkAndroid::WindowSurfaceVkAndroid(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window)
: WindowSurfaceVk(surfaceState, window)
: WindowSurfaceVkSwapchain(surfaceState, window)
{}
angle::Result WindowSurfaceVkAndroid::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)
......
......@@ -15,7 +15,7 @@
namespace rx
{
class WindowSurfaceVkAndroid : public WindowSurfaceVk
class WindowSurfaceVkAndroid : public WindowSurfaceVkSwapchain
{
public:
WindowSurfaceVkAndroid(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
......
......@@ -22,7 +22,7 @@ namespace rx
WindowSurfaceVkFuchsia::WindowSurfaceVkFuchsia(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window)
: WindowSurfaceVk(surfaceState, window)
: WindowSurfaceVkSwapchain(surfaceState, window)
{}
WindowSurfaceVkFuchsia::~WindowSurfaceVkFuchsia() {}
......
......@@ -15,7 +15,7 @@
namespace rx
{
class WindowSurfaceVkFuchsia : public WindowSurfaceVk
class WindowSurfaceVkFuchsia : public WindowSurfaceVkSwapchain
{
public:
WindowSurfaceVkFuchsia(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
......
......@@ -24,7 +24,7 @@ constexpr EGLAttrib kDefaultStreamDescriptor = static_cast<EGLAttrib>(kGgpPrimar
WindowSurfaceVkGGP::WindowSurfaceVkGGP(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window)
: WindowSurfaceVk(surfaceState, window)
: WindowSurfaceVkSwapchain(surfaceState, window)
{}
angle::Result WindowSurfaceVkGGP::createSurfaceVk(vk::Context *context, gl::Extents *extentsOut)
......
......@@ -15,7 +15,7 @@
namespace rx
{
class WindowSurfaceVkGGP : public WindowSurfaceVk
class WindowSurfaceVkGGP : public WindowSurfaceVkSwapchain
{
public:
WindowSurfaceVkGGP(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
......
......@@ -15,7 +15,7 @@ namespace rx
WindowSurfaceVkSimple::WindowSurfaceVkSimple(const egl::SurfaceState &surfaceState,
EGLNativeWindowType window)
: WindowSurfaceVk(surfaceState, window)
: WindowSurfaceVkSwapchain(surfaceState, window)
{}
WindowSurfaceVkSimple::~WindowSurfaceVkSimple() {}
......
......@@ -15,7 +15,7 @@
namespace rx
{
class WindowSurfaceVkSimple final : public WindowSurfaceVk
class WindowSurfaceVkSimple final : public WindowSurfaceVkSwapchain
{
public:
WindowSurfaceVkSimple(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
......
......@@ -13,6 +13,8 @@
#include "common/linux/dma_buf_utils.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/linux/gbm/SurfaceVkGbm.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
namespace rx
......@@ -48,11 +50,16 @@ bool DisplayVkGbm::isValidNativeWindow(EGLNativeWindowType window) const
SurfaceImpl *DisplayVkGbm::createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window)
{
return nullptr;
return new SurfaceVkGbm(state, window);
}
egl::ConfigSet DisplayVkGbm::generateConfigs()
{
if (!getRenderer()->getFeatures().supportsExternalMemoryDmaBufAndModifiers.enabled)
{
return {}; // No configuration supported
}
const std::array<GLenum, 1> kColorFormats = {GL_BGRA8_EXT};
std::vector<GLenum> depthStencilFormats(
......@@ -68,7 +75,11 @@ egl::ConfigSet DisplayVkGbm::generateConfigs()
egl_vk::GenerateConfigs(kColorFormats.data(), kColorFormats.size(),
depthStencilFormats.data(), depthStencilFormats.size(), this);
cfgSet.begin()->second.nativeVisualID = DRM_FORMAT_XRGB8888;
for (std::pair<const EGLint, egl::Config> &cfgEntry : cfgSet)
{
egl::Config &cfg = cfgEntry.second;
cfg.nativeVisualID = DRM_FORMAT_XRGB8888;
}
return cfgSet;
}
......
This diff is collapsed.
//
// Copyright 2022 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.
//
// SurfaceVkGbm.h:
// Defines the class interface for SurfaceVkGbm, implementing WindowSurfaceVk.
//
#ifndef LIBANGLE_RENDERER_VULKAN_GBM_WINDOWSURFACEVKGBM_H_
#define LIBANGLE_RENDERER_VULKAN_GBM_WINDOWSURFACEVKGBM_H_
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
#include <array>
#include <gbm.h>
struct gbm_surface;
namespace rx
{
struct SurfaceImage : angle::NonCopyable
{
SurfaceImage();
SurfaceImage(SurfaceImage &&);
SurfaceImage(struct gbm_bo *bo);
~SurfaceImage();
SurfaceImage &operator=(SurfaceImage &&other);
gbm_bo *mGbmBO = nullptr;
bool mAcquired = false;
bool mLocked = false;
};
class SurfaceVkGbm : public WindowSurfaceVk
{
public:
SurfaceVkGbm(const egl::SurfaceState &surfaceState, EGLNativeWindowType window);
~SurfaceVkGbm() override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
void setSwapInterval(EGLint interval) override;
egl::Error lockSurface(const egl::Display *display,
EGLint usageHint,
bool preservePixels,
uint8_t **bufferPtrOut,
EGLint *bufferPitchOut) override;
egl::Error unlockSurface(const egl::Display *display, bool preservePixels) override;
const vk::Semaphore *getAndResetAcquireImageSemaphore() override;
angle::Result createImages(struct gbm_device *gbmDevice,
uint32_t width,
uint32_t height,
uint32_t format,
const uint64_t *modifiers,
size_t count,
uint32_t usage);
void destroyImages();
gbm_bo *lockFrontImage();
void releaseImage(gbm_bo *bo);
bool hasFreeImages();