diff -ur skia.org/tools/sk_app/MetalWindowContext.h skia/tools/sk_app/MetalWindowContext.h --- skia.org/tools/sk_app/MetalWindowContext.h 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/MetalWindowContext.h 2023-07-08 21:51:53.416328675 +0200 @@ -51,7 +51,7 @@ static void checkDestroyShared(); - void onSwapBuffers() override; + void onSwapBuffers(const SkIRect* rect = nullptr) override; bool fValid; diff -ur skia.org/tools/sk_app/MetalWindowContext.mm skia/tools/sk_app/MetalWindowContext.mm --- skia.org/tools/sk_app/MetalWindowContext.mm 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/MetalWindowContext.mm 2023-07-08 21:52:10.064396318 +0200 @@ -191,7 +191,7 @@ return surface; } -void MetalWindowContext::onSwapBuffers() { +void MetalWindowContext::onSwapBuffers(const SkIRect*) { id currentDrawable = (id)fDrawableHandle; id commandBuffer([*fShared->fQueue commandBuffer]); diff -ur skia.org/tools/sk_app/unix/RasterWindowContext_unix.cpp skia/tools/sk_app/unix/RasterWindowContext_unix.cpp --- skia.org/tools/sk_app/unix/RasterWindowContext_unix.cpp 2023-07-08 21:49:27.183700444 +0200 +++ skia/tools/sk_app/unix/RasterWindowContext_unix.cpp 2023-07-08 21:54:06.840852252 +0200 @@ -24,7 +24,7 @@ void setDisplayParams(const DisplayParams& params) override; protected: - void onSwapBuffers() override; + void onSwapBuffers(const SkIRect* rect = nullptr) override; sk_sp fBackbufferSurface; Display* fDisplay; @@ -58,7 +58,7 @@ sk_sp RasterWindowContext_xlib::getBackbufferSurface() { return fBackbufferSurface; } -void RasterWindowContext_xlib::onSwapBuffers() { +void RasterWindowContext_xlib::onSwapBuffers(const SkIRect* rect) { SkPixmap pm; if (!fBackbufferSurface->peekPixels(&pm)) { return; @@ -80,7 +80,9 @@ if (!XInitImage(&image)) { return; } - XPutImage(fDisplay, fWindow, fGC, &image, 0, 0, 0, 0, pm.width(), pm.height()); + SkIRect update = rect ? *rect : SkIRect::MakeWH( pm.width(), pm.height()); + XPutImage(fDisplay, fWindow, fGC, &image, update.x(), update.y(), + update.x(), update.y(), update.width(), update.height()); } } // anonymous namespace diff -ur skia.org/tools/sk_app/VulkanWindowContext.cpp skia/tools/sk_app/VulkanWindowContext.cpp --- skia.org/tools/sk_app/VulkanWindowContext.cpp 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/VulkanWindowContext.cpp 2023-07-08 21:52:53.676570245 +0200 @@ -572,7 +572,7 @@ return sk_ref_sp(surface); } -void VulkanWindowContext::onSwapBuffers() { +void VulkanWindowContext::onSwapBuffers(const SkIRect*) { BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex; sk_sp surface = fSurfaces[backbuffer->fImageIndex]; diff -ur skia.org/tools/sk_app/VulkanWindowContext.h skia/tools/sk_app/VulkanWindowContext.h --- skia.org/tools/sk_app/VulkanWindowContext.h 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/VulkanWindowContext.h 2023-07-08 21:52:34.580494658 +0200 @@ -71,7 +71,7 @@ bool createSwapchain(int width, int height, const DisplayParams& params); bool createBuffers(VkFormat format, VkImageUsageFlags, SkColorType colorType, VkSharingMode); void destroyBuffers(); - void onSwapBuffers() override; + void onSwapBuffers(const SkIRect* rect = nullptr) override; // Create functions CreateVkSurfaceFn fCreateVkSurfaceFn; diff -ur skia.org/tools/sk_app/win/RasterWindowContext_win.cpp skia/tools/sk_app/win/RasterWindowContext_win.cpp --- skia.org/tools/sk_app/win/RasterWindowContext_win.cpp 2023-07-08 21:49:27.183700444 +0200 +++ skia/tools/sk_app/win/RasterWindowContext_win.cpp 2023-07-08 21:55:26.169145828 +0200 @@ -27,7 +27,7 @@ void setDisplayParams(const DisplayParams& params) override; protected: - void onSwapBuffers() override; + void onSwapBuffers(const SkIRect* rect=nullptr) override; SkAutoMalloc fSurfaceMemory; sk_sp fBackbufferSurface; @@ -73,13 +73,17 @@ sk_sp RasterWindowContext_win::getBackbufferSurface() { return fBackbufferSurface; } -void RasterWindowContext_win::onSwapBuffers() { +void RasterWindowContext_win::onSwapBuffers(const SkIRect* rect) { BITMAPINFO* bmpInfo = reinterpret_cast(fSurfaceMemory.get()); HDC dc = GetDC(fWnd); SkPixmap pixmap; fBackbufferSurface->peekPixels(&pixmap); - StretchDIBits(dc, 0, 0, fWidth, fHeight, 0, 0, fWidth, fHeight, pixmap.addr(), bmpInfo, - DIB_RGB_COLORS, SRCCOPY); + SkIRect update = rect ? *rect : SkIRect::MakeWH( fWidth, fHeight ); + // It appears that y-axis handling is broken if it doesn't match the window size. + update = SkIRect::MakeXYWH( update.x(), 0, update.width(), fHeight ); + StretchDIBits(dc, update.x(), update.y(), update.width(), update.height(), + update.x(), update.y(), update.width(), update.height(), + pixmap.addr(), bmpInfo, DIB_RGB_COLORS, SRCCOPY); ReleaseDC(fWnd, dc); } diff -ur skia.org/tools/sk_app/WindowContext.cpp skia/tools/sk_app/WindowContext.cpp --- skia.org/tools/sk_app/WindowContext.cpp 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/WindowContext.cpp 2023-07-08 21:56:23.373350669 +0200 @@ -20,7 +20,7 @@ WindowContext::~WindowContext() {} -void WindowContext::swapBuffers() { +void WindowContext::swapBuffers(const SkIRect* rect) { #if defined(SK_GRAPHITE) if (fGraphiteContext) { SkASSERT(fGraphiteRecorder); @@ -33,7 +33,7 @@ } } #endif - this->onSwapBuffers(); + this->onSwapBuffers(rect); } } //namespace sk_app diff -ur skia.org/tools/sk_app/WindowContext.h skia/tools/sk_app/WindowContext.h --- skia.org/tools/sk_app/WindowContext.h 2023-07-08 21:49:27.179700423 +0200 +++ skia/tools/sk_app/WindowContext.h 2023-07-08 21:51:08.804143750 +0200 @@ -31,7 +31,7 @@ virtual sk_sp getBackbufferSurface() = 0; - void swapBuffers(); + void swapBuffers(const SkIRect* rect = nullptr); virtual bool isValid() = 0; @@ -57,7 +57,7 @@ protected: virtual bool isGpuContext() { return true; } - virtual void onSwapBuffers() = 0; + virtual void onSwapBuffers(const SkIRect* rect = nullptr) = 0; sk_sp fContext; #if defined(SK_GRAPHITE)