Better handle the frame-buffer locking case.
diff --git a/dlls/ddraw/d3ddevice/mesa.c b/dlls/ddraw/d3ddevice/mesa.c
index 2baf549..11b5a59 100644
--- a/dlls/ddraw/d3ddevice/mesa.c
+++ b/dlls/ddraw/d3ddevice/mesa.c
@@ -3607,13 +3607,45 @@
dst = ((char *)This->surface_desc.lpSurface) +
(pRect->top * This->surface_desc.u1.lPitch) + (pRect->left * GET_BPP(This->surface_desc));
- for (y = (This->surface_desc.dwHeight - pRect->top - 1);
- y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
- y--) {
- glReadPixels(pRect->left, y,
- pRect->right - pRect->left, 1,
+
+ if (This->surface_desc.u1.lPitch != (GET_BPP(This->surface_desc) * This->surface_desc.dwWidth)) {
+ /* Slow-path in case of 'odd' surfaces. This could be fixed using some GL options, but I
+ * could not be bothered considering the rare cases where it may be useful :-)
+ */
+ for (y = (This->surface_desc.dwHeight - pRect->top - 1);
+ y >= ((int) This->surface_desc.dwHeight - (int) pRect->bottom);
+ y--) {
+ glReadPixels(pRect->left, y,
+ pRect->right - pRect->left, 1,
+ buffer_color, buffer_format, dst);
+ dst += This->surface_desc.u1.lPitch;
+ }
+ } else {
+ /* Faster path for surface copy. Note that I can use static variables here as I am
+ * protected by the OpenGL critical section so this function won't be called by
+ * two threads at the same time.
+ */
+ static char *buffer = NULL;
+ static int buffer_width = 0;
+ char *dst2 = dst + ((pRect->bottom - pRect->top) - 1) * This->surface_desc.u1.lPitch;
+ int current_width = (pRect->right - pRect->left) * GET_BPP(This->surface_desc);
+
+ glReadPixels(pRect->left, ((int) This->surface_desc.dwHeight - (int) pRect->bottom),
+ pRect->right - pRect->left, pRect->bottom - pRect->top,
buffer_color, buffer_format, dst);
- dst += This->surface_desc.u1.lPitch;
+
+ if (current_width > buffer_width) {
+ if (buffer != NULL) HeapFree(GetProcessHeap(), 0, buffer);
+ buffer_width = current_width;
+ buffer = HeapAlloc(GetProcessHeap(), 0, buffer_width);
+ }
+ for (y = 0; y < ((pRect->bottom - pRect->top) / 2); y++) {
+ memcpy(buffer, dst, current_width);
+ memcpy(dst, dst2, current_width);
+ memcpy(dst2, buffer, current_width);
+ dst += This->surface_desc.u1.lPitch;
+ dst2 -= This->surface_desc.u1.lPitch;
+ }
}
gl_d3d_dev->state[buffer_type] = SURFACE_MEMORY;