Commit ab5acbd5 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: implement swapchain resizing

Vulkan allows a swapchain to be created based off of an older swapchain that's still presenting, to support seamless window resizing. The old swapchain will remain alive (though no image can be acquired from it) and automatically cleaned once no image is being presented from it. The retired swapchain can be destroyed once all operations on its images are completed. We store the old swapchain next to the serial of submission that's used for CPU throttling and defer the destroy call until after `finishToSerial` for that serial is called. Bug: angleproject:2942 Change-Id: Ic62a5a57b712ffa2b087f5fecde0dc8942194075 Reviewed-on: https://chromium-review.googlesource.com/c/1435634 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent 088e5217
......@@ -93,7 +93,8 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVKDepthStencilImageUsageFlags
: kSurfaceVKColorImageUsageFlags;
gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
gl::Extents extents(std::max(static_cast<int>(width), 1), std::max(static_cast<int>(height), 1),
1);
ANGLE_TRY(image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, 1, usage, 1, 1));
VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
......@@ -274,8 +275,11 @@ WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState,
mInstance(VK_NULL_HANDLE),
mSwapchain(VK_NULL_HANDLE),
mSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
mMinImageCount(0),
mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
mCurrentSwapchainImageIndex(0),
mCurrentSwapSerialIndex(0)
mCurrentSwapHistoryIndex(0)
{
mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageView, 0, nullptr);
}
......@@ -296,17 +300,15 @@ void WindowSurfaceVk::destroy(const egl::Display *display)
// We might not need to flush the pipe here.
(void)renderer->finish(displayVk);
mDepthStencilImage.releaseImage(renderer);
mDepthStencilImage.releaseStagingBuffer(renderer);
mDepthStencilImageView.destroy(device);
releaseSwapchainImages(renderer);
for (SwapchainImage &swapchainImage : mSwapchainImages)
for (SwapHistory &swap : mSwapHistory)
{
// Although we don't own the swapchain image handles, we need to keep our shutdown clean.
swapchainImage.image.resetImageWeakReference();
swapchainImage.image.destroy(device);
swapchainImage.imageView.destroy(device);
swapchainImage.framebuffer.destroy(device);
if (swap.swapchain != VK_NULL_HANDLE)
{
vkDestroySwapchainKHR(device, swap.swapchain, nullptr);
swap.swapchain = VK_NULL_HANDLE;
}
}
if (mSwapchain)
......@@ -401,27 +403,27 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
// - On fifo, we use max(3, minImageCount). Triple-buffering allows us to present an image,
// have one in the queue and record in another. Note: on certain configurations (windows +
// nvidia + windowed mode), we could get away with a smaller number.
uint32_t minImageCount = surfaceCaps.minImageCount;
mMinImageCount = surfaceCaps.minImageCount;
if (mSwapchainPresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR)
{
minImageCount = std::max<uint32_t>(2, minImageCount);
mMinImageCount = std::max<uint32_t>(2, mMinImageCount);
}
else if (mSwapchainPresentMode == VK_PRESENT_MODE_FIFO_KHR)
{
minImageCount = std::max<uint32_t>(3, minImageCount);
mMinImageCount = std::max<uint32_t>(3, mMinImageCount);
}
// Make sure we don't exceed maxImageCount.
if (surfaceCaps.maxImageCount > 0 && minImageCount > surfaceCaps.maxImageCount)
if (surfaceCaps.maxImageCount > 0 && mMinImageCount > surfaceCaps.maxImageCount)
{
minImageCount = surfaceCaps.maxImageCount;
mMinImageCount = surfaceCaps.maxImageCount;
}
// Default to identity transform.
VkSurfaceTransformFlagBitsKHR preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
if ((surfaceCaps.supportedTransforms & preTransform) == 0)
mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
if ((surfaceCaps.supportedTransforms & mPreTransform) == 0)
{
preTransform = surfaceCaps.currentTransform;
mPreTransform = surfaceCaps.currentTransform;
}
uint32_t surfaceFormatCount = 0;
......@@ -455,38 +457,89 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
ANGLE_VK_CHECK(displayVk, foundFormat, VK_ERROR_INITIALIZATION_FAILED);
}
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
if ((surfaceCaps.supportedCompositeAlpha & compositeAlpha) == 0)
mCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
if ((surfaceCaps.supportedCompositeAlpha & mCompositeAlpha) == 0)
{
compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
}
ANGLE_VK_CHECK(displayVk, (surfaceCaps.supportedCompositeAlpha & compositeAlpha) != 0,
ANGLE_VK_CHECK(displayVk, (surfaceCaps.supportedCompositeAlpha & mCompositeAlpha) != 0,
VK_ERROR_INITIALIZATION_FAILED);
ANGLE_TRY(recreateSwapchain(displayVk, extents, mCurrentSwapHistoryIndex));
// Get the first available swapchain iamge.
return nextSwapchainImage(displayVk);
}
angle::Result WindowSurfaceVk::recreateSwapchain(DisplayVk *displayVk,
const gl::Extents &extents,
uint32_t swapHistoryIndex)
{
RendererVk *renderer = displayVk->getRenderer();
VkDevice device = renderer->getDevice();
VkSwapchainKHR oldSwapchain = mSwapchain;
mSwapchain = VK_NULL_HANDLE;
if (oldSwapchain)
{
// Note: the old swapchain must be destroyed regardless of whether creating the new
// swapchain succeeds. We can only destroy the swapchain once rendering to all its images
// have finished. We therefore store the handle to the swapchain being destroyed in the
// swap history (alongside the serial of the last submission) so it can be destroyed once we
// wait on that serial as part of the CPU throttling.
//
// TODO(syoussefi): the spec specifically allows multiple retired swapchains to exist:
//
// > Multiple retired swapchains can be associated with the same VkSurfaceKHR through
// > multiple uses of oldSwapchain that outnumber calls to vkDestroySwapchainKHR.
//
// However, a bug in the validation layers currently forces us to limit this to one retired
// swapchain. Once the issue is resolved, the following for loop can be removed.
// http://anglebug.com/3095
for (SwapHistory &swap : mSwapHistory)
{
if (swap.swapchain != VK_NULL_HANDLE)
{
ANGLE_TRY(renderer->finishToSerial(displayVk, swap.serial));
vkDestroySwapchainKHR(renderer->getDevice(), swap.swapchain, nullptr);
swap.swapchain = VK_NULL_HANDLE;
}
}
mSwapHistory[swapHistoryIndex].swapchain = oldSwapchain;
}
releaseSwapchainImages(renderer);
const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
VkFormat nativeFormat = format.vkTextureFormat;
// We need transfer src for reading back from the backbuffer.
VkImageUsageFlags imageUsageFlags = kSurfaceVKColorImageUsageFlags;
constexpr VkImageUsageFlags kImageUsageFlags = kSurfaceVKColorImageUsageFlags;
VkSwapchainCreateInfoKHR swapchainInfo = {};
swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainInfo.flags = 0;
swapchainInfo.surface = mSurface;
swapchainInfo.minImageCount = minImageCount;
swapchainInfo.minImageCount = mMinImageCount;
swapchainInfo.imageFormat = nativeFormat;
swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swapchainInfo.imageExtent.width = width;
swapchainInfo.imageExtent.height = height;
// Note: Vulkan doesn't allow 0-width/height swapchains.
swapchainInfo.imageExtent.width = std::max(extents.width, 1);
swapchainInfo.imageExtent.height = std::max(extents.height, 1);
swapchainInfo.imageArrayLayers = 1;
swapchainInfo.imageUsage = imageUsageFlags;
swapchainInfo.imageUsage = kImageUsageFlags;
swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainInfo.queueFamilyIndexCount = 0;
swapchainInfo.pQueueFamilyIndices = nullptr;
swapchainInfo.preTransform = preTransform;
swapchainInfo.compositeAlpha = compositeAlpha;
swapchainInfo.preTransform = mPreTransform;
swapchainInfo.compositeAlpha = mCompositeAlpha;
swapchainInfo.presentMode = mSwapchainPresentMode;
swapchainInfo.clipped = VK_TRUE;
swapchainInfo.oldSwapchain = VK_NULL_HANDLE;
swapchainInfo.oldSwapchain = oldSwapchain;
VkDevice device = renderer->getDevice();
// TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old
// swapchain need to carry over to the new one. http://anglebug.com/2942
ANGLE_VK_TRY(displayVk, vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &mSwapchain));
// Intialize the swapchain image views.
......@@ -503,8 +556,16 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
transparentBlack.float32[2] = 0.0f;
transparentBlack.float32[3] = 0.0f;
// Note: we expect subsequent calls to vkGetSwapchainImagesKHR to return the same number of
// images, given that the same value for minImageCount was provided. If that's not true, then
// the swap history would need to be preserved correctly; if there are more images now, the
// circular history buffer needs to be rearranged to remain continuous, and if there are fewer
// images now, we need to finishToSerial for the part of history that doesn't fit and clean up
// the respective old swapchains.
ASSERT(mSwapHistory.size() == 0 || mSwapHistory.size() == imageCount);
mSwapchainImages.resize(imageCount);
mSwapSerials.resize(imageCount);
mSwapHistory.resize(imageCount);
for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
{
......@@ -523,9 +584,6 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
member.image.clearColor(transparentBlack, 0, 1, commandBuffer);
}
// Get the first available swapchain iamge.
ANGLE_TRY(nextSwapchainImage(displayVk));
// Initialize depth/stencil if requested.
if (mState.config->depthStencilFormat != GL_NONE)
{
......@@ -555,6 +613,73 @@ angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
return angle::Result::Continue;
}
angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(DisplayVk *displayVk,
uint32_t swapHistoryIndex,
bool presentOutOfDate)
{
// Check for window resize and recreate swapchain if necessary.
gl::Extents currentExtents;
ANGLE_TRY(getCurrentWindowSize(displayVk, &currentExtents));
if (!presentOutOfDate && currentExtents.width == getWidth() &&
currentExtents.height == getHeight())
{
return angle::Result::Continue;
}
VkSurfaceCapabilitiesKHR surfaceCaps;
const VkPhysicalDevice &physicalDevice = displayVk->getRenderer()->getPhysicalDevice();
ANGLE_VK_TRY(displayVk,
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, &surfaceCaps));
uint32_t width = surfaceCaps.currentExtent.width;
uint32_t height = surfaceCaps.currentExtent.height;
if (width != 0xFFFFFFFFu)
{
ASSERT(height != 0xFFFFFFFFu);
currentExtents.width = width;
currentExtents.height = height;
}
return recreateSwapchain(displayVk, currentExtents, swapHistoryIndex);
}
void WindowSurfaceVk::releaseSwapchainImages(RendererVk *renderer)
{
if (mDepthStencilImage.valid())
{
Serial depthStencilSerial = mDepthStencilImage.getStoredQueueSerial();
mDepthStencilImage.releaseImage(renderer);
mDepthStencilImage.releaseStagingBuffer(renderer);
if (mDepthStencilImageView.valid())
{
renderer->releaseObject(depthStencilSerial, &mDepthStencilImageView);
}
}
for (SwapchainImage &swapchainImage : mSwapchainImages)
{
Serial imageSerial = swapchainImage.image.getStoredQueueSerial();
// We don't own the swapchain image handles, so we just remove our reference to it.
swapchainImage.image.resetImageWeakReference();
swapchainImage.image.destroy(renderer->getDevice());
if (swapchainImage.imageView.valid())
{
renderer->releaseObject(imageSerial, &swapchainImage.imageView);
}
if (swapchainImage.framebuffer.valid())
{
renderer->releaseObject(imageSerial, &swapchainImage.framebuffer);
}
}
mSwapchainImages.clear();
}
FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
......@@ -582,12 +707,16 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL
{
RendererVk *renderer = displayVk->getRenderer();
// If the swapchain is not in mailbox mode, throttle the submissions. NOTE(syoussefi): this can
// be done in mailbox mode too, just currently unnecessary.
if (mSwapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR)
// Throttle the submissions to avoid getting too far ahead of the GPU.
{
TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl: Throttle CPU");
ANGLE_TRY(renderer->finishToSerial(displayVk, mSwapSerials[mCurrentSwapSerialIndex]));
SwapHistory &swap = mSwapHistory[mCurrentSwapHistoryIndex];
ANGLE_TRY(renderer->finishToSerial(displayVk, swap.serial));
if (swap.swapchain != VK_NULL_HANDLE)
{
vkDestroySwapchainKHR(renderer->getDevice(), swap.swapchain, nullptr);
swap.swapchain = VK_NULL_HANDLE;
}
}
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
......@@ -600,9 +729,11 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL
ANGLE_TRY(renderer->flush(displayVk));
// Remember the serial of the last submission.
mSwapSerials[mCurrentSwapSerialIndex++] = renderer->getLastSubmittedQueueSerial();
mCurrentSwapSerialIndex =
mCurrentSwapSerialIndex == mSwapSerials.size() ? 0 : mCurrentSwapSerialIndex;
mSwapHistory[mCurrentSwapHistoryIndex].serial = renderer->getLastSubmittedQueueSerial();
uint32_t currentSwapHistoryIndex = mCurrentSwapHistoryIndex;
++mCurrentSwapHistoryIndex;
mCurrentSwapHistoryIndex =
mCurrentSwapHistoryIndex == mSwapHistory.size() ? 0 : mCurrentSwapHistoryIndex;
// Ask the renderer what semaphore it signaled in the last flush.
const vk::Semaphore *commandsCompleteSemaphore =
......@@ -643,7 +774,17 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL
presentInfo.pNext = &presentRegions;
}
ANGLE_VK_TRY(displayVk, vkQueuePresentKHR(renderer->getQueue(), &presentInfo));
VkResult result = vkQueuePresentKHR(renderer->getQueue(), &presentInfo);
// If SUBOPTIMAL/OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
// continuing.
bool swapchainOutOfDate = result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR;
if (!swapchainOutOfDate)
{
ANGLE_VK_TRY(displayVk, result);
}
ANGLE_TRY(checkForOutOfDateSwapchain(displayVk, currentSwapHistoryIndex, swapchainOutOfDate));
{
// Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue:
......
......@@ -141,12 +141,25 @@ class WindowSurfaceVk : public SurfaceImpl
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(DisplayVk *displayVk,
const gl::Extents &extents,
uint32_t swapHistoryIndex);
angle::Result checkForOutOfDateSwapchain(DisplayVk *displayVk,
uint32_t swapHistoryIndex,
bool presentOutOfDate);
void releaseSwapchainImages(RendererVk *renderer);
angle::Result nextSwapchainImage(DisplayVk *displayVk);
angle::Result swapImpl(DisplayVk *displayVk, EGLint *rects, EGLint n_rects);
VkSwapchainKHR mSwapchain;
// Cached information used to recreate swapchains.
VkPresentModeKHR mSwapchainPresentMode;
uint32_t mMinImageCount;
VkSurfaceTransformFlagBitsKHR mPreTransform;
VkCompositeAlphaFlagBitsKHR mCompositeAlpha;
RenderTargetVk mColorRenderTarget;
RenderTargetVk mDepthStencilRenderTarget;
......@@ -167,10 +180,15 @@ class WindowSurfaceVk : public SurfaceImpl
std::vector<SwapchainImage> mSwapchainImages;
// A circular buffer, with the same size as mSwapchainImages (N), that stores the serial of the
// renderer on every swap. In FIFO present modes, the CPU is throttled by waiting for the
// Nth previous serial to finish.
std::vector<Serial> mSwapSerials;
size_t mCurrentSwapSerialIndex;
// renderer on every swap. The CPU is throttled by waiting for the Nth previous serial to
// finish. Old swapchains are scheduled to be destroyed at the same time.
struct SwapHistory
{
Serial serial;
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
};
std::vector<SwapHistory> mSwapHistory;
size_t mCurrentSwapHistoryIndex;
vk::ImageHelper mDepthStencilImage;
vk::ImageView mDepthStencilImageView;
......
......@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkAndroid::createSurfaceVk(vk::Context *context, gl::
ANGLE_VK_TRY(context, vkCreateAndroidSurfaceKHR(context->getRenderer()->getInstance(),
&createInfo, nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkAndroid::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
int32_t width = ANativeWindow_getWidth(mNativeWindowType);
int32_t height = ANativeWindow_getHeight(mNativeWindowType);
ANGLE_VK_CHECK(context, width > 0 && height > 0, VK_ERROR_INITIALIZATION_FAILED);
......
......@@ -25,6 +25,7 @@ class WindowSurfaceVkAndroid : public WindowSurfaceVk
private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
};
} // namespace rx
......
......@@ -1403,6 +1403,7 @@ void ImageHelper::init2DWeakReference(VkImage handle,
mExtents = extents;
mFormat = &format;
mSamples = samples;
mCurrentLayout = ImageLayout::Undefined;
mLayerCount = 1;
mLevelCount = 1;
......
......@@ -32,6 +32,12 @@ angle::Result WindowSurfaceVkWin32::createSurfaceVk(vk::Context *context, gl::Ex
ANGLE_VK_TRY(context, vkCreateWin32SurfaceKHR(context->getRenderer()->getInstance(),
&createInfo, nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkWin32::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
RECT rect;
ANGLE_VK_CHECK(context, GetClientRect(mNativeWindowType, &rect) == TRUE,
VK_ERROR_INITIALIZATION_FAILED);
......
......@@ -25,6 +25,7 @@ class WindowSurfaceVkWin32 : public WindowSurfaceVk
private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
};
} // namespace rx
......
......@@ -33,6 +33,12 @@ angle::Result WindowSurfaceVkXcb::createSurfaceVk(vk::Context *context, gl::Exte
ANGLE_VK_TRY(context, vkCreateXcbSurfaceKHR(context->getRenderer()->getInstance(), &createInfo,
nullptr, &mSurface));
return getCurrentWindowSize(context, extentsOut);
}
angle::Result WindowSurfaceVkXcb::getCurrentWindowSize(vk::Context *context,
gl::Extents *extentsOut)
{
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(mXcbConnection, mNativeWindowType);
xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(mXcbConnection, cookie, nullptr);
ASSERT(reply);
......
......@@ -28,6 +28,7 @@ class WindowSurfaceVkXcb : public WindowSurfaceVk
private:
angle::Result createSurfaceVk(vk::Context *context, gl::Extents *extentsOut) override;
angle::Result getCurrentWindowSize(vk::Context *context, gl::Extents *extentsOut) override;
xcb_connection_t *mXcbConnection;
};
......
......@@ -178,7 +178,6 @@
2635 WIN VULKAN : dEQP-EGL.functional.resize.surface_size.stretch_width = FAIL
2635 WIN VULKAN : dEQP-EGL.functional.wide_color.pbuffer_8888_colorspace_default = FAIL
2716 WIN VULKAN : dEQP-EGL.functional.preserve_swap.no_preserve.* = FAIL
2811 WIN VULKAN : dEQP-EGL.functional.swap_buffers_with_damage.resize* = SKIP
// Linux failures
2546 LINUX : dEQP-EGL.functional.color_clears.multi_context.gles1.rgba8888_pixmap = SKIP
......
......@@ -24,10 +24,13 @@
# include <dcomp.h>
#endif
using namespace angle;
namespace
{
class EGLSurfaceTest : public EGLTest
class EGLSurfaceTest : public EGLTest,
public ::testing::WithParamInterface<angle::PlatformParameters>
{
protected:
EGLSurfaceTest()
......@@ -88,13 +91,15 @@ class EGLSurfaceTest : public EGLTest
ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT);
}
void initializeDisplay(EGLenum platformType)
void initializeDisplay()
{
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT =
reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplayEXT"));
ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);
GLenum platformType = GetParam().getRenderer();
std::vector<EGLint> displayAttributes;
displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
displayAttributes.push_back(platformType);
......@@ -102,13 +107,8 @@ class EGLSurfaceTest : public EGLTest
displayAttributes.push_back(EGL_DONT_CARE);
displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
displayAttributes.push_back(EGL_DONT_CARE);
if (platformType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE ||
platformType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
{
displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
}
displayAttributes.push_back(EGL_NONE);
mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
......@@ -249,16 +249,12 @@ class EGLSurfaceTest : public EGLTest
// Test a surface bug where we could have two Window surfaces active
// at one time, blocking message loops. See http://crbug.com/475085
TEST_F(EGLSurfaceTest, MessageLoopBug)
TEST_P(EGLSurfaceTest, MessageLoopBug)
{
const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
// TODO(syoussefi): http://anglebug.com/3123
ANGLE_SKIP_TEST_IF(IsAndroid());
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
initializeSurfaceWithDefaultConfig();
runMessageLoopTest(EGL_NO_SURFACE, EGL_NO_CONTEXT);
......@@ -266,32 +262,24 @@ TEST_F(EGLSurfaceTest, MessageLoopBug)
// Tests the message loop bug, but with setting a second context
// instead of null.
TEST_F(EGLSurfaceTest, MessageLoopBugContext)
TEST_P(EGLSurfaceTest, MessageLoopBugContext)
{
const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
// TODO(syoussefi): http://anglebug.com/3123
ANGLE_SKIP_TEST_IF(IsAndroid());
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
initializeSurfaceWithDefaultConfig();
runMessageLoopTest(mPbufferSurface, mSecondContext);
}
// Test a bug where calling makeCurrent twice would release the surface
TEST_F(EGLSurfaceTest, MakeCurrentTwice)
TEST_P(EGLSurfaceTest, MakeCurrentTwice)
{
#if defined(ANGLE_PLATFORM_APPLE) && !defined(ANGLE_STANDALONE_BUILD)
// TODO(cwallez) Make context creation return at least an OpenGL ES 2 context on
// the Mac trybots.
std::cout << "Test skipped temporarily skipped on the Mac trybots" << std::endl;
return;
#endif
// TODO(syoussefi): http://anglebug.com/3123
ANGLE_SKIP_TEST_IF(IsAndroid());
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);
initializeDisplay();
initializeSurfaceWithDefaultConfig();
eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
......@@ -304,17 +292,18 @@ TEST_F(EGLSurfaceTest, MakeCurrentTwice)
glClear(GL_COLOR_BUFFER_BIT);
}
// Test that the D3D window surface is correctly resized after calling swapBuffers
TEST_F(EGLSurfaceTest, ResizeD3DWindow)
// Test that the window surface is correctly resized after calling swapBuffers
TEST_P(EGLSurfaceTest, ResizeWindow)
{
const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
// TODO(syoussefi): http://anglebug.com/3123
ANGLE_SKIP_TEST_IF(IsAndroid());
GLenum platform = GetParam().getRenderer();
bool platformSupportsZeroSize = platform == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE ||
platform == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
int minSize = platformSupportsZeroSize ? 0 : 1;
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
initializeSurfaceWithDefaultConfig();
initializeContext();
......@@ -327,15 +316,19 @@ TEST_F(EGLSurfaceTest, ResizeD3DWindow)
ASSERT_EGL_SUCCESS();
ASSERT_EQ(64, height); // initial size
// set window's height to 0
mOSWindow->resize(64, 0);
// set window's height to 0 (if possible) or 1
mOSWindow->resize(64, minSize);
eglSwapBuffers(mDisplay, mWindowSurface);
ASSERT_EGL_SUCCESS();
// TODO(syoussefi): the GLX implementation still reads the window size as 64x64 through
// XGetGeometry. http://anglebug.com/3122
ANGLE_SKIP_TEST_IF(IsLinux() && IsOpenGL());
eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
ASSERT_EGL_SUCCESS();
ASSERT_EQ(0, height);
ASSERT_EQ(minSize, height);
// restore window's height
mOSWindow->resize(64, 64);
......@@ -350,19 +343,13 @@ TEST_F(EGLSurfaceTest, ResizeD3DWindow)
// Test creating a surface that supports a EGLConfig with 16bit
// support GL_RGB565
TEST_F(EGLSurfaceTest, CreateWithEGLConfig5650Support)
TEST_P(EGLSurfaceTest, CreateWithEGLConfig5650Support)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
const EGLint configAttributes[] = {
EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
......@@ -385,19 +372,13 @@ TEST_F(EGLSurfaceTest, CreateWithEGLConfig5650Support)
// Test creating a surface that supports a EGLConfig with 16bit
// support GL_RGBA4
TEST_F(EGLSurfaceTest, CreateWithEGLConfig4444Support)
TEST_P(EGLSurfaceTest, CreateWithEGLConfig4444Support)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
const EGLint configAttributes[] = {
EGL_RED_SIZE, 4, EGL_GREEN_SIZE, 4, EGL_BLUE_SIZE, 4, EGL_ALPHA_SIZE, 4,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
......@@ -420,19 +401,13 @@ TEST_F(EGLSurfaceTest, CreateWithEGLConfig4444Support)
// Test creating a surface that supports a EGLConfig with 16bit
// support GL_RGB5_A1
TEST_F(EGLSurfaceTest, CreateWithEGLConfig5551Support)
TEST_P(EGLSurfaceTest, CreateWithEGLConfig5551Support)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
const EGLint configAttributes[] = {
EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 5, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 1,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
......@@ -454,19 +429,13 @@ TEST_F(EGLSurfaceTest, CreateWithEGLConfig5551Support)
}
// Test creating a surface that supports a EGLConfig without alpha support
TEST_F(EGLSurfaceTest, CreateWithEGLConfig8880Support)
TEST_P(EGLSurfaceTest, CreateWithEGLConfig8880Support)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
......@@ -487,16 +456,13 @@ TEST_F(EGLSurfaceTest, CreateWithEGLConfig8880Support)
glDeleteProgram(program);
}
TEST_F(EGLSurfaceTest, FixedSizeWindow)
TEST_P(EGLSurfaceTest, FixedSizeWindow)
{
ANGLE_SKIP_TEST_IF(
!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"));
const EGLint configAttributes[] = {
EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_SAMPLE_BUFFERS, 0, EGL_NONE};
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
ANGLE_SKIP_TEST_IF(EGLWindow::FindEGLConfig(mDisplay, configAttributes, &mConfig) == EGL_FALSE);
ANGLE_SKIP_TEST_IF(
......@@ -549,15 +515,18 @@ TEST_F(EGLSurfaceTest, FixedSizeWindow)
}
#if defined(ANGLE_ENABLE_D3D11)
class EGLSurfaceTestD3D11 : public EGLSurfaceTest
{};
// Test that rendering to an IDCompositionSurface using a pbuffer works.
TEST_F(EGLSurfaceTest, CreateDirectCompositionSurface)
TEST_P(EGLSurfaceTestD3D11, CreateDirectCompositionSurface)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
std::cout << "D3D Platform not supported in ANGLE" << std::endl;
return;
}
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLAttrib device = 0;
EGLAttrib newEglDevice = 0;
......@@ -625,7 +594,7 @@ TEST_F(EGLSurfaceTest, CreateDirectCompositionSurface)
glDeleteProgram(program);
}
TEST_F(EGLSurfaceTest, CreateSurfaceWithMSAA)
TEST_P(EGLSurfaceTestD3D11, CreateSurfaceWithMSAA)
{
if (!ANGLETest::eglDisplayExtensionEnabled(EGL_NO_DISPLAY, "EGL_ANGLE_platform_angle_d3d"))
{
......@@ -648,7 +617,7 @@ TEST_F(EGLSurfaceTest, CreateSurfaceWithMSAA)
};
// clang-format on
initializeDisplay(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
initializeDisplay();
EGLConfig config;
if (EGLWindow::FindEGLConfig(mDisplay, configAttributes, &config) == EGL_FALSE)
{
......@@ -697,4 +666,19 @@ TEST_F(EGLSurfaceTest, CreateSurfaceWithMSAA)
}
#endif // ANGLE_ENABLE_D3D11
} // namespace
} // anonymous namespace
ANGLE_INSTANTIATE_TEST(EGLSurfaceTest,
ES2_D3D9(),
ES2_D3D11(),
ES3_D3D11(),
ES2_OPENGL(),
ES3_OPENGL(),
ES2_OPENGLES(),
ES3_OPENGLES(),
ES2_VULKAN());
#if defined(ANGLE_ENABLE_D3D11)
ANGLE_INSTANTIATE_TEST(EGLSurfaceTestD3D11, ES2_D3D11(), ES3_D3D11());
#endif
......@@ -431,7 +431,7 @@ bool X11Window::resize(int width, int height)
// Wait until the window as actually been resized so that the code calling resize
// can assume the window has been resized.
const double kResizeWaitDelay = 0.2;
while (mHeight != height && mWidth != width && timer->getElapsedTime() < kResizeWaitDelay)
while ((mHeight != height || mWidth != width) && timer->getElapsedTime() < kResizeWaitDelay)
{
messageLoop();
angle::Sleep(10);
......@@ -478,6 +478,10 @@ void X11Window::signalTestEvent()
// Hijack StructureNotifyMask as we know we will be listening for it.
XSendEvent(mDisplay, mWindow, False, StructureNotifyMask, &event);
// For test events, the tests want to check that it really did arrive, and they don't wait
// long. XSync here makes sure the event is sent by the time the messageLoop() is called.
XSync(mDisplay, false);
}
void X11Window::processEvent(const XEvent &xEvent)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment