Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2022
- 68 participants
- 3274 messages
[PATCH 2/7] win32u: Move NtUserScrollWindowEx implementation from user32.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/user32/edit.c | 4 +-
dlls/user32/listbox.c | 8 +-
dlls/user32/mdi.c | 8 +-
dlls/user32/painting.c | 240 +----------------------------------
dlls/user32/user32.spec | 2 +-
dlls/win32u/dce.c | 204 +++++++++++++++++++++++++++++
dlls/win32u/gdiobj.c | 1 +
dlls/win32u/win32u.spec | 2 +-
dlls/win32u/win32u_private.h | 4 +
dlls/win32u/window.c | 2 +-
dlls/win32u/wrappers.c | 9 ++
include/ntuser.h | 6 +
12 files changed, 239 insertions(+), 251 deletions(-)
diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c
index b7eaf2b9ddf..70f105b9a0a 100644
--- a/dlls/user32/edit.c
+++ b/dlls/user32/edit.c
@@ -1708,8 +1708,8 @@ static BOOL EDIT_EM_LineScroll_internal(EDITSTATE *es, INT dx, INT dy)
GetClientRect(es->hwndSelf, &rc1);
IntersectRect(&rc, &rc1, &es->format_rect);
- ScrollWindowEx(es->hwndSelf, -dx, dy,
- NULL, &rc, NULL, NULL, SW_INVALIDATE);
+ NtUserScrollWindowEx(es->hwndSelf, -dx, dy,
+ NULL, &rc, NULL, NULL, SW_INVALIDATE);
/* force scroll info update */
EDIT_UpdateScrollInfo(es);
}
diff --git a/dlls/user32/listbox.c b/dlls/user32/listbox.c
index 0eed2fdfe65..b8f127c0963 100644
--- a/dlls/user32/listbox.c
+++ b/dlls/user32/listbox.c
@@ -439,8 +439,8 @@ static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
else
dy = (descr->top_item - index) * descr->item_height;
- ScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL,
- SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ NtUserScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
}
else
InvalidateRect( descr->self, NULL, TRUE );
@@ -1340,8 +1340,8 @@ static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
/* Invalidate the focused item so it will be repainted correctly */
if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
InvalidateRect( descr->self, &rect, TRUE );
- ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
- SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ NtUserScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
}
else
InvalidateRect( descr->self, NULL, TRUE );
diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c
index e5a52012413..26772aed763 100644
--- a/dlls/user32/mdi.c
+++ b/dlls/user32/mdi.c
@@ -1822,11 +1822,11 @@ void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
if( uMsg == WM_VSCROLL )
- ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
- SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ NtUserScrollWindowEx( hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
else
- ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
- SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
+ NtUserScrollWindowEx( hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
+ SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
done:
SetThreadDpiAwarenessContext( context );
}
diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c
index e7be362773a..419c952d998 100644
--- a/dlls/user32/painting.c
+++ b/dlls/user32/painting.c
@@ -19,72 +19,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-#include <assert.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "ntstatus.h"
-#define WIN32_NO_STATUS
#include "user_private.h"
-#include "win.h"
-#include "controls.h"
-#include "wine/server.h"
-#include "wine/list.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(win);
-
-
-/*************************************************************************
- * fix_caret
- *
- * Helper for ScrollWindowEx:
- * If the return value is 0, no special caret handling is necessary.
- * Otherwise the return value is the handle of the window that owns the
- * caret. Its caret needs to be hidden during the scroll operation and
- * moved to new_caret_pos if move_caret is TRUE.
- */
-static HWND fix_caret(HWND hWnd, const RECT *scroll_rect, INT dx, INT dy,
- UINT flags, LPBOOL move_caret, LPPOINT new_caret_pos)
-{
- GUITHREADINFO info;
- RECT rect, mapped_rcCaret;
-
- info.cbSize = sizeof(info);
- if (!NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info )) return 0;
- if (!info.hwndCaret) return 0;
-
- mapped_rcCaret = info.rcCaret;
- if (info.hwndCaret == hWnd)
- {
- /* The caret needs to be moved along with scrolling even if it's
- * outside the visible area. Otherwise, when the caret is scrolled
- * out from the view, the position won't get updated anymore and
- * the caret will never scroll back again. */
- *move_caret = TRUE;
- new_caret_pos->x = info.rcCaret.left + dx;
- new_caret_pos->y = info.rcCaret.top + dy;
- }
- else
- {
- *move_caret = FALSE;
- if (!(flags & SW_SCROLLCHILDREN) || !IsChild(hWnd, info.hwndCaret))
- return 0;
- MapWindowPoints(info.hwndCaret, hWnd, (LPPOINT)&mapped_rcCaret, 2);
- }
-
- /* If the caret is not in the src/dest rects, all is fine done. */
- if (!IntersectRect(&rect, scroll_rect, &mapped_rcCaret))
- {
- rect = *scroll_rect;
- OffsetRect(&rect, dx, dy);
- if (!IntersectRect(&rect, &rect, &mapped_rcCaret))
- return 0;
- }
-
- /* Indicate that the caret needs to be updated during the scrolling. */
- return info.hwndCaret;
-}
/***********************************************************************
@@ -197,177 +132,6 @@ BOOL WINAPI ValidateRect( HWND hwnd, const RECT *rect )
}
-static INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect, const RECT *clipRect,
- HRGN hrgnUpdate, LPRECT rcUpdate, UINT flags, BOOL is_ex )
-{
- INT retVal = NULLREGION;
- BOOL bOwnRgn = TRUE;
- BOOL bUpdate = (rcUpdate || hrgnUpdate || flags & (SW_INVALIDATE | SW_ERASE));
- int rdw_flags;
- HRGN hrgnTemp;
- HRGN hrgnWinupd = 0;
- HDC hDC;
- RECT rc, cliprc;
- HWND hwndCaret = NULL;
- BOOL moveCaret = FALSE;
- POINT newCaretPos;
-
- TRACE( "%p, %d,%d hrgnUpdate=%p rcUpdate = %p %s %04x\n",
- hwnd, dx, dy, hrgnUpdate, rcUpdate, wine_dbgstr_rect(rect), flags );
- TRACE( "clipRect = %s\n", wine_dbgstr_rect(clipRect));
- if( flags & ~( SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE))
- FIXME("some flags (%04x) are unhandled\n", flags);
-
- rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ?
- RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE ;
-
- if (!WIN_IsWindowDrawable( hwnd, TRUE )) return ERROR;
- hwnd = WIN_GetFullHandle( hwnd );
-
- GetClientRect(hwnd, &rc);
-
- if (clipRect) IntersectRect(&cliprc,&rc,clipRect);
- else cliprc = rc;
-
- if (rect) IntersectRect(&rc, &rc, rect);
-
- if( hrgnUpdate ) bOwnRgn = FALSE;
- else if( bUpdate ) hrgnUpdate = CreateRectRgn( 0, 0, 0, 0 );
-
- newCaretPos.x = newCaretPos.y = 0;
-
- if( !IsRectEmpty(&cliprc) && (dx || dy)) {
- DWORD dcxflags = 0;
- DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
-
- hwndCaret = fix_caret(hwnd, &rc, dx, dy, flags, &moveCaret, &newCaretPos);
- if (hwndCaret)
- NtUserHideCaret( hwndCaret );
-
- if (is_ex) dcxflags |= DCX_CACHE;
- if( style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS;
- if( GetClassLongW( hwnd, GCL_STYLE ) & CS_PARENTDC)
- dcxflags |= DCX_PARENTCLIP;
- if( !(flags & SW_SCROLLCHILDREN) && (style & WS_CLIPCHILDREN))
- dcxflags |= DCX_CLIPCHILDREN;
- hDC = NtUserGetDCEx( hwnd, 0, dcxflags);
- if (hDC)
- {
- NtUserScrollDC( hDC, dx, dy, &rc, &cliprc, hrgnUpdate, rcUpdate );
-
- NtUserReleaseDC( hwnd, hDC );
-
- if (!bUpdate)
- NtUserRedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags);
- }
-
- /* If the windows has an update region, this must be
- * scrolled as well. Keep a copy in hrgnWinupd
- * to be added to hrngUpdate at the end. */
- hrgnTemp = CreateRectRgn( 0, 0, 0, 0 );
- retVal = NtUserGetUpdateRgn( hwnd, hrgnTemp, FALSE );
- if (retVal != NULLREGION)
- {
- HRGN hrgnClip = CreateRectRgnIndirect(&cliprc);
- if( !bOwnRgn) {
- hrgnWinupd = CreateRectRgn( 0, 0, 0, 0);
- CombineRgn( hrgnWinupd, hrgnTemp, 0, RGN_COPY);
- }
- OffsetRgn( hrgnTemp, dx, dy );
- CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
- if( !bOwnRgn)
- CombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR );
- NtUserRedrawWindow( hwnd, NULL, hrgnTemp, rdw_flags);
-
- /* Catch the case where the scrolling amount exceeds the size of the
- * original window. This generated a second update area that is the
- * location where the original scrolled content would end up.
- * This second region is not returned by the ScrollDC and sets
- * ScrollWindowEx apart from just a ScrollDC.
- *
- * This has been verified with testing on windows.
- */
- if (abs(dx) > abs(rc.right - rc.left) ||
- abs(dy) > abs(rc.bottom - rc.top))
- {
- SetRectRgn( hrgnTemp, rc.left + dx, rc.top + dy, rc.right+dx, rc.bottom + dy);
- CombineRgn( hrgnTemp, hrgnTemp, hrgnClip, RGN_AND );
- CombineRgn( hrgnUpdate, hrgnUpdate, hrgnTemp, RGN_OR );
-
- if (rcUpdate)
- {
- RECT rcTemp;
- GetRgnBox( hrgnTemp, &rcTemp );
- UnionRect( rcUpdate, rcUpdate, &rcTemp );
- }
-
- if( !bOwnRgn)
- CombineRgn( hrgnWinupd, hrgnWinupd, hrgnTemp, RGN_OR );
- }
- DeleteObject( hrgnClip );
- }
- DeleteObject( hrgnTemp );
- } else {
- /* nothing was scrolled */
- if( !bOwnRgn)
- SetRectRgn( hrgnUpdate, 0, 0, 0, 0 );
- SetRectEmpty( rcUpdate);
- }
-
- if( flags & SW_SCROLLCHILDREN )
- {
- HWND *list = WIN_ListChildren( hwnd );
- if (list)
- {
- int i;
- RECT r, dummy;
- for (i = 0; list[i]; i++)
- {
- WIN_GetRectangles( list[i], COORDS_PARENT, &r, NULL );
- if (!rect || IntersectRect(&dummy, &r, rect))
- NtUserSetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0,
- SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
- SWP_NOREDRAW | SWP_DEFERERASE );
- }
- HeapFree( GetProcessHeap(), 0, list );
- }
- }
-
- if( flags & (SW_INVALIDATE | SW_ERASE) )
- NtUserRedrawWindow( hwnd, NULL, hrgnUpdate, rdw_flags |
- ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
-
- if( hrgnWinupd) {
- CombineRgn( hrgnUpdate, hrgnUpdate, hrgnWinupd, RGN_OR);
- DeleteObject( hrgnWinupd);
- }
-
- if( moveCaret )
- SetCaretPos( newCaretPos.x, newCaretPos.y );
- if( hwndCaret )
- NtUserShowCaret( hwndCaret );
-
- if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
-
- return retVal;
-}
-
-
-/*************************************************************************
- * ScrollWindowEx (USER32.@)
- *
- * Note: contrary to what the doc says, pixels that are scrolled from the
- * outside of clipRect to the inside are NOT painted.
- *
- */
-INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy,
- const RECT *rect, const RECT *clipRect,
- HRGN hrgnUpdate, LPRECT rcUpdate,
- UINT flags )
-{
- return scroll_window( hwnd, dx, dy, rect, clipRect, hrgnUpdate, rcUpdate, flags, TRUE );
-}
-
/*************************************************************************
* ScrollWindow (USER32.@)
*
@@ -375,8 +139,8 @@ INT WINAPI ScrollWindowEx( HWND hwnd, INT dx, INT dy,
BOOL WINAPI ScrollWindow( HWND hwnd, INT dx, INT dy,
const RECT *rect, const RECT *clipRect )
{
- return scroll_window( hwnd, dx, dy, rect, clipRect, 0, NULL,
- SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN), FALSE ) != ERROR;
+ UINT flags = SW_INVALIDATE | SW_ERASE | (rect ? 0 : SW_SCROLLCHILDREN) | SW_NODCCACHE;
+ return NtUserScrollWindowEx( hwnd, dx, dy, rect, clipRect, 0, NULL, flags );
}
/************************************************************************
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index ee533305a6e..8a7387040dc 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -630,7 +630,7 @@
@ stdcall ScrollChildren(long long long long)
@ stdcall ScrollDC(long long long ptr ptr long ptr) NtUserScrollDC
@ stdcall ScrollWindow(long long long ptr ptr)
-@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long)
+@ stdcall ScrollWindowEx(long long long ptr ptr long ptr long) NtUserScrollWindowEx
@ stdcall SendDlgItemMessageA(long long long long long)
@ stdcall SendDlgItemMessageW(long long long long long)
@ stdcall SendIMEMessageExA(long long)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c
index acbb213d7b7..872112e4a24 100644
--- a/dlls/win32u/dce.c
+++ b/dlls/win32u/dce.c
@@ -1591,3 +1591,207 @@ BOOL WINAPI NtUserLockWindowUpdate( HWND hwnd )
}
return !InterlockedCompareExchangePointer( (void **)&locked_hwnd, hwnd, 0 );
}
+
+/*************************************************************************
+ * fix_caret
+ *
+ * Helper for NtUserScrollWindowEx:
+ * If the return value is 0, no special caret handling is necessary.
+ * Otherwise the return value is the handle of the window that owns the
+ * caret. Its caret needs to be hidden during the scroll operation and
+ * moved to new_caret_pos if move_caret is TRUE.
+ */
+static HWND fix_caret( HWND hwnd, const RECT *scroll_rect, INT dx, INT dy,
+ UINT flags, BOOL *move_caret, POINT *new_caret_pos )
+{
+ RECT rect, mapped_caret;
+ GUITHREADINFO info;
+
+ info.cbSize = sizeof(info);
+ if (!NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info )) return 0;
+ if (!info.hwndCaret) return 0;
+
+ mapped_caret = info.rcCaret;
+ if (info.hwndCaret == hwnd)
+ {
+ /* The caret needs to be moved along with scrolling even if it's
+ * outside the visible area. Otherwise, when the caret is scrolled
+ * out from the view, the position won't get updated anymore and
+ * the caret will never scroll back again. */
+ *move_caret = TRUE;
+ new_caret_pos->x = info.rcCaret.left + dx;
+ new_caret_pos->y = info.rcCaret.top + dy;
+ }
+ else
+ {
+ *move_caret = FALSE;
+ if (!(flags & SW_SCROLLCHILDREN) || !is_child( hwnd, info.hwndCaret ))
+ return 0;
+ map_window_points( info.hwndCaret, hwnd, (POINT *)&mapped_caret, 2, get_thread_dpi() );
+ }
+
+ /* If the caret is not in the src/dest rects, all is fine done. */
+ if (!intersect_rect( &rect, scroll_rect, &mapped_caret ))
+ {
+ rect = *scroll_rect;
+ OffsetRect( &rect, dx, dy );
+ if (!intersect_rect( &rect, &rect, &mapped_caret ))
+ return 0;
+ }
+
+ /* Indicate that the caret needs to be updated during the scrolling. */
+ return info.hwndCaret;
+}
+
+/*************************************************************************
+ * NtUserScrollWindowEx (win32u.@)
+ *
+ * Note: contrary to what the doc says, pixels that are scrolled from the
+ * outside of clipRect to the inside are NOT painted.
+ */
+INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect,
+ const RECT *clip_rect, HRGN update_rgn,
+ RECT *update_rect, UINT flags )
+{
+ BOOL update = update_rect || update_rgn || flags & (SW_INVALIDATE | SW_ERASE);
+ BOOL own_rgn = TRUE, move_caret = FALSE;
+ HRGN temp_rgn, winupd_rgn = 0;
+ INT retval = NULLREGION;
+ HWND caret_hwnd = NULL;
+ POINT new_caret_pos;
+ RECT rc, cliprc;
+ int rdw_flags;
+ HDC hdc;
+
+ TRACE( "%p, %d,%d update_rgn=%p update_rect = %p %s %04x\n",
+ hwnd, dx, dy, update_rgn, update_rect, wine_dbgstr_rect(rect), flags );
+ TRACE( "clip_rect = %s\n", wine_dbgstr_rect(clip_rect) );
+ if (flags & ~(SW_SCROLLCHILDREN | SW_INVALIDATE | SW_ERASE))
+ FIXME( "some flags (%04x) are unhandled\n", flags );
+
+ rdw_flags = (flags & SW_ERASE) && (flags & SW_INVALIDATE) ?
+ RDW_INVALIDATE | RDW_ERASE : RDW_INVALIDATE;
+
+ if (!is_window_drawable( hwnd, TRUE )) return ERROR;
+ hwnd = get_full_window_handle( hwnd );
+
+ get_client_rect( hwnd, &rc );
+ if (clip_rect) intersect_rect( &cliprc, &rc, clip_rect );
+ else cliprc = rc;
+
+ if (rect) intersect_rect( &rc, &rc, rect );
+ if (update_rgn) own_rgn = FALSE;
+ else if (update) update_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+
+ new_caret_pos.x = new_caret_pos.y = 0;
+
+ if (!IsRectEmpty( &cliprc ) && (dx || dy))
+ {
+ DWORD style = get_window_long( hwnd, GWL_STYLE );
+ DWORD dcxflags = 0;
+
+ caret_hwnd = fix_caret( hwnd, &rc, dx, dy, flags, &move_caret, &new_caret_pos );
+ if (caret_hwnd) NtUserHideCaret( caret_hwnd );
+
+ if (!(flags & SW_NODCCACHE)) dcxflags |= DCX_CACHE;
+ if (style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS;
+ if (get_class_long( hwnd, GCL_STYLE, FALSE ) & CS_PARENTDC) dcxflags |= DCX_PARENTCLIP;
+ if (!(flags & SW_SCROLLCHILDREN) && (style & WS_CLIPCHILDREN))
+ dcxflags |= DCX_CLIPCHILDREN;
+ hdc = NtUserGetDCEx( hwnd, 0, dcxflags);
+ if (hdc)
+ {
+ NtUserScrollDC( hdc, dx, dy, &rc, &cliprc, update_rgn, update_rect );
+ NtUserReleaseDC( hwnd, hdc );
+ if (!update) NtUserRedrawWindow( hwnd, NULL, update_rgn, rdw_flags );
+ }
+
+ /* If the windows has an update region, this must be scrolled as well.
+ * Keep a copy in winupd_rgn to be added to hrngUpdate at the end. */
+ temp_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
+ retval = NtUserGetUpdateRgn( hwnd, temp_rgn, FALSE );
+ if (retval != NULLREGION)
+ {
+ HRGN clip_rgn = NtGdiCreateRectRgn( cliprc.left, cliprc.top,
+ cliprc.right, cliprc.bottom );
+ if (!own_rgn)
+ {
+ winupd_rgn = NtGdiCreateRectRgn( 0, 0, 0, 0);
+ NtGdiCombineRgn( winupd_rgn, temp_rgn, 0, RGN_COPY);
+ }
+ NtGdiOffsetRgn( temp_rgn, dx, dy );
+ NtGdiCombineRgn( temp_rgn, temp_rgn, clip_rgn, RGN_AND );
+ if (!own_rgn) NtGdiCombineRgn( winupd_rgn, winupd_rgn, temp_rgn, RGN_OR );
+ NtUserRedrawWindow( hwnd, NULL, temp_rgn, rdw_flags );
+
+ /*
+ * Catch the case where the scrolling amount exceeds the size of the
+ * original window. This generated a second update area that is the
+ * location where the original scrolled content would end up.
+ * This second region is not returned by the ScrollDC and sets
+ * ScrollWindowEx apart from just a ScrollDC.
+ *
+ * This has been verified with testing on windows.
+ */
+ if (abs( dx ) > abs( rc.right - rc.left ) || abs( dy ) > abs( rc.bottom - rc.top ))
+ {
+ NtGdiSetRectRgn( temp_rgn, rc.left + dx, rc.top + dy, rc.right+dx, rc.bottom + dy );
+ NtGdiCombineRgn( temp_rgn, temp_rgn, clip_rgn, RGN_AND );
+ NtGdiCombineRgn( update_rgn, update_rgn, temp_rgn, RGN_OR );
+
+ if (update_rect)
+ {
+ RECT temp_rect;
+ NtGdiGetRgnBox( temp_rgn, &temp_rect );
+ union_rect( update_rect, update_rect, &temp_rect );
+ }
+
+ if (!own_rgn) NtGdiCombineRgn( winupd_rgn, winupd_rgn, temp_rgn, RGN_OR );
+ }
+ NtGdiDeleteObjectApp( clip_rgn );
+ }
+ NtGdiDeleteObjectApp( temp_rgn );
+ }
+ else
+ {
+ /* nothing was scrolled */
+ if (!own_rgn) NtGdiSetRectRgn( update_rgn, 0, 0, 0, 0 );
+ SetRectEmpty( update_rect );
+ }
+
+ if (flags & SW_SCROLLCHILDREN)
+ {
+ HWND *list = list_window_children( 0, hwnd, NULL, 0 );
+ if (list)
+ {
+ RECT r, dummy;
+ int i;
+
+ for (i = 0; list[i]; i++)
+ {
+ get_window_rects( list[i], COORDS_PARENT, &r, NULL, get_thread_dpi() );
+ if (!rect || intersect_rect( &dummy, &r, rect ))
+ NtUserSetWindowPos( list[i], 0, r.left + dx, r.top + dy, 0, 0,
+ SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE |
+ SWP_NOREDRAW | SWP_DEFERERASE );
+ }
+ free( list );
+ }
+ }
+
+ if (flags & (SW_INVALIDATE | SW_ERASE))
+ NtUserRedrawWindow( hwnd, NULL, update_rgn, rdw_flags |
+ ((flags & SW_SCROLLCHILDREN) ? RDW_ALLCHILDREN : 0 ) );
+
+ if (winupd_rgn)
+ {
+ NtGdiCombineRgn( update_rgn, update_rgn, winupd_rgn, RGN_OR );
+ NtGdiDeleteObjectApp( winupd_rgn );
+ }
+
+ if (move_caret) set_caret_pos( new_caret_pos.x, new_caret_pos.y );
+ if (caret_hwnd) NtUserShowCaret( caret_hwnd );
+ if (own_rgn && update_rgn) NtGdiDeleteObjectApp( update_rgn );
+
+ return retval;
+}
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c
index c29e7773e6c..222b74b45d6 100644
--- a/dlls/win32u/gdiobj.c
+++ b/dlls/win32u/gdiobj.c
@@ -1200,6 +1200,7 @@ static struct unix_funcs unix_funcs =
NtUserRegisterHotKey,
NtUserReleaseDC,
NtUserScrollDC,
+ NtUserScrollWindowEx,
NtUserSelectPalette,
NtUserSendInput,
NtUserSetActiveWindow,
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index 8584fc4e5c3..86d359b8386 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -1156,7 +1156,7 @@
@ stub NtUserRestoreWindowDpiChanges
@ stub NtUserSBGetParms
@ stdcall NtUserScrollDC(long long long ptr ptr long ptr)
-@ stub NtUserScrollWindowEx
+@ stdcall NtUserScrollWindowEx(long long long ptr ptr long ptr long)
@ stdcall NtUserSelectPalette(long long long)
@ stub NtUserSendEventMessage
@ stdcall NtUserSendInput(long ptr long)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index c5303010ef3..2394a8850a5 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -268,6 +268,9 @@ struct unix_funcs
INT (WINAPI *pNtUserReleaseDC)( HWND hwnd, HDC hdc );
BOOL (WINAPI *pNtUserScrollDC)( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip,
HRGN ret_update_rgn, RECT *update_rect );
+ INT (WINAPI *pNtUserScrollWindowEx)( HWND hwnd, INT dx, INT dy, const RECT *rect,
+ const RECT *clip_rect, HRGN update_rgn,
+ RECT *update_rect, UINT flags );
HPALETTE (WINAPI *pNtUserSelectPalette)( HDC hdc, HPALETTE hpal, WORD bkg );
UINT (WINAPI *pNtUserSendInput)( UINT count, INPUT *inputs, int size );
HWND (WINAPI *pNtUserSetActiveWindow)( HWND hwnd );
@@ -449,6 +452,7 @@ extern HWND is_current_process_window( HWND hwnd ) DECLSPEC_HIDDEN;
extern HWND is_current_thread_window( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL is_iconic( HWND hwnd ) DECLSPEC_HIDDEN;
+extern BOOL is_window_drawable( HWND hwnd, BOOL icon ) DECLSPEC_HIDDEN;
extern BOOL is_window_enabled( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL is_window_unicode( HWND hwnd ) DECLSPEC_HIDDEN;
extern DWORD get_window_long( HWND hwnd, INT offset ) DECLSPEC_HIDDEN;
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index 319f47712e6..34bf87bc9ba 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -762,7 +762,7 @@ static BOOL is_window_visible( HWND hwnd )
* minimized, and it is itself not minimized unless we are
* trying to draw its default class icon.
*/
-static BOOL is_window_drawable( HWND hwnd, BOOL icon )
+BOOL is_window_drawable( HWND hwnd, BOOL icon )
{
HWND *list;
BOOL retval = TRUE;
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c
index b336059fe96..679cce95b9a 100644
--- a/dlls/win32u/wrappers.c
+++ b/dlls/win32u/wrappers.c
@@ -1112,6 +1112,15 @@ BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const R
return unix_funcs->pNtUserScrollDC( hdc, dx, dy, scroll, clip, ret_update_rgn, update_rect );
}
+INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect,
+ const RECT *clip_rect, HRGN update_rgn,
+ RECT *update_rect, UINT flags )
+{
+ if (!unix_funcs) return 0;
+ return unix_funcs->pNtUserScrollWindowEx( hwnd, dx, dy, rect, clip_rect,
+ update_rgn, update_rect, flags );
+}
+
HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE hpal, WORD bkg )
{
if (!unix_funcs) return 0;
diff --git a/include/ntuser.h b/include/ntuser.h
index e0c65a9f532..b6b69879dd7 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -227,6 +227,9 @@ struct send_message_callback_params
#define NTUSER_OBJ_ACCEL 0x08
#define NTUSER_OBJ_HOOK 0x0f
+/* NtUserScrollWindowEx flag */
+#define SW_NODCCACHE 0x8000
+
/* NtUserInitializeClientPfnArrays parameter, not compatible with Windows */
struct user_client_procs
{
@@ -615,6 +618,9 @@ BOOL WINAPI NtUserRemoveMenu( HMENU menu, UINT id, UINT flags );
HANDLE WINAPI NtUserRemoveProp( HWND hwnd, const WCHAR *str );
BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip,
HRGN ret_update_rgn, RECT *update_rect );
+INT WINAPI NtUserScrollWindowEx( HWND hwnd, INT dx, INT dy, const RECT *rect,
+ const RECT *clip_rect, HRGN update_rgn,
+ RECT *update_rect, UINT flags ) DECLSPEC_HIDDEN;
HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE palette, WORD force_background );
UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size );
HWND WINAPI NtUserSetActiveWindow( HWND hwnd );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/211
June 9, 2022
[PATCH 1/7] win32u: Remove no longer used __wine_set_user_driver PE entry point.
by Jacek Caban
From: Jacek Caban <jacek(a)codeweavers.com>
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/win32u/driver.c | 4 ++--
dlls/win32u/gdiobj.c | 1 -
dlls/win32u/win32u.spec | 1 -
dlls/win32u/win32u_private.h | 1 -
dlls/win32u/wrappers.c | 9 ---------
include/wine/gdi_driver.h | 12 ++++++------
6 files changed, 8 insertions(+), 20 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c
index 1f538d100ed..4a853b516f4 100644
--- a/dlls/win32u/driver.c
+++ b/dlls/win32u/driver.c
@@ -1223,9 +1223,9 @@ static const struct user_driver_funcs lazy_load_driver =
const struct user_driver_funcs *user_driver = &lazy_load_driver;
/******************************************************************************
- * __wine_set_user_driver (win32u.@)
+ * __wine_set_user_driver (win32u.so)
*/
-void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version )
+void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version )
{
struct user_driver_funcs *driver, *prev;
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c
index edb21456d8d..c29e7773e6c 100644
--- a/dlls/win32u/gdiobj.c
+++ b/dlls/win32u/gdiobj.c
@@ -1249,7 +1249,6 @@ static struct unix_funcs unix_funcs =
__wine_get_vulkan_driver,
__wine_get_wgl_driver,
__wine_send_input,
- __wine_set_user_driver,
};
NTSTATUS gdi_init(void)
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index 17be6894508..8584fc4e5c3 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -1322,7 +1322,6 @@
# Graphics drivers
@ cdecl __wine_send_input(long ptr ptr)
-@ cdecl __wine_set_user_driver(ptr long)
# OpenGL
@ cdecl __wine_get_wgl_driver(long long)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index fd6dba82da2..c5303010ef3 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -328,7 +328,6 @@ struct unix_funcs
const struct vulkan_funcs * (CDECL *get_vulkan_driver)( UINT version );
struct opengl_funcs * (CDECL *get_wgl_driver)( HDC hdc, UINT version );
BOOL (CDECL *wine_send_input)( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput );
- void (CDECL *set_user_driver)( const struct user_driver_funcs *funcs, UINT version );
};
/* clipboard.c */
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c
index 13b4b7164ab..b336059fe96 100644
--- a/dlls/win32u/wrappers.c
+++ b/dlls/win32u/wrappers.c
@@ -1408,15 +1408,6 @@ BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *raw
return unix_funcs->wine_send_input( hwnd, input, rawinput );
}
-/***********************************************************************
- * __wine_set_user_driver (win32u.@)
- */
-void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version )
-{
- if (!unix_funcs) return;
- return unix_funcs->set_user_driver( funcs, version );
-}
-
extern void wrappers_init( unixlib_handle_t handle )
{
const void *args;
diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h
index 52fd6fe49d3..998aa3ed3e9 100644
--- a/include/wine/gdi_driver.h
+++ b/include/wine/gdi_driver.h
@@ -168,7 +168,7 @@ struct gdi_dc_funcs
};
/* increment this when you change the DC function table */
-#define WINE_GDI_DRIVER_VERSION 79
+#define WINE_GDI_DRIVER_VERSION 80
#define GDI_PRIORITY_NULL_DRV 0 /* null driver */
#define GDI_PRIORITY_FONT_DRV 100 /* any font driver */
@@ -196,9 +196,9 @@ static inline void push_dc_driver( PHYSDEV *dev, PHYSDEV physdev, const struct g
/* support for window surfaces */
-struct window_surface;
+#ifdef WINE_UNIX_LIB
-#ifndef __WINE_USE_MSVCRT
+struct window_surface;
struct window_surface_funcs
{
@@ -333,10 +333,10 @@ struct user_driver_funcs
void (*pThreadDetach)(void);
};
-#endif /* __WINE_USE_MSVCRT */
+extern void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version );
+
+#endif /* WINE_UNIX_LIB */
-struct user_driver_funcs;
-extern void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version );
extern struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version );
extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver( UINT version );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/211
June 9, 2022
[PATCH 0/7] MR211: win32u: user32 conversion
by Jacek Caban (ï¼ jacek)
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/211
June 9, 2022
[PATCH v2 2/2] winhttp: Use completion port for async send.
by Paul Gofman
From: Paul Gofman <pgofman(a)codeweavers.com>
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/winhttp/net.c | 23 +++++++++++++++++++++--
dlls/winhttp/winhttp_private.h | 1 +
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c
index a17582c90a6..40c9f3c8534 100644
--- a/dlls/winhttp/net.c
+++ b/dlls/winhttp/net.c
@@ -53,9 +53,20 @@ static int sock_send(int fd, const void *msg, size_t len, WSAOVERLAPPED *ovr)
BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len )
{
- DWORD retflags;
+ OVERLAPPED *completion_ovr;
+ ULONG_PTR key;
- return WSAGetOverlappedResult( conn->socket, ovr, len, TRUE, &retflags );
+ if (!GetQueuedCompletionStatus( conn->port, len, &key, &completion_ovr, INFINITE ))
+ {
+ WARN( "GetQueuedCompletionStatus failed, err %lu.\n", GetLastError() );
+ return FALSE;
+ }
+ if ((key != conn->socket && conn->socket != -1) || completion_ovr != (OVERLAPPED *)ovr)
+ {
+ ERR( "Unexpected completion key %Ix, overlapped %p.\n", key, completion_ovr );
+ return FALSE;
+ }
+ return TRUE;
}
static int sock_recv(int fd, void *msg, size_t len, int flags)
@@ -279,6 +290,8 @@ void netconn_close( struct netconn *conn )
if (conn->socket != -1)
closesocket( conn->socket );
release_host( conn->host );
+ if (conn->port)
+ CloseHandle( conn->port );
free(conn);
}
@@ -452,6 +465,12 @@ DWORD netconn_send( struct netconn *conn, const void *msg, size_t len, int *sent
{
DWORD err;
+ if (ovr && !conn->port)
+ {
+ if (!(conn->port = CreateIoCompletionPort( (HANDLE)(SOCKET)conn->socket, NULL, (ULONG_PTR)conn->socket, 0 )))
+ ERR( "Failed to create port.\n" );
+ }
+
if (conn->secure)
{
const BYTE *ptr = msg;
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 6c381af627f..79941dee31a 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -117,6 +117,7 @@ struct netconn
char *peek_msg;
char *peek_msg_mem;
size_t peek_len;
+ HANDLE port;
};
struct header
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/210
June 8, 2022
[PATCH v2 1/2] winhttp: Introduce netconn_wait_overlapped_result() helper.
by Paul Gofman
From: Paul Gofman <pgofman(a)codeweavers.com>
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
dlls/winhttp/net.c | 7 +++++++
dlls/winhttp/request.c | 4 ++--
dlls/winhttp/winhttp_private.h | 1 +
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c
index 17520a54f63..a17582c90a6 100644
--- a/dlls/winhttp/net.c
+++ b/dlls/winhttp/net.c
@@ -51,6 +51,13 @@ static int sock_send(int fd, const void *msg, size_t len, WSAOVERLAPPED *ovr)
return -1;
}
+BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len )
+{
+ DWORD retflags;
+
+ return WSAGetOverlappedResult( conn->socket, ovr, len, TRUE, &retflags );
+}
+
static int sock_recv(int fd, void *msg, size_t len, int flags)
{
int ret;
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 2754dc29163..7fb582362aa 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -3336,9 +3336,9 @@ static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHOR
static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
{
- DWORD ret, retflags, len, i;
+ DWORD ret, len, i;
- if (!WSAGetOverlappedResult( socket->request->netconn->socket, ovr, &len, TRUE, &retflags ))
+ if (!netconn_wait_overlapped_result( socket->request->netconn, ovr, &len ))
return WSAGetLastError();
if (socket->bytes_in_send_frame_buffer)
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 98e05f068ba..6c381af627f 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -371,6 +371,7 @@ DWORD netconn_recv( struct netconn *, void *, size_t, int, int * ) DECLSPEC_HIDD
DWORD netconn_resolve( WCHAR *, INTERNET_PORT, struct sockaddr_storage *, int ) DECLSPEC_HIDDEN;
DWORD netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL ) DECLSPEC_HIDDEN;
DWORD netconn_send( struct netconn *, const void *, size_t, int *, WSAOVERLAPPED * ) DECLSPEC_HIDDEN;
+BOOL netconn_wait_overlapped_result( struct netconn *conn, WSAOVERLAPPED *ovr, DWORD *len ) DECLSPEC_HIDDEN;
void netconn_cancel_io( struct netconn *conn ) DECLSPEC_HIDDEN;
DWORD netconn_set_timeout( struct netconn *, BOOL, int ) DECLSPEC_HIDDEN;
BOOL netconn_is_alive( struct netconn * ) DECLSPEC_HIDDEN;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/210
June 8, 2022
[PATCH v2 0/2] MR210: winhttp: Use completion port for overlapped send.
by Paul Gofman (ï¼ gofman)
There are a few issues with the way it is done now:
1. We queue overlapped WSARecv from one (user) thread and then await completion on another. As it became apparent the completions queued by a thread are canceled when thread terminates. That is currently not the case in Wine, but I have a pending MR for that: https://gitlab.winehq.org/wine/wine/-/merge_requests/135. User may use WinhttpWebSocketSend() and close the thread, if it gets to async send path that send may be canceled before it is complete. The only condition when the async operation is not canceled is that the queued async IO has a completion port and no event (which becomes the case with these patches). I tested on Windows that terminating the thread which called WinhttpWebSocketSend() doesn't cancel the async send, while I am reproducing this case with Wine and the refernced patch.
2. Using overlapped WSASend without a completion port or an event is fragile: the socket may potentially be signaled by a parallel async operation (or maybe instead not singaled until that operation completes; I think Wine and Windows currently don't agree in lot of details how that works, including maybe the higher level WSAGetOverlappedResult). This is more of theoretical point as currently we don't queue any overlapped receives.
3. WSAGetOverlappedResult is currently buggy in a funny way. It doesn't check for valid socket handle, and so if called with an overlapped without an event it waits on socket, and if socket is -1 it is current process pseudo handle and the wait hangs forever. I've sent a patch for winsock for that: https://gitlab.winehq.org/wine/wine/-/merge_requests/203. But since we need completion port for 1 anyway it also seems to also solve the potential race issue between setting socket to -1 when aborting operation and starting wait for overlapped IO on it without additional complications.
--
v2: winhttp: Use completion port for async send.
winhttp: Introduce netconn_wait_overlapped_result() helper.
https://gitlab.winehq.org/wine/wine/-/merge_requests/210
June 8, 2022
[PATCH vkd3d v6 9/9] vkd3d-shader/hlsl: Parse the mul() intrinsic.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl.y | 118 ++++++++++++++++++++++++
tests/hlsl-majority-pragma.shader_test | 2 +-
tests/hlsl-majority-typedef.shader_test | 2 +-
tests/hlsl-mul.shader_test | 36 ++++----
4 files changed, 138 insertions(+), 20 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index 2aee51533..df5fda472 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -2046,6 +2046,123 @@ static bool intrinsic_min(struct hlsl_ctx *ctx,
return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MIN, params->args[0], params->args[1], loc);
}
+static bool intrinsic_mul(struct hlsl_ctx *ctx,
+ const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
+{
+ struct hlsl_ir_node *arg1 = params->args[0], *arg2 = params->args[1], *cast1, *cast2;
+ enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type);
+ struct hlsl_type *cast_type1 = arg1->data_type, *cast_type2 = arg2->data_type, *matrix_type, *ret_type;
+ unsigned int i, j, k, vect_count = 0;
+ struct vkd3d_string_buffer *name;
+ static unsigned int counter = 0;
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+
+ if (arg1->data_type->type == HLSL_CLASS_SCALAR || arg2->data_type->type == HLSL_CLASS_SCALAR)
+ return !!add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, arg1, arg2, loc);
+
+ if (arg1->data_type->type == HLSL_CLASS_VECTOR)
+ {
+ vect_count++;
+ cast_type1 = hlsl_get_matrix_type(ctx, base, arg1->data_type->dimx, 1);
+ }
+ if (arg2->data_type->type == HLSL_CLASS_VECTOR)
+ {
+ vect_count++;
+ cast_type2 = hlsl_get_matrix_type(ctx, base, 1, arg2->data_type->dimx);
+ }
+
+ matrix_type = hlsl_get_matrix_type(ctx, base, cast_type2->dimx, cast_type1->dimy);
+
+ if (vect_count == 0)
+ {
+ ret_type = matrix_type;
+ }
+ else if (vect_count == 1)
+ {
+ assert(matrix_type->dimx == 1 || matrix_type->dimy == 1);
+ ret_type = hlsl_get_vector_type(ctx, base, matrix_type->dimx * matrix_type->dimy);
+ }
+ else
+ {
+ assert(matrix_type->dimx == 1 && matrix_type->dimy == 1);
+ ret_type = hlsl_get_scalar_type(ctx, base);
+ }
+
+ if (!(cast1 = add_implicit_conversion(ctx, params->instrs, arg1, cast_type1, loc)))
+ return false;
+
+ if (!(cast2 = add_implicit_conversion(ctx, params->instrs, arg2, cast_type2, loc)))
+ return false;
+
+ name = vkd3d_string_buffer_get(&ctx->string_buffers);
+ vkd3d_string_buffer_printf(name, "<mul-%u>", counter++);
+ var = hlsl_new_synthetic_var(ctx, name->buffer, matrix_type, *loc);
+ vkd3d_string_buffer_release(&ctx->string_buffers, name);
+ if (!var)
+ return false;
+
+ for (i = 0; i < matrix_type->dimx; ++i)
+ for (j = 0; j < matrix_type->dimy; ++j)
+ {
+ struct hlsl_ir_node *node = NULL;
+ struct hlsl_type *scalar_type;
+ struct hlsl_ir_store *store;
+ struct hlsl_ir_constant *c;
+ unsigned int offset;
+
+ for (k = 0; k < cast_type1->dimx && k < cast_type2->dimy; ++k)
+ {
+ struct hlsl_ir_load *value1, *value2;
+ struct hlsl_ir_node *mul;
+
+ offset = hlsl_compute_component_offset(ctx, cast_type1, j * cast_type1->dimx + k, &scalar_type);
+ if (!(c = hlsl_new_uint_constant(ctx, offset, loc)))
+ return false;
+ list_add_tail(params->instrs, &c->node.entry);
+
+ if (!(value1 = add_load(ctx, params->instrs, cast1, &c->node, scalar_type, *loc)))
+ return false;
+
+ offset = hlsl_compute_component_offset(ctx, cast_type2, k * cast_type2->dimx + i, &scalar_type);
+ if (!(c = hlsl_new_uint_constant(ctx, offset, loc)))
+ return false;
+ list_add_tail(params->instrs, &c->node.entry);
+
+ if (!(value2 = add_load(ctx, params->instrs, cast2, &c->node, scalar_type, *loc)))
+ return false;
+
+ if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, &value1->node, &value2->node, loc)))
+ return false;
+
+ if (node)
+ {
+ if (!(node = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_ADD, node, mul, loc)))
+ return false;
+ }
+ else
+ {
+ node = mul;
+ }
+ }
+
+ offset = hlsl_compute_component_offset(ctx, matrix_type, j * matrix_type->dimx + i, &scalar_type);
+ if (!(c = hlsl_new_uint_constant(ctx, offset, loc)))
+ return false;
+ list_add_tail(params->instrs, &c->node.entry);
+
+ if (!(store = hlsl_new_store(ctx, var, &c->node, node, 0, *loc)))
+ return false;
+ list_add_tail(params->instrs, &store->node.entry);
+ }
+
+ if (!(load = hlsl_new_load(ctx, var, NULL, matrix_type, *loc)))
+ return false;
+ list_add_tail(params->instrs, &load->node.entry);
+
+ return !!add_implicit_conversion(ctx, params->instrs, &load->node, ret_type, loc);
+}
+
static bool intrinsic_pow(struct hlsl_ctx *ctx,
const struct parse_initializer *params, const struct vkd3d_shader_location *loc)
{
@@ -2106,6 +2223,7 @@ intrinsic_functions[] =
{"floor", 1, true, intrinsic_floor},
{"max", 2, true, intrinsic_max},
{"min", 2, true, intrinsic_min},
+ {"mul", 2, true, intrinsic_mul},
{"pow", 2, true, intrinsic_pow},
{"round", 1, true, intrinsic_round},
{"saturate", 1, true, intrinsic_saturate},
diff --git a/tests/hlsl-majority-pragma.shader_test b/tests/hlsl-majority-pragma.shader_test
index a9f917ff8..e7fc75cde 100644
--- a/tests/hlsl-majority-pragma.shader_test
+++ b/tests/hlsl-majority-pragma.shader_test
@@ -17,5 +17,5 @@ uniform 0 float4 0.1 0.2 0.0 0.0
uniform 4 float4 0.3 0.4 0.0 0.0
uniform 8 float4 0.1 0.3 0.0 0.0
uniform 12 float4 0.2 0.4 0.0 0.0
-todo draw quad
+draw quad
probe all rgba (0.17, 0.39, 0.17, 0.39) 1
diff --git a/tests/hlsl-majority-typedef.shader_test b/tests/hlsl-majority-typedef.shader_test
index 192c96db1..1460e9a08 100644
--- a/tests/hlsl-majority-typedef.shader_test
+++ b/tests/hlsl-majority-typedef.shader_test
@@ -18,5 +18,5 @@ uniform 0 float4 0.1 0.2 0.0 0.0
uniform 4 float4 0.3 0.4 0.0 0.0
uniform 8 float4 0.1 0.3 0.0 0.0
uniform 12 float4 0.2 0.4 0.0 0.0
-todo draw quad
+draw quad
probe all rgba (0.17, 0.39, 0.17, 0.39) 1
diff --git a/tests/hlsl-mul.shader_test b/tests/hlsl-mul.shader_test
index 1d137e696..7b4531873 100644
--- a/tests/hlsl-mul.shader_test
+++ b/tests/hlsl-mul.shader_test
@@ -12,7 +12,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (30.0, 70.0, 110.0, 150.0)
[pixel shader]
@@ -28,7 +28,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (90.0, 100.0, 110.0, 120.0)
[pixel shader]
@@ -44,7 +44,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (14.0, 38.0, 62.0, 86.0)
[pixel shader]
@@ -60,7 +60,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (38.0, 44.0, 50.0, 56.0)
[pixel shader]
@@ -75,7 +75,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (14.0, 32.0, 50.0, 0.0)
[pixel shader]
@@ -90,7 +90,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (30.0, 36.0, 42.0, 0.0)
[pixel shader]
@@ -106,7 +106,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (50.0, 60.0, 70.0, 80.0)
[pixel shader]
@@ -122,7 +122,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (50.0, 60.0, 70.0, 80.0)
[pixel shader]
@@ -138,7 +138,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (10.0, 20.0, 30.0, 40.0)
[pixel shader]
@@ -154,7 +154,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (10.0, 50.0, 90.0, 130.0)
[pixel shader]
@@ -170,7 +170,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (10.0, 20.0, 30.0, 40.0)
[pixel shader]
@@ -186,7 +186,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (10.0, 50.0, 90.0, 130.0)
[pixel shader]
@@ -202,7 +202,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (90.0, 100.0, 110.0, 120.0)
[pixel shader]
@@ -218,7 +218,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (5.0, 10.0, 15.0, 20.0)
[pixel shader]
@@ -234,7 +234,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -250,7 +250,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (30.0, 70.0, 110.0, 150.0)
[pixel shader]
@@ -268,7 +268,7 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (83.0, 98.0, 113.0, 128.0)
[pixel shader]
@@ -286,5 +286,5 @@ float4 main(float4 pos : sv_position) : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (78.0, 96.0, 114.0, 0.0)
--
2.36.1
June 8, 2022
[PATCH vkd3d v6 8/9] vkd3d-shader/hlsl: Split matrix operations.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl.y | 74 ++++++++++++++++++++++++++++++++++++
tests/hlsl-shape.shader_test | 30 +++++++--------
2 files changed, 89 insertions(+), 15 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index 687569e83..2aee51533 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -1201,6 +1201,22 @@ static bool expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct
return true;
}
+static unsigned int minor_size(const struct hlsl_type *type)
+{
+ if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR)
+ return type->dimx;
+ else
+ return type->dimy;
+}
+
+static unsigned int major_size(const struct hlsl_type *type)
+{
+ if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR)
+ return type->dimy;
+ else
+ return type->dimx;
+}
+
static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs,
enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS],
struct hlsl_type *type, const struct vkd3d_shader_location *loc)
@@ -1208,6 +1224,64 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs,
struct hlsl_ir_expr *expr;
unsigned int i;
+ if (type->type == HLSL_CLASS_MATRIX)
+ {
+ struct vkd3d_string_buffer *name;
+ static unsigned int counter = 0;
+ struct hlsl_type *vector_type;
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+
+ vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type));
+
+ name = vkd3d_string_buffer_get(&ctx->string_buffers);
+ vkd3d_string_buffer_printf(name, "<split_op-%u>", counter++);
+ var = hlsl_new_synthetic_var(ctx, name->buffer, type, *loc);
+ vkd3d_string_buffer_release(&ctx->string_buffers, name);
+ if (!var)
+ return NULL;
+
+ for (i = 0; i < major_size(type); i++)
+ {
+ struct hlsl_ir_node *value, *vector_operands[HLSL_MAX_OPERANDS] = { NULL };
+ struct hlsl_ir_store *store;
+ struct hlsl_ir_constant *c;
+ unsigned int j;
+
+ if (!(c = hlsl_new_uint_constant(ctx, 4 * i, loc)))
+ return NULL;
+ list_add_tail(instrs, &c->node.entry);
+
+ for (j = 0; j < HLSL_MAX_OPERANDS; j++)
+ {
+ if (operands[j])
+ {
+ struct hlsl_type *vector_arg_type;
+ struct hlsl_ir_load *load;
+
+ vector_arg_type = hlsl_get_vector_type(ctx, operands[j]->data_type->base_type, minor_size(type));
+
+ if (!(load = add_load(ctx, instrs, operands[j], &c->node, vector_arg_type, *loc)))
+ return NULL;
+ vector_operands[j] = &load->node;
+ }
+ }
+
+ if (!(value = add_expr(ctx, instrs, op, vector_operands, vector_type, loc)))
+ return NULL;
+
+ if (!(store = hlsl_new_store(ctx, var, &c->node, value, 0, *loc)))
+ return NULL;
+ list_add_tail(instrs, &store->node.entry);
+ }
+
+ if (!(load = hlsl_new_load(ctx, var, NULL, type, *loc)))
+ return NULL;
+ list_add_tail(instrs, &load->node.entry);
+
+ return &load->node;
+ }
+
if (!(expr = hlsl_alloc(ctx, sizeof(*expr))))
return NULL;
init_node(&expr->node, HLSL_IR_EXPR, type, *loc);
diff --git a/tests/hlsl-shape.shader_test b/tests/hlsl-shape.shader_test
index 65cc322c1..b96f0fd22 100644
--- a/tests/hlsl-shape.shader_test
+++ b/tests/hlsl-shape.shader_test
@@ -93,7 +93,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 7.0, 9.0)
[pixel shader]
@@ -107,7 +107,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 7.0, 9.0)
[pixel shader]
@@ -122,7 +122,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -137,7 +137,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -152,7 +152,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 7.0, 12.0, 17.0)
[pixel shader]
@@ -167,7 +167,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 7.0, 12.0, 17.0)
[pixel shader]
@@ -183,7 +183,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 0.0)
[pixel shader]
@@ -199,7 +199,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (9.0, 11.0, 13.0, 0.0)
[pixel shader]
@@ -223,7 +223,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -247,7 +247,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -273,7 +273,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -285,7 +285,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 3.0, 4.0, 5.0)
[pixel shader]
@@ -297,7 +297,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 3.0, 4.0, 5.0)
[pixel shader]
@@ -336,7 +336,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 3.0, 4.0, 5.0)
[pixel shader]
@@ -351,5 +351,5 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (6.0, 7.0, 8.0, 9.0)
--
2.36.1
June 8, 2022
[PATCH vkd3d v6 7/9] vkd3d-shader/hlsl: Lower matrix casts.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl.y | 93 ++++++++++++++++++-
tests/hlsl-duplicate-modifiers.shader_test | 2 +-
tests/hlsl-initializer-matrix.shader_test | 2 +-
...lsl-return-implicit-conversion.shader_test | 8 +-
tests/hlsl-shape.shader_test | 10 +-
tests/matrix-semantics.shader_test | 12 +--
6 files changed, 106 insertions(+), 21 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
index cf0f51f2d..687569e83 100644
--- a/libs/vkd3d-shader/hlsl.y
+++ b/libs/vkd3d-shader/hlsl.y
@@ -266,6 +266,9 @@ static bool implicit_compatible_data_types(struct hlsl_type *t1, struct hlsl_typ
return false;
}
+static struct hlsl_ir_load *add_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_node,
+ struct hlsl_ir_node *offset, struct hlsl_type *data_type, const struct vkd3d_shader_location loc);
+
static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs,
struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc)
{
@@ -275,10 +278,92 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs,
if (hlsl_types_are_equal(src_type, dst_type))
return node;
- if (!(cast = hlsl_new_cast(ctx, node, dst_type, loc)))
- return NULL;
- list_add_tail(instrs, &cast->node.entry);
- return &cast->node;
+ if ((src_type->type == HLSL_CLASS_MATRIX || dst_type->type == HLSL_CLASS_MATRIX)
+ && src_type->type <= HLSL_CLASS_LAST_NUMERIC && dst_type->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ struct vkd3d_string_buffer *name;
+ static unsigned int counter = 0;
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+ unsigned int dst_idx;
+ bool broadcast;
+
+ broadcast = src_type->dimx == 1 && src_type->dimy == 1;
+ assert(dst_type->dimx * dst_type->dimy <= src_type->dimx * src_type->dimy || broadcast);
+ if (src_type->type == HLSL_CLASS_MATRIX && dst_type->type == HLSL_CLASS_MATRIX && !broadcast)
+ {
+ assert(dst_type->dimx <= src_type->dimx);
+ assert(dst_type->dimy <= src_type->dimy);
+ }
+
+ name = vkd3d_string_buffer_get(&ctx->string_buffers);
+ vkd3d_string_buffer_printf(name, "<cast-%u>", counter++);
+ var = hlsl_new_synthetic_var(ctx, name->buffer, dst_type, *loc);
+ vkd3d_string_buffer_release(&ctx->string_buffers, name);
+ if (!var)
+ return NULL;
+
+ for (dst_idx = 0; dst_idx < dst_type->dimx * dst_type->dimy; ++dst_idx)
+ {
+ struct hlsl_type *src_scalar_type, *dst_scalar_type;
+ unsigned int src_idx, src_offset, dst_offset;
+ struct hlsl_ir_store *store;
+ struct hlsl_ir_constant *c;
+
+ if (broadcast)
+ {
+ src_idx = 0;
+ }
+ else
+ {
+ if (src_type->type == HLSL_CLASS_MATRIX && dst_type->type == HLSL_CLASS_MATRIX)
+ {
+ unsigned int x = dst_idx % dst_type->dimx, y = dst_idx / dst_type->dimx;
+
+ src_idx = y * src_type->dimx + x;
+ }
+ else
+ {
+ src_idx = dst_idx;
+ }
+ }
+
+ dst_offset = hlsl_compute_component_offset(ctx, dst_type, dst_idx, &dst_scalar_type);
+ src_offset = hlsl_compute_component_offset(ctx, src_type, src_idx, &src_scalar_type);
+
+ if (!(c = hlsl_new_uint_constant(ctx, src_offset, loc)))
+ return NULL;
+ list_add_tail(instrs, &c->node.entry);
+
+ if (!(load = add_load(ctx, instrs, node, &c->node, src_scalar_type, *loc)))
+ return NULL;
+
+ if (!(cast = hlsl_new_cast(ctx, &load->node, dst_scalar_type, loc)))
+ return NULL;
+ list_add_tail(instrs, &cast->node.entry);
+
+ if (!(c = hlsl_new_uint_constant(ctx, dst_offset, loc)))
+ return NULL;
+ list_add_tail(instrs, &c->node.entry);
+
+ if (!(store = hlsl_new_store(ctx, var, &c->node, &cast->node, 0, *loc)))
+ return NULL;
+ list_add_tail(instrs, &store->node.entry);
+ }
+
+ if (!(load = hlsl_new_load(ctx, var, NULL, dst_type, *loc)))
+ return NULL;
+ list_add_tail(instrs, &load->node.entry);
+
+ return &load->node;
+ }
+ else
+ {
+ if (!(cast = hlsl_new_cast(ctx, node, dst_type, loc)))
+ return NULL;
+ list_add_tail(instrs, &cast->node.entry);
+ return &cast->node;
+ }
}
static struct hlsl_ir_node *add_implicit_conversion(struct hlsl_ctx *ctx, struct list *instrs,
diff --git a/tests/hlsl-duplicate-modifiers.shader_test b/tests/hlsl-duplicate-modifiers.shader_test
index fcae12da8..6491701ae 100644
--- a/tests/hlsl-duplicate-modifiers.shader_test
+++ b/tests/hlsl-duplicate-modifiers.shader_test
@@ -7,5 +7,5 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (0.1, 0.2, 0.3, 0.4)
diff --git a/tests/hlsl-initializer-matrix.shader_test b/tests/hlsl-initializer-matrix.shader_test
index ea9de9c03..7e12b0a00 100644
--- a/tests/hlsl-initializer-matrix.shader_test
+++ b/tests/hlsl-initializer-matrix.shader_test
@@ -55,7 +55,7 @@ float4 main() : SV_TARGET
}
[test]
-todo draw quad
+draw quad
probe all rgba (21, 22, 31, 32)
diff --git a/tests/hlsl-return-implicit-conversion.shader_test b/tests/hlsl-return-implicit-conversion.shader_test
index bf99d9cbd..545340eb3 100644
--- a/tests/hlsl-return-implicit-conversion.shader_test
+++ b/tests/hlsl-return-implicit-conversion.shader_test
@@ -5,7 +5,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (0.4, 0.3, 0.2, 0.1)
[pixel shader]
@@ -15,7 +15,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (0.4, 0.3, 0.2, 0.1)
[pixel shader]
@@ -25,7 +25,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (0.4, 0.3, 0.2, 0.1)
[pixel shader]
@@ -35,7 +35,7 @@ float4x1 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (0.4, 0.3, 0.2, 0.1)
[pixel shader]
diff --git a/tests/hlsl-shape.shader_test b/tests/hlsl-shape.shader_test
index 57d59534b..65cc322c1 100644
--- a/tests/hlsl-shape.shader_test
+++ b/tests/hlsl-shape.shader_test
@@ -211,7 +211,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -235,7 +235,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -260,7 +260,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 6.0, 8.0)
[pixel shader]
@@ -309,7 +309,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 0.0, 0.0)
[pixel shader]
@@ -321,7 +321,7 @@ float4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (2.0, 4.0, 0.0, 0.0)
[pixel shader]
diff --git a/tests/matrix-semantics.shader_test b/tests/matrix-semantics.shader_test
index 1be504064..43f467ecd 100644
--- a/tests/matrix-semantics.shader_test
+++ b/tests/matrix-semantics.shader_test
@@ -5,7 +5,7 @@ float4x1 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (1.0, 2.0, 3.0, 4.0)
[pixel shader]
@@ -15,7 +15,7 @@ row_major float1x4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe all rgba (1.0, 2.0, 3.0, 4.0)
[require]
@@ -44,7 +44,7 @@ row_major float4x1 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe render target 0 all r (1.0)
probe render target 1 all r (2.0)
probe render target 2 all r (3.0)
@@ -57,7 +57,7 @@ float1x4 main() : sv_target
}
[test]
-todo draw quad
+draw quad
probe render target 0 all r (1.0)
probe render target 1 all r (2.0)
probe render target 2 all r (3.0)
@@ -78,7 +78,7 @@ void main(out float1x2 x : sv_target0, out float1x2 y : sv_target2)
}
[test]
-todo draw quad
+draw quad
probe render target 0 all r (1.0)
probe render target 1 all r (2.0)
probe render target 2 all r (5.0)
@@ -96,7 +96,7 @@ void main(out row_major float1x4 x : sv_target0, out float1x2 y : sv_target1)
}
[test]
-todo draw quad
+draw quad
probe render target 0 all rgba (1.0, 2.0, 3.0, 4.0)
probe render target 1 all r (5.0)
probe render target 2 all r (6.0)
--
2.36.1
June 8, 2022
[PATCH vkd3d v6 6/9] tests: Test how matrix types interact with semantics.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
Makefile.am | 1 +
tests/matrix-semantics.shader_test | 102 +++++++++++++++++++++++++++++
2 files changed, 103 insertions(+)
create mode 100644 tests/matrix-semantics.shader_test
diff --git a/Makefile.am b/Makefile.am
index 6e827175a..bdbf8e408 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -108,6 +108,7 @@ vkd3d_shader_tests = \
tests/hlsl-vector-indexing-uniform.shader_test \
tests/logic-operations.shader_test \
tests/math.shader_test \
+ tests/matrix-semantics.shader_test \
tests/multiple-rt.shader_test \
tests/nointerpolation.shader_test \
tests/pow.shader_test \
diff --git a/tests/matrix-semantics.shader_test b/tests/matrix-semantics.shader_test
new file mode 100644
index 000000000..1be504064
--- /dev/null
+++ b/tests/matrix-semantics.shader_test
@@ -0,0 +1,102 @@
+[pixel shader]
+float4x1 main() : sv_target
+{
+ return float4(1.0, 2.0, 3.0, 4.0);
+}
+
+[test]
+todo draw quad
+probe all rgba (1.0, 2.0, 3.0, 4.0)
+
+[pixel shader]
+row_major float1x4 main() : sv_target
+{
+ return float4(1.0, 2.0, 3.0, 4.0);
+}
+
+[test]
+todo draw quad
+probe all rgba (1.0, 2.0, 3.0, 4.0)
+
+[require]
+shader model >= 4.0
+
+[render target 0]
+format r32 float
+size (640, 480)
+
+[render target 1]
+format r32 float
+size (640, 480)
+
+[render target 2]
+format r32 float
+size (640, 480)
+
+[render target 3]
+format r32 float
+size (640, 480)
+
+[pixel shader]
+row_major float4x1 main() : sv_target
+{
+ return float4(1.0, 2.0, 3.0, 4.0);
+}
+
+[test]
+todo draw quad
+probe render target 0 all r (1.0)
+probe render target 1 all r (2.0)
+probe render target 2 all r (3.0)
+probe render target 3 all r (4.0)
+
+[pixel shader]
+float1x4 main() : sv_target
+{
+ return float4(1.0, 2.0, 3.0, 4.0);
+}
+
+[test]
+todo draw quad
+probe render target 0 all r (1.0)
+probe render target 1 all r (2.0)
+probe render target 2 all r (3.0)
+probe render target 3 all r (4.0)
+
+[pixel shader fail todo]
+void main(out float1x2 x : sv_target0, out float1x2 y : sv_target1)
+{
+ x = float2(1.0, 2.0);
+ y = float2(5.0, 6.0);
+}
+
+[pixel shader]
+void main(out float1x2 x : sv_target0, out float1x2 y : sv_target2)
+{
+ x = float2(1.0, 2.0);
+ y = float2(5.0, 6.0);
+}
+
+[test]
+todo draw quad
+probe render target 0 all r (1.0)
+probe render target 1 all r (2.0)
+probe render target 2 all r (5.0)
+probe render target 3 all r (6.0)
+
+[render target 0]
+format r32g32b32a32 float
+size (640, 480)
+
+[pixel shader]
+void main(out row_major float1x4 x : sv_target0, out float1x2 y : sv_target1)
+{
+ x = float4(1.0, 2.0, 3.0, 4.0);
+ y = float2(5.0, 6.0);
+}
+
+[test]
+todo draw quad
+probe render target 0 all rgba (1.0, 2.0, 3.0, 4.0)
+probe render target 1 all r (5.0)
+probe render target 2 all r (6.0)
--
2.36.1
June 8, 2022