Commit 26c6c4a5 by Antonio Maiorano

Fix Win32SurfaceKHR resize issues

* Fixes crash when window is resized. * Take destination pitch into account when updating the framebuffer, so we no longer get skewed renders. * Return VK_ERROR_OUT_OF_DATE_KHR when presenting if the swapchain image dimensions do not match the window surface's. Bug: b/139372840 Change-Id: I744adbf222a1d06bc9cc879e299b11b56f6dd7cf Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/37429 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Tested-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent a68a80a4
...@@ -733,6 +733,11 @@ void Image::blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) co ...@@ -733,6 +733,11 @@ void Image::blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) co
device->getBlitter()->blit(this, dstImage, region, filter); device->getBlitter()->blit(this, dstImage, region, filter);
} }
void Image::blitToBuffer(VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t* dst, int bufferRowPitch, int bufferSlicePitch) const
{
device->getBlitter()->blitToBuffer(this, subresource, offset, extent, dst, bufferRowPitch, bufferSlicePitch);
}
void Image::resolve(Image* dstImage, const VkImageResolve& region) const void Image::resolve(Image* dstImage, const VkImageResolve& region) const
{ {
VkImageBlit blitRegion; VkImageBlit blitRegion;
......
...@@ -41,6 +41,7 @@ public: ...@@ -41,6 +41,7 @@ public:
void copyFrom(Buffer* srcBuffer, const VkBufferImageCopy& region); void copyFrom(Buffer* srcBuffer, const VkBufferImageCopy& region);
void blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) const; void blit(Image* dstImage, const VkImageBlit& region, VkFilter filter) const;
void blitToBuffer(VkImageSubresourceLayers subresource, VkOffset3D offset, VkExtent3D extent, uint8_t* dst, int bufferRowPitch, int bufferSlicePitch) const;
void resolve(Image* dstImage, const VkImageResolve& region) const; void resolve(Image* dstImage, const VkImageResolve& region) const;
void clear(const VkClearValue& clearValue, const vk::Format& viewFormat, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange); void clear(const VkClearValue& clearValue, const vk::Format& viewFormat, const VkRect2D& renderArea, const VkImageSubresourceRange& subresourceRange);
void clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange); void clear(const VkClearColorValue& color, const VkImageSubresourceRange& subresourceRange);
......
...@@ -213,7 +213,7 @@ void Queue::garbageCollect() ...@@ -213,7 +213,7 @@ void Queue::garbageCollect()
} }
#ifndef __ANDROID__ #ifndef __ANDROID__
void Queue::present(const VkPresentInfoKHR* presentInfo) VkResult Queue::present(const VkPresentInfoKHR* presentInfo)
{ {
// This is a hack to deal with screen tearing for now. // This is a hack to deal with screen tearing for now.
// Need to correctly implement threading using VkSemaphore // Need to correctly implement threading using VkSemaphore
...@@ -227,8 +227,12 @@ void Queue::present(const VkPresentInfoKHR* presentInfo) ...@@ -227,8 +227,12 @@ void Queue::present(const VkPresentInfoKHR* presentInfo)
for(uint32_t i = 0; i < presentInfo->swapchainCount; i++) for(uint32_t i = 0; i < presentInfo->swapchainCount; i++)
{ {
vk::Cast(presentInfo->pSwapchains[i])->present(presentInfo->pImageIndices[i]); VkResult result = vk::Cast(presentInfo->pSwapchains[i])->present(presentInfo->pImageIndices[i]);
if (result != VK_SUCCESS)
return result;
} }
return VK_SUCCESS;
} }
#endif #endif
......
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
VkResult submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, Fence* fence); VkResult submit(uint32_t submitCount, const VkSubmitInfo* pSubmits, Fence* fence);
VkResult waitIdle(); VkResult waitIdle();
#ifndef __ANDROID__ #ifndef __ANDROID__
void present(const VkPresentInfoKHR* presentInfo); VkResult present(const VkPresentInfoKHR* presentInfo);
#endif #endif
private: private:
......
...@@ -2927,9 +2927,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentI ...@@ -2927,9 +2927,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentI
TRACE("(VkQueue queue = %p, const VkPresentInfoKHR* pPresentInfo = %p)", TRACE("(VkQueue queue = %p, const VkPresentInfoKHR* pPresentInfo = %p)",
queue, pPresentInfo); queue, pPresentInfo);
vk::Cast(queue)->present(pPresentInfo); return vk::Cast(queue)->present(pPresentInfo);
return VK_SUCCESS;
} }
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex) VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex)
......
...@@ -35,7 +35,7 @@ public: ...@@ -35,7 +35,7 @@ public:
virtual void attachImage(PresentImage* image) override {} virtual void attachImage(PresentImage* image) override {}
virtual void detachImage(PresentImage* image) override {} virtual void detachImage(PresentImage* image) override {}
void present(PresentImage* image) override; VkResult present(PresentImage* image) override;
private: private:
MetalLayer* metalLayer = nullptr; MetalLayer* metalLayer = nullptr;
......
...@@ -128,7 +128,7 @@ void MacOSSurfaceMVK::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceC ...@@ -128,7 +128,7 @@ void MacOSSurfaceMVK::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceC
pSurfaceCapabilities->maxImageExtent = extent; pSurfaceCapabilities->maxImageExtent = extent;
} }
void MacOSSurfaceMVK::present(PresentImage* image) VkResult MacOSSurfaceMVK::present(PresentImage* image)
{ {
auto drawable = metalLayer->getNextDrawable(); auto drawable = metalLayer->getNextDrawable();
if(drawable) if(drawable)
...@@ -140,6 +140,7 @@ void MacOSSurfaceMVK::present(PresentImage* image) ...@@ -140,6 +140,7 @@ void MacOSSurfaceMVK::present(PresentImage* image)
bytesPerRow:image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0)]; bytesPerRow:image->getImage()->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0)];
[drawable present]; [drawable present];
} }
return VK_SUCCESS;
} }
} }
...@@ -90,7 +90,7 @@ public: ...@@ -90,7 +90,7 @@ public:
virtual void attachImage(PresentImage* image) = 0; virtual void attachImage(PresentImage* image) = 0;
virtual void detachImage(PresentImage* image) = 0; virtual void detachImage(PresentImage* image) = 0;
virtual void present(PresentImage* image) = 0; virtual VkResult present(PresentImage* image) = 0;
void associateSwapchain(SwapchainKHR* swapchain); void associateSwapchain(SwapchainKHR* swapchain);
void disassociateSwapchain(); void disassociateSwapchain();
......
...@@ -198,11 +198,11 @@ VkResult SwapchainKHR::getNextImage(uint64_t timeout, Semaphore* semaphore, Fenc ...@@ -198,11 +198,11 @@ VkResult SwapchainKHR::getNextImage(uint64_t timeout, Semaphore* semaphore, Fenc
return VK_NOT_READY; return VK_NOT_READY;
} }
void SwapchainKHR::present(uint32_t index) VkResult SwapchainKHR::present(uint32_t index)
{ {
auto & image = images[index]; auto& image = images[index];
image.setStatus(PRESENTING); image.setStatus(PRESENTING);
surface->present(&image); VkResult result = surface->present(&image);
image.setStatus(AVAILABLE); image.setStatus(AVAILABLE);
if(retired) if(retired)
...@@ -210,6 +210,8 @@ void SwapchainKHR::present(uint32_t index) ...@@ -210,6 +210,8 @@ void SwapchainKHR::present(uint32_t index)
surface->detachImage(&image); surface->detachImage(&image);
image.clear(); image.clear();
} }
return result;
} }
} }
\ No newline at end of file
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
VkResult getNextImage(uint64_t timeout, Semaphore* semaphore, Fence* fence, uint32_t* pImageIndex); VkResult getNextImage(uint64_t timeout, Semaphore* semaphore, Fence* fence, uint32_t* pImageIndex);
void present(uint32_t index); VkResult present(uint32_t index);
PresentImage const &getImage(uint32_t imageIndex) { return images[imageIndex]; } PresentImage const &getImage(uint32_t imageIndex) { return images[imageIndex]; }
private: private:
......
...@@ -19,37 +19,35 @@ ...@@ -19,37 +19,35 @@
#include <string.h> #include <string.h>
namespace
{
VkExtent2D getWindowSize(HWND hwnd)
{
RECT clientRect = {};
BOOL status = GetClientRect(hwnd, &clientRect);
ASSERT(status != 0);
int windowWidth = clientRect.right - clientRect.left;
int windowHeight = clientRect.bottom - clientRect.top;
return { static_cast<uint32_t>(windowWidth), static_cast<uint32_t>(windowHeight) };
}
}
namespace vk { namespace vk {
Win32SurfaceKHR::Win32SurfaceKHR(const VkWin32SurfaceCreateInfoKHR *pCreateInfo, void *mem) : Win32SurfaceKHR::Win32SurfaceKHR(const VkWin32SurfaceCreateInfoKHR *pCreateInfo, void *mem) :
hwnd(pCreateInfo->hwnd) hwnd(pCreateInfo->hwnd)
{ {
ASSERT(IsWindow(hwnd) == TRUE); ASSERT(IsWindow(hwnd) == TRUE);
RECT clientRect = {};
BOOL status = GetClientRect(hwnd, &clientRect);
ASSERT(status != 0);
windowContext = GetDC(hwnd); windowContext = GetDC(hwnd);
bitmapContext = CreateCompatibleDC(windowContext); bitmapContext = CreateCompatibleDC(windowContext);
lazyCreateFrameBuffer();
BITMAPINFO bitmapInfo = {};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFO);
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biHeight = clientRect.top - clientRect.bottom;
bitmapInfo.bmiHeader.biWidth = clientRect.right - clientRect.left;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmap = CreateDIBSection(bitmapContext, &bitmapInfo, DIB_RGB_COLORS, &framebuffer, 0, 0);
ASSERT(bitmap != NULL);
SelectObject(bitmapContext, bitmap);
} }
void Win32SurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator) void Win32SurfaceKHR::destroySurface(const VkAllocationCallbacks *pAllocator)
{ {
SelectObject(bitmapContext, NULL); destroyFrameBuffer();
DeleteObject(bitmap);
ReleaseDC(hwnd, windowContext); ReleaseDC(hwnd, windowContext);
DeleteDC(bitmapContext); DeleteDC(bitmapContext);
} }
...@@ -62,15 +60,7 @@ size_t Win32SurfaceKHR::ComputeRequiredAllocationSize(const VkWin32SurfaceCreate ...@@ -62,15 +60,7 @@ size_t Win32SurfaceKHR::ComputeRequiredAllocationSize(const VkWin32SurfaceCreate
void Win32SurfaceKHR::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const void Win32SurfaceKHR::getSurfaceCapabilities(VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) const
{ {
SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities); SurfaceKHR::getSurfaceCapabilities(pSurfaceCapabilities);
VkExtent2D extent = getWindowSize(hwnd);
RECT clientRect = {};
BOOL status = GetClientRect(hwnd, &clientRect);
ASSERT(status != 0);
int windowWidth = clientRect.right - clientRect.left;
int windowHeight = clientRect.bottom - clientRect.top;
VkExtent2D extent = {static_cast<uint32_t>(windowWidth), static_cast<uint32_t>(windowHeight)};
pSurfaceCapabilities->currentExtent = extent; pSurfaceCapabilities->currentExtent = extent;
pSurfaceCapabilities->minImageExtent = extent; pSurfaceCapabilities->minImageExtent = extent;
pSurfaceCapabilities->maxImageExtent = extent; pSurfaceCapabilities->maxImageExtent = extent;
...@@ -88,20 +78,80 @@ void Win32SurfaceKHR::detachImage(PresentImage* image) ...@@ -88,20 +78,80 @@ void Win32SurfaceKHR::detachImage(PresentImage* image)
// present instead of associating the image with the surface. // present instead of associating the image with the surface.
} }
void Win32SurfaceKHR::present(PresentImage* image) VkResult Win32SurfaceKHR::present(PresentImage* image)
{ {
// Recreate frame buffer in case window size has changed
lazyCreateFrameBuffer();
if(!framebuffer) if(!framebuffer)
{ {
return; // e.g. window width or height is 0
return VK_SUCCESS;
} }
VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0); VkExtent3D extent = image->getImage()->getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
// FIXME(b/139184291): Assumes B8G8R8A8 surface without stride padding. if (windowExtent.width != extent.width || windowExtent.height != extent.height)
size_t bytes = extent.width * extent.height * 4; {
memcpy(framebuffer, image->getImageMemory()->getOffsetPointer(0), bytes); return VK_ERROR_OUT_OF_DATE_KHR;
}
VkImageSubresourceLayers subresourceLayers{};
subresourceLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceLayers.layerCount = 1;
image->getImage()->blitToBuffer(subresourceLayers, VkOffset3D{}, extent, reinterpret_cast<uint8_t*>(framebuffer), bitmapRowPitch, 0);
StretchBlt(windowContext, 0, 0, extent.width, extent.height, bitmapContext, 0, 0, extent.width, extent.height, SRCCOPY); StretchBlt(windowContext, 0, 0, extent.width, extent.height, bitmapContext, 0, 0, extent.width, extent.height, SRCCOPY);
return VK_SUCCESS;
}
void Win32SurfaceKHR::lazyCreateFrameBuffer()
{
auto currWindowExtent = getWindowSize(hwnd);
if (currWindowExtent.width == windowExtent.width && currWindowExtent.height == windowExtent.height)
{
return;
}
windowExtent = currWindowExtent;
if (framebuffer)
{
destroyFrameBuffer();
}
if (windowExtent.width == 0 || windowExtent.height == 0)
{
return;
}
BITMAPINFO bitmapInfo = {};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFO);
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biHeight = -windowExtent.height;
bitmapInfo.bmiHeader.biWidth = windowExtent.width;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmap = CreateDIBSection(bitmapContext, &bitmapInfo, DIB_RGB_COLORS, &framebuffer, 0, 0);
ASSERT(bitmap != NULL);
SelectObject(bitmapContext, bitmap);
BITMAP header;
int status = GetObject(bitmap, sizeof(BITMAP), &header);
ASSERT(status != 0);
bitmapRowPitch = static_cast<int>(header.bmWidthBytes);
}
void Win32SurfaceKHR::destroyFrameBuffer()
{
SelectObject(bitmapContext, NULL);
DeleteObject(bitmap);
bitmap = {};
bitmapRowPitch = 0;
framebuffer = nullptr;
} }
} }
\ No newline at end of file
...@@ -41,15 +41,20 @@ public: ...@@ -41,15 +41,20 @@ public:
virtual void attachImage(PresentImage* image) override; virtual void attachImage(PresentImage* image) override;
virtual void detachImage(PresentImage* image) override; virtual void detachImage(PresentImage* image) override;
void present(PresentImage* image) override; VkResult present(PresentImage* image) override;
private: private:
void lazyCreateFrameBuffer();
void destroyFrameBuffer();
const HWND hwnd; const HWND hwnd;
HDC windowContext = {}; HDC windowContext = {};
HDC bitmapContext = {}; HDC bitmapContext = {};
VkExtent2D windowExtent = {};
HBITMAP bitmap = {}; HBITMAP bitmap = {};
int bitmapRowPitch = 0;
void *framebuffer = nullptr; void *framebuffer = nullptr;
}; };
......
...@@ -139,7 +139,7 @@ void XcbSurfaceKHR::detachImage(PresentImage* image) ...@@ -139,7 +139,7 @@ void XcbSurfaceKHR::detachImage(PresentImage* image)
} }
} }
void XcbSurfaceKHR::present(PresentImage* image) VkResult XcbSurfaceKHR::present(PresentImage* image)
{ {
auto it = graphicsContexts.find(image); auto it = graphicsContexts.find(image);
if(it != graphicsContexts.end()) if(it != graphicsContexts.end())
...@@ -167,6 +167,8 @@ void XcbSurfaceKHR::present(PresentImage* image) ...@@ -167,6 +167,8 @@ void XcbSurfaceKHR::present(PresentImage* image)
libXcb->xcb_flush(connection); libXcb->xcb_flush(connection);
} }
return VK_SUCCESS;
} }
} }
\ No newline at end of file
...@@ -36,7 +36,7 @@ public: ...@@ -36,7 +36,7 @@ public:
virtual void attachImage(PresentImage* image) override; virtual void attachImage(PresentImage* image) override;
virtual void detachImage(PresentImage* image) override; virtual void detachImage(PresentImage* image) override;
void present(PresentImage* image) override; VkResult present(PresentImage* image) override;
private: private:
xcb_connection_t* connection; xcb_connection_t* connection;
......
...@@ -82,7 +82,7 @@ void XlibSurfaceKHR::detachImage(PresentImage* image) ...@@ -82,7 +82,7 @@ void XlibSurfaceKHR::detachImage(PresentImage* image)
} }
} }
void XlibSurfaceKHR::present(PresentImage* image) VkResult XlibSurfaceKHR::present(PresentImage* image)
{ {
auto it = imageMap.find(image); auto it = imageMap.find(image);
if(it != imageMap.end()) if(it != imageMap.end())
...@@ -95,6 +95,8 @@ void XlibSurfaceKHR::present(PresentImage* image) ...@@ -95,6 +95,8 @@ void XlibSurfaceKHR::present(PresentImage* image)
libX11->XPutImage(pDisplay, window, gc, xImage, 0, 0, 0, 0, extent.width, extent.height); libX11->XPutImage(pDisplay, window, gc, xImage, 0, 0, 0, 0, extent.width, extent.height);
} }
} }
return VK_SUCCESS;
} }
} }
\ No newline at end of file
...@@ -36,7 +36,7 @@ public: ...@@ -36,7 +36,7 @@ public:
virtual void attachImage(PresentImage* image) override; virtual void attachImage(PresentImage* image) override;
virtual void detachImage(PresentImage* image) override; virtual void detachImage(PresentImage* image) override;
void present(PresentImage* image) override; VkResult present(PresentImage* image) override;
private: private:
Display *const pDisplay; Display *const pDisplay;
......
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