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 4/6] uiautomationcore/tests: Store test IAccessible data in structures.
by Connor McAdams
From: Connor McAdams <cmcadams(a)codeweavers.com>
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
dlls/uiautomationcore/tests/uiautomation.c | 151 ++++++++++++---------
1 file changed, 90 insertions(+), 61 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 344fd2cdbf0..f61a4b21c50 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -61,13 +61,6 @@ DEFINE_EXPECT(Accessible_get_accParent);
DEFINE_EXPECT(Accessible_child_accNavigate);
DEFINE_EXPECT(Accessible_child_get_accParent);
-static LONG Accessible_ref = 1;
-static LONG Accessible_child_ref = 1;
-static IAccessible Accessible;
-static IAccessible Accessible_child;
-static IOleWindow OleWindow;
-static HWND Accessible_hwnd = NULL;
-static HWND OleWindow_hwnd = NULL;
static IAccessible *acc_client;
static BOOL check_variant_i4(VARIANT *v, int val)
@@ -78,14 +71,32 @@ static BOOL check_variant_i4(VARIANT *v, int val)
return FALSE;
}
+static struct Accessible
+{
+ IAccessible IAccessible_iface;
+ IOleWindow IOleWindow_iface;
+ LONG ref;
+
+ IAccessible *parent;
+ HWND acc_hwnd;
+ HWND ow_hwnd;
+} Accessible, Accessible_child;
+
+static inline struct Accessible* impl_from_Accessible(IAccessible *iface)
+{
+ return CONTAINING_RECORD(iface, struct Accessible, IAccessible_iface);
+}
+
static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid, void **obj)
{
+ struct Accessible *This = impl_from_Accessible(iface);
+
*obj = NULL;
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IAccessible))
*obj = iface;
- else if (IsEqualIID(riid, &IID_IOleWindow) && (iface == &Accessible))
- *obj = &OleWindow;
+ else if (IsEqualIID(riid, &IID_IOleWindow))
+ *obj = &This->IOleWindow_iface;
else
return E_NOINTERFACE;
@@ -95,18 +106,14 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
static ULONG WINAPI Accessible_AddRef(IAccessible *iface)
{
- if (iface == &Accessible_child)
- return InterlockedIncrement(&Accessible_child_ref);
- else
- return InterlockedIncrement(&Accessible_ref);
+ struct Accessible *This = impl_from_Accessible(iface);
+ return InterlockedIncrement(&This->ref);
}
static ULONG WINAPI Accessible_Release(IAccessible *iface)
{
- if (iface == &Accessible_child)
- return InterlockedDecrement(&Accessible_child_ref);
- else
- return InterlockedDecrement(&Accessible_ref);
+ struct Accessible *This = impl_from_Accessible(iface);
+ return InterlockedDecrement(&This->ref);
}
static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
@@ -139,14 +146,16 @@ static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID disp_id_membe
static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **out_parent)
{
- if (iface == &Accessible_child)
- {
+ struct Accessible *This = impl_from_Accessible(iface);
+
+ if (This == &Accessible_child)
CHECK_EXPECT(Accessible_child_get_accParent);
- return IAccessible_QueryInterface(&Accessible, &IID_IDispatch, (void **)out_parent);
- }
else
CHECK_EXPECT(Accessible_get_accParent);
+ if (This->parent)
+ return IAccessible_QueryInterface(This->parent, &IID_IDispatch, (void **)out_parent);
+
*out_parent = NULL;
return S_FALSE;
}
@@ -256,7 +265,9 @@ static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left,
static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG nav_direction,
VARIANT child_id_start, VARIANT *out_var)
{
- if (iface == &Accessible_child)
+ struct Accessible *This = impl_from_Accessible(iface);
+
+ if (This == &Accessible_child)
CHECK_EXPECT(Accessible_child_accNavigate);
else
CHECK_EXPECT(Accessible_accNavigate);
@@ -267,10 +278,10 @@ static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG nav_direct
* IAccessible's contained in a Direct Annotation wrapper object.
*/
if ((nav_direction == NAVDIR_INTERNAL_HWND) && check_variant_i4(&child_id_start, CHILDID_SELF) &&
- Accessible_hwnd)
+ This->acc_hwnd)
{
V_VT(out_var) = VT_I4;
- V_I4(out_var) = HandleToUlong(Accessible_hwnd);
+ V_I4(out_var) = HandleToUlong(This->acc_hwnd);
return S_OK;
}
return S_FALSE;
@@ -334,30 +345,35 @@ static IAccessibleVtbl AccessibleVtbl = {
Accessible_put_accValue
};
+static inline struct Accessible* impl_from_OleWindow(IOleWindow *iface)
+{
+ return CONTAINING_RECORD(iface, struct Accessible, IOleWindow_iface);
+}
+
static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **obj)
{
- return IAccessible_QueryInterface(&Accessible, riid, obj);
+ struct Accessible *This = impl_from_OleWindow(iface);
+ return IAccessible_QueryInterface(&This->IAccessible_iface, riid, obj);
}
static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
{
- return IAccessible_AddRef(&Accessible);
+ struct Accessible *This = impl_from_OleWindow(iface);
+ return IAccessible_AddRef(&This->IAccessible_iface);
}
static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
{
- return IAccessible_Release(&Accessible);
+ struct Accessible *This = impl_from_OleWindow(iface);
+ return IAccessible_Release(&This->IAccessible_iface);
}
static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
{
- if (OleWindow_hwnd)
- {
- *hwnd = OleWindow_hwnd;
- return S_OK;
- }
+ struct Accessible *This = impl_from_OleWindow(iface);
- return E_FAIL;
+ *hwnd = This->ow_hwnd;
+ return *hwnd ? S_OK : E_FAIL;
}
static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL f_enter_mode)
@@ -373,9 +389,22 @@ static const IOleWindowVtbl OleWindowVtbl = {
OleWindow_ContextSensitiveHelp
};
-static IAccessible Accessible = {&AccessibleVtbl};
-static IAccessible Accessible_child = {&AccessibleVtbl};
-static IOleWindow OleWindow = {&OleWindowVtbl};
+static struct Accessible Accessible =
+{
+ { &AccessibleVtbl },
+ { &OleWindowVtbl },
+ 1,
+ NULL,
+ 0, 0
+};
+static struct Accessible Accessible_child =
+{
+ { &AccessibleVtbl },
+ { &OleWindowVtbl },
+ 1,
+ &Accessible.IAccessible_iface,
+ 0, 0
+};
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
@@ -663,7 +692,7 @@ static void test_UiaProviderFromIAccessible(void)
hr = pUiaProviderFromIAccessible(NULL, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
- hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, NULL);
+ hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, NULL);
ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/*
@@ -682,9 +711,9 @@ static void test_UiaProviderFromIAccessible(void)
/* Don't return an HWND from accNavigate or OleWindow. */
SET_EXPECT(Accessible_accNavigate);
SET_EXPECT(Accessible_get_accParent);
- Accessible_hwnd = NULL;
- OleWindow_hwnd = NULL;
- hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ Accessible.acc_hwnd = NULL;
+ Accessible.ow_hwnd = NULL;
+ hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(Accessible_accNavigate);
CHECK_CALLED(Accessible_get_accParent);
@@ -692,15 +721,15 @@ static void test_UiaProviderFromIAccessible(void)
/* Return an HWND from accNavigate, not OleWindow. */
SET_EXPECT(Accessible_accNavigate);
SET_EXPECT(winproc_GETOBJECT_CLIENT);
- acc_client = &Accessible;
- Accessible_hwnd = hwnd;
- OleWindow_hwnd = NULL;
- hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ acc_client = &Accessible.IAccessible_iface;
+ Accessible.acc_hwnd = hwnd;
+ Accessible.ow_hwnd = NULL;
+ hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(Accessible_accNavigate);
- ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
IRawElementProviderSimple_Release(elprov);
- ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
acc_client = NULL;
/* Skip tests on Win10v1507. */
@@ -714,22 +743,22 @@ static void test_UiaProviderFromIAccessible(void)
/* Return an HWND from parent IAccessible's IOleWindow interface. */
SET_EXPECT(Accessible_child_accNavigate);
SET_EXPECT(Accessible_child_get_accParent);
- Accessible_hwnd = NULL;
- OleWindow_hwnd = hwnd;
- hr = pUiaProviderFromIAccessible(&Accessible_child, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ Accessible.acc_hwnd = NULL;
+ Accessible.ow_hwnd = hwnd;
+ hr = pUiaProviderFromIAccessible(&Accessible_child.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(Accessible_child_accNavigate);
CHECK_CALLED(Accessible_child_get_accParent);
- ok(Accessible_child_ref == 2, "Unexpected refcnt %ld\n", Accessible_child_ref);
+ ok(Accessible_child.ref == 2, "Unexpected refcnt %ld\n", Accessible_child.ref);
IRawElementProviderSimple_Release(elprov);
- ok(Accessible_child_ref == 1, "Unexpected refcnt %ld\n", Accessible_child_ref);
+ ok(Accessible_child.ref == 1, "Unexpected refcnt %ld\n", Accessible_child.ref);
/* Return an HWND from OleWindow, not accNavigate. */
- Accessible_hwnd = NULL;
- OleWindow_hwnd = hwnd;
- hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ Accessible.acc_hwnd = NULL;
+ Accessible.ow_hwnd = hwnd;
+ hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opt);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -743,19 +772,19 @@ static void test_UiaProviderFromIAccessible(void)
VariantClear(&v);
IRawElementProviderSimple_Release(elprov);
- ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
/* ChildID other than CHILDID_SELF. */
- hr = pUiaProviderFromIAccessible(&Accessible, 1, UIA_PFIA_DEFAULT, &elprov);
+ hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, 1, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
IRawElementProviderSimple_Release(elprov);
- ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+ ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
DestroyWindow(hwnd);
UnregisterClassA("pUiaProviderFromIAccessible class", NULL);
- Accessible_hwnd = NULL;
- OleWindow_hwnd = NULL;
+ Accessible.acc_hwnd = NULL;
+ Accessible.ow_hwnd = NULL;
}
START_TEST(uiautomation)
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/207
June 8, 2022
[PATCH 3/6] uiautomationcore: Use WindowFromAccessibleObject to get HWND in UiaProviderFromIAccessible.
by Connor McAdams
From: Connor McAdams <cmcadams(a)codeweavers.com>
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
dlls/uiautomationcore/Makefile.in | 2 +-
dlls/uiautomationcore/tests/uiautomation.c | 64 +++++++++++++++++++---
dlls/uiautomationcore/uia_provider.c | 28 ++--------
3 files changed, 61 insertions(+), 33 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in
index 61a560d6c2e..a1cf5575814 100644
--- a/dlls/uiautomationcore/Makefile.in
+++ b/dlls/uiautomationcore/Makefile.in
@@ -1,6 +1,6 @@
MODULE = uiautomationcore.dll
IMPORTLIB = uiautomationcore
-IMPORTS = uuid ole32 oleaut32 user32
+IMPORTS = uuid ole32 oleaut32 user32 oleacc
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 704e43180bd..344fd2cdbf0 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -53,11 +53,18 @@ static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD,
expect_ ## func = called_ ## func = FALSE; \
}while(0)
+#define NAVDIR_INTERNAL_HWND 10
+
DEFINE_EXPECT(winproc_GETOBJECT_CLIENT);
DEFINE_EXPECT(Accessible_accNavigate);
+DEFINE_EXPECT(Accessible_get_accParent);
+DEFINE_EXPECT(Accessible_child_accNavigate);
+DEFINE_EXPECT(Accessible_child_get_accParent);
static LONG Accessible_ref = 1;
+static LONG Accessible_child_ref = 1;
static IAccessible Accessible;
+static IAccessible Accessible_child;
static IOleWindow OleWindow;
static HWND Accessible_hwnd = NULL;
static HWND OleWindow_hwnd = NULL;
@@ -77,7 +84,7 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IAccessible))
*obj = iface;
- else if (IsEqualIID(riid, &IID_IOleWindow))
+ else if (IsEqualIID(riid, &IID_IOleWindow) && (iface == &Accessible))
*obj = &OleWindow;
else
return E_NOINTERFACE;
@@ -88,12 +95,18 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
static ULONG WINAPI Accessible_AddRef(IAccessible *iface)
{
- return InterlockedIncrement(&Accessible_ref);
+ if (iface == &Accessible_child)
+ return InterlockedIncrement(&Accessible_child_ref);
+ else
+ return InterlockedIncrement(&Accessible_ref);
}
static ULONG WINAPI Accessible_Release(IAccessible *iface)
{
- return InterlockedDecrement(&Accessible_ref);
+ if (iface == &Accessible_child)
+ return InterlockedDecrement(&Accessible_child_ref);
+ else
+ return InterlockedDecrement(&Accessible_ref);
}
static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo)
@@ -126,8 +139,16 @@ static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID disp_id_membe
static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **out_parent)
{
- ok(0, "unexpected call\n");
- return E_NOTIMPL;
+ if (iface == &Accessible_child)
+ {
+ CHECK_EXPECT(Accessible_child_get_accParent);
+ return IAccessible_QueryInterface(&Accessible, &IID_IDispatch, (void **)out_parent);
+ }
+ else
+ CHECK_EXPECT(Accessible_get_accParent);
+
+ *out_parent = NULL;
+ return S_FALSE;
}
static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *out_count)
@@ -235,14 +256,18 @@ static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left,
static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG nav_direction,
VARIANT child_id_start, VARIANT *out_var)
{
- CHECK_EXPECT(Accessible_accNavigate);
+ if (iface == &Accessible_child)
+ CHECK_EXPECT(Accessible_child_accNavigate);
+ else
+ CHECK_EXPECT(Accessible_accNavigate);
VariantInit(out_var);
/*
* This is an undocumented way for UI Automation to get an HWND for
* IAccessible's contained in a Direct Annotation wrapper object.
*/
- if ((nav_direction == 10) && check_variant_i4(&child_id_start, CHILDID_SELF))
+ if ((nav_direction == NAVDIR_INTERNAL_HWND) && check_variant_i4(&child_id_start, CHILDID_SELF) &&
+ Accessible_hwnd)
{
V_VT(out_var) = VT_I4;
V_I4(out_var) = HandleToUlong(Accessible_hwnd);
@@ -326,8 +351,13 @@ static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
{
- *hwnd = OleWindow_hwnd;
- return S_OK;
+ if (OleWindow_hwnd)
+ {
+ *hwnd = OleWindow_hwnd;
+ return S_OK;
+ }
+
+ return E_FAIL;
}
static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL f_enter_mode)
@@ -344,6 +374,7 @@ static const IOleWindowVtbl OleWindowVtbl = {
};
static IAccessible Accessible = {&AccessibleVtbl};
+static IAccessible Accessible_child = {&AccessibleVtbl};
static IOleWindow OleWindow = {&OleWindowVtbl};
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
@@ -650,11 +681,13 @@ static void test_UiaProviderFromIAccessible(void)
/* Don't return an HWND from accNavigate or OleWindow. */
SET_EXPECT(Accessible_accNavigate);
+ SET_EXPECT(Accessible_get_accParent);
Accessible_hwnd = NULL;
OleWindow_hwnd = NULL;
hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(Accessible_accNavigate);
+ CHECK_CALLED(Accessible_get_accParent);
/* Return an HWND from accNavigate, not OleWindow. */
SET_EXPECT(Accessible_accNavigate);
@@ -678,6 +711,19 @@ static void test_UiaProviderFromIAccessible(void)
}
expect_winproc_GETOBJECT_CLIENT = FALSE;
+ /* Return an HWND from parent IAccessible's IOleWindow interface. */
+ SET_EXPECT(Accessible_child_accNavigate);
+ SET_EXPECT(Accessible_child_get_accParent);
+ Accessible_hwnd = NULL;
+ OleWindow_hwnd = hwnd;
+ hr = pUiaProviderFromIAccessible(&Accessible_child, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+ CHECK_CALLED(Accessible_child_accNavigate);
+ CHECK_CALLED(Accessible_child_get_accParent);
+ ok(Accessible_child_ref == 2, "Unexpected refcnt %ld\n", Accessible_child_ref);
+ IRawElementProviderSimple_Release(elprov);
+ ok(Accessible_child_ref == 1, "Unexpected refcnt %ld\n", Accessible_child_ref);
+
/* Return an HWND from OleWindow, not accNavigate. */
Accessible_hwnd = NULL;
OleWindow_hwnd = hwnd;
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c
index 790593dbcab..d2a0da15c3c 100644
--- a/dlls/uiautomationcore/uia_provider.c
+++ b/dlls/uiautomationcore/uia_provider.c
@@ -151,7 +151,6 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
struct msaa_provider *msaa_prov;
IServiceProvider *serv_prov;
HWND hwnd = NULL;
- IOleWindow *win;
HRESULT hr;
TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
@@ -187,28 +186,11 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
IServiceProvider_Release(serv_prov);
}
- hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void **)&win);
- if (SUCCEEDED(hr))
- {
- hr = IOleWindow_GetWindow(win, &hwnd);
- if (FAILED(hr))
- hwnd = NULL;
- IOleWindow_Release(win);
- }
-
- if (!IsWindow(hwnd))
- {
- VARIANT v, cid;
-
- VariantInit(&v);
- variant_init_i4(&cid, CHILDID_SELF);
- hr = IAccessible_accNavigate(acc, 10, cid, &v);
- if (SUCCEEDED(hr) && V_VT(&v) == VT_I4)
- hwnd = ULongToHandle(V_I4(&v));
-
- if (!IsWindow(hwnd))
- return E_FAIL;
- }
+ hr = WindowFromAccessibleObject(acc, &hwnd);
+ if (FAILED(hr))
+ return hr;
+ if (!hwnd)
+ return E_FAIL;
msaa_prov = heap_alloc(sizeof(*msaa_prov));
if (!msaa_prov)
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/207
June 8, 2022
[PATCH 2/6] uiautomationcore/tests: Skip UiaProviderFromIAccessible tests on Win10v1507.
by Connor McAdams
From: Connor McAdams <cmcadams(a)codeweavers.com>
In Windows 10 version 1507, UiaProviderFromIAccessible will try to check
the IAccessible passed in against the root IAccessible of the HWND
associated with the passed in IAccessible. In all other Windows
versions, this check is done on a call to get_HostRawElementProvider, or
the first time navigating towards a parent or sibling. Rather than work
around this, just skip the tests if this happens.
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
dlls/uiautomationcore/tests/uiautomation.c | 36 ++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 246f8aba7c1..704e43180bd 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -53,6 +53,7 @@ static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD,
expect_ ## func = called_ ## func = FALSE; \
}while(0)
+DEFINE_EXPECT(winproc_GETOBJECT_CLIENT);
DEFINE_EXPECT(Accessible_accNavigate);
static LONG Accessible_ref = 1;
@@ -60,6 +61,7 @@ static IAccessible Accessible;
static IOleWindow OleWindow;
static HWND Accessible_hwnd = NULL;
static HWND OleWindow_hwnd = NULL;
+static IAccessible *acc_client;
static BOOL check_variant_i4(VARIANT *v, int val)
{
@@ -130,6 +132,7 @@ static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **o
static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *out_count)
{
+ ok(0, "unexpected call\n");
return E_NOTIMPL;
}
@@ -143,6 +146,7 @@ static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT child_
static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT child_id,
BSTR *out_name)
{
+ ok(0, "unexpected call\n");
return E_NOTIMPL;
}
@@ -163,12 +167,14 @@ static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT
static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT child_id,
VARIANT *out_role)
{
+ ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT child_id,
VARIANT *out_state)
{
+ ok(0, "unexpected call\n");
return E_NOTIMPL;
}
@@ -222,6 +228,7 @@ static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG select_flags
static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left,
LONG *out_top, LONG *out_width, LONG *out_height, VARIANT child_id)
{
+ ok(0, "unexpected call\n");
return E_NOTIMPL;
}
@@ -341,6 +348,24 @@ static IOleWindow OleWindow = {&OleWindowVtbl};
static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
+ switch (message)
+ {
+ case WM_GETOBJECT:
+ if (lParam == (DWORD)OBJID_CLIENT)
+ {
+ CHECK_EXPECT(winproc_GETOBJECT_CLIENT);
+ if (acc_client)
+ return LresultFromObject(&IID_IAccessible, wParam, (IUnknown *)acc_client);
+
+ break;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
return DefWindowProcA(hwnd, message, wParam, lParam);
}
@@ -633,6 +658,8 @@ static void test_UiaProviderFromIAccessible(void)
/* Return an HWND from accNavigate, not OleWindow. */
SET_EXPECT(Accessible_accNavigate);
+ SET_EXPECT(winproc_GETOBJECT_CLIENT);
+ acc_client = &Accessible;
Accessible_hwnd = hwnd;
OleWindow_hwnd = NULL;
hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
@@ -641,6 +668,15 @@ static void test_UiaProviderFromIAccessible(void)
ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref);
IRawElementProviderSimple_Release(elprov);
ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref);
+ acc_client = NULL;
+
+ /* Skip tests on Win10v1507. */
+ if (called_winproc_GETOBJECT_CLIENT)
+ {
+ win_skip("UiaProviderFromIAccessible behaves inconsistently on Win10 1507, skipping tests.\n");
+ return;
+ }
+ expect_winproc_GETOBJECT_CLIENT = FALSE;
/* Return an HWND from OleWindow, not accNavigate. */
Accessible_hwnd = NULL;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/207
June 8, 2022
[PATCH 1/6] include: Add UI Automation Control Type ID definitions.
by Connor McAdams
From: Connor McAdams <cmcadams(a)codeweavers.com>
Signed-off-by: Connor McAdams <cmcadams(a)codeweavers.com>
---
include/uiautomationclient.idl | 49 ++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl
index 917d3456ebf..43ac6b0752f 100644
--- a/include/uiautomationclient.idl
+++ b/include/uiautomationclient.idl
@@ -253,4 +253,53 @@ library UIAutomationClient {
/*
}
*/
+ /* FIXME: Uncomment when properly supported in widl
+ [dllname("<no entry points>")]
+ module UIA_ControlTypeIds
+ {
+ */
+ const long UIA_ButtonControlTypeId = 50000;
+ const long UIA_CalendarControlTypeId = 50001;
+ const long UIA_CheckBoxControlTypeId = 50002;
+ const long UIA_ComboBoxControlTypeId = 50003;
+ const long UIA_EditControlTypeId = 50004;
+ const long UIA_HyperlinkControlTypeId = 50005;
+ const long UIA_ImageControlTypeId = 50006;
+ const long UIA_ListItemControlTypeId = 50007;
+ const long UIA_ListControlTypeId = 50008;
+ const long UIA_MenuControlTypeId = 50009;
+ const long UIA_MenuBarControlTypeId = 50010;
+ const long UIA_MenuItemControlTypeId = 50011;
+ const long UIA_ProgressBarControlTypeId = 50012;
+ const long UIA_RadioButtonControlTypeId = 50013;
+ const long UIA_ScrollBarControlTypeId = 50014;
+ const long UIA_SliderControlTypeId = 50015;
+ const long UIA_SpinnerControlTypeId = 50016;
+ const long UIA_StatusBarControlTypeId = 50017;
+ const long UIA_TabControlTypeId = 50018;
+ const long UIA_TabItemControlTypeId = 50019;
+ const long UIA_TextControlTypeId = 50020;
+ const long UIA_ToolBarControlTypeId = 50021;
+ const long UIA_ToolTipControlTypeId = 50022;
+ const long UIA_TreeControlTypeId = 50023;
+ const long UIA_TreeItemControlTypeId = 50024;
+ const long UIA_CustomControlTypeId = 50025;
+ const long UIA_GroupControlTypeId = 50026;
+ const long UIA_ThumbControlTypeId = 50027;
+ const long UIA_DataGridControlTypeId = 50028;
+ const long UIA_DataItemControlTypeId = 50029;
+ const long UIA_DocumentControlTypeId = 50030;
+ const long UIA_SplitButtonControlTypeId = 50031;
+ const long UIA_WindowControlTypeId = 50032;
+ const long UIA_PaneControlTypeId = 50033;
+ const long UIA_HeaderControlTypeId = 50034;
+ const long UIA_HeaderItemControlTypeId = 50035;
+ const long UIA_TableControlTypeId = 50036;
+ const long UIA_TitleBarControlTypeId = 50037;
+ const long UIA_SeparatorControlTypeId = 50038;
+ const long UIA_SemanticZoomControlTypeId = 50039;
+ const long UIA_AppBarControlTypeId = 50040;
+ /*
+ };
+ */
}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/207
June 8, 2022
[PATCH 0/6] MR207: UiaProviderFromIAccessible improvements.
by Connor McAdams (ï¼ cmcadams)
Add support for get_accState and get_accRole in UI Automation, along with various other cleanups.
--
https://gitlab.winehq.org/wine/wine/-/merge_requests/207
June 8, 2022
Re: [PATCH 6/6] uiautomationcore: Implement MSAA accState based property IDs for MSAA providers.
by Connor McAdams
On Wed, Jun 08, 2022 at 10:04:43AM +0100, Huw Davies wrote:
> On Wed, May 25, 2022 at 02:37:39PM -0400, Connor McAdams wrote:
> > static void test_UiaProviderFromIAccessible(void)
> > diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c
> > index ab2b8305b10..69bc78e34c0 100644
> > --- a/dlls/uiautomationcore/uia_provider.c
> > +++ b/dlls/uiautomationcore/uia_provider.c
> > @@ -32,6 +32,25 @@ static void variant_init_i4(VARIANT *v, int val)
> > V_I4(v) = val;
> > }
> >
> > +static void variant_init_bool(VARIANT *v, BOOL val)
> > +{
> > + V_VT(v) = VT_BOOL;
> > + V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE;
> > +}
> > +
> > +static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, LONG flag)
>
> DWORD/ULONG flag.
>
> > +{
> > + HRESULT hr;
> > + VARIANT v;
> > +
> > + VariantInit(&v);
> > + hr = IAccessible_get_accState(acc, cid, &v);
> > + if (SUCCEEDED(hr) && V_VT(&v) == VT_I4 && (V_I4(&v) & flag))
> > + return TRUE;
> > +
> > + return FALSE;
> > +}
> > +
> > static LONG msaa_role_to_uia_control_type(LONG role)
> > {
> > switch (role)
> > @@ -214,6 +233,26 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
> >
> > break;
> >
> > + case UIA_HasKeyboardFocusPropertyId:
> > + variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
> > + STATE_SYSTEM_FOCUSED));
>
> Unless you have need for these two helpers down the line, I'd combine
> them, i.e. have _check_acc_state() return a VARIANT.
>
I use msaa_check_acc_state separately in a later patch, so it helps to
have them separate.
> Huw.
>
> P.S. bonus points will be awarded for using gitlab to send v2 ;-)
Okee doke, will fix the LONG flag and try out a gitlab PR.
Thanks!
June 8, 2022
Re: [PATCH vkd3d v5 08/14] tests: Test how matrix types interact with semantics.
by Giovanni Mascellani
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Il 07/06/22 23:29, Zebediah Figura ha scritto:
> From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
>
> Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
> ---
> v5: Expand to bind and test all used render targets.
>
> 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)
June 8, 2022
Re: [PATCH vkd3d v5 07/14] tests: Add a test for multiple render targets.
by Giovanni Mascellani
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Il 07/06/22 23:29, Zebediah Figura ha scritto:
> Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
> ---
> v5: New patch.
>
> Makefile.am | 1 +
> tests/multiple-rt.shader_test | 19 +++++++++++++++++++
> tests/shader_runner.c | 26 ++++++++++++++++++++++++--
> 3 files changed, 44 insertions(+), 2 deletions(-)
> create mode 100644 tests/multiple-rt.shader_test
>
> diff --git a/Makefile.am b/Makefile.am
> index 400dc8aae..6e827175a 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/multiple-rt.shader_test \
> tests/nointerpolation.shader_test \
> tests/pow.shader_test \
> tests/preproc-if.shader_test \
> diff --git a/tests/multiple-rt.shader_test b/tests/multiple-rt.shader_test
> new file mode 100644
> index 000000000..59e4acbbe
> --- /dev/null
> +++ b/tests/multiple-rt.shader_test
> @@ -0,0 +1,19 @@
> +[render target 0]
> +format r32g32b32a32 float
> +size (640, 480)
> +
> +[render target 1]
> +format r32g32b32a32 float
> +size (640, 480)
> +
> +[pixel shader]
> +void main(out float4 o0 : sv_target0, out float4 o1 : sv_target1)
> +{
> + o0 = float4(0.1, 0.2, 0.3, 0.4);
> + o1 = float4(0.5, 0.6, 0.7, 0.8);
> +}
> +
> +[test]
> +draw quad
> +probe render target 0 all rgba (0.1, 0.2, 0.3, 0.4)
> +probe render target 1 all rgba (0.5, 0.6, 0.7, 0.8)
> diff --git a/tests/shader_runner.c b/tests/shader_runner.c
> index e2dc2dda6..25986b316 100644
> --- a/tests/shader_runner.c
> +++ b/tests/shader_runner.c
> @@ -468,7 +468,7 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> }
> else if (match_string(line, "probe", &line))
> {
> - unsigned int left, top, right, bottom, ulps;
> + unsigned int left, top, right, bottom, ulps, slot;
> struct resource_readback *rb;
> struct resource *resource;
> int ret, len;
> @@ -479,7 +479,7 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
>
> if (match_string(line, "uav", &line))
> {
> - unsigned int slot = strtoul(line, &rest, 10);
> + slot = strtoul(line, &rest, 10);
>
> if (rest == line)
> fatal_error("Malformed UAV index '%s'.\n", line);
> @@ -487,6 +487,16 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
>
> resource = get_resource(runner, RESOURCE_TYPE_UAV, slot);
> }
> + else if (match_string(line, "render target", &line))
> + {
> + slot = strtoul(line, &rest, 10);
> +
> + if (rest == line)
> + fatal_error("Malformed render target index '%s'.\n", line);
> + line = rest;
> +
> + resource = get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, slot);
> + }
> else
> {
> resource = get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0);
> @@ -836,6 +846,18 @@ void run_shader_tests(struct shader_runner *runner, int argc, char **argv, const
> current_sampler->v_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
> current_sampler->w_address = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
> }
> + else if (sscanf(line, "[render target %u]\n", &index))
> + {
> + state = STATE_RESOURCE;
> +
> + memset(¤t_resource, 0, sizeof(current_resource));
> +
> + current_resource.slot = index;
> + current_resource.type = RESOURCE_TYPE_RENDER_TARGET;
> + current_resource.format = DXGI_FORMAT_R32G32B32A32_FLOAT;
> + current_resource.data_type = TEXTURE_DATA_FLOAT;
> + current_resource.texel_size = 16;
> + }
> else if (sscanf(line, "[texture %u]\n", &index))
> {
> state = STATE_RESOURCE;
June 8, 2022
Re: [PATCH vkd3d v5 06/14] tests: Add a basic shader test for UAVs.
by Giovanni Mascellani
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Il 07/06/22 23:29, Zebediah Figura ha scritto:
> Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
> ---
> v5: New patch.
>
> Makefile.am | 1 +
> tests/shader_runner.c | 22 ++++++++++++--
> tests/shader_runner_d3d12.c | 10 +++++--
> tests/shader_runner_vulkan.c | 12 ++++----
> tests/uav.shader_test | 56 ++++++++++++++++++++++++++++++++++++
> 5 files changed, 90 insertions(+), 11 deletions(-)
> create mode 100644 tests/uav.shader_test
>
> diff --git a/Makefile.am b/Makefile.am
> index dd3ce1ff6..400dc8aae 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -132,6 +132,7 @@ vkd3d_shader_tests = \
> tests/texture-load.shader_test \
> tests/texture-load-typed.shader_test \
> tests/trigonometry.shader_test \
> + tests/uav.shader_test \
> tests/writemask-assignop-0.shader_test \
> tests/writemask-assignop-1.shader_test \
> tests/writemask-assignop-2.shader_test \
> diff --git a/tests/shader_runner.c b/tests/shader_runner.c
> index f367027f7..e2dc2dda6 100644
> --- a/tests/shader_runner.c
> +++ b/tests/shader_runner.c
> @@ -370,6 +370,8 @@ static void set_uniforms(struct shader_runner *runner, size_t offset, size_t cou
>
> static void parse_test_directive(struct shader_runner *runner, const char *line)
> {
> + char *rest;
> +
> runner->is_todo = false;
>
> if (match_string(line, "todo", &line))
> @@ -475,19 +477,33 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> if (runner->last_render_failed)
> return;
>
> - resource = get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0);
> + if (match_string(line, "uav", &line))
> + {
> + unsigned int slot = strtoul(line, &rest, 10);
> +
> + if (rest == line)
> + fatal_error("Malformed UAV index '%s'.\n", line);
> + line = rest;
> +
> + resource = get_resource(runner, RESOURCE_TYPE_UAV, slot);
> + }
> + else
> + {
> + resource = get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0);
> + }
> +
> rb = runner->ops->get_resource_readback(runner, resource);
>
> if (match_string(line, "all", &line))
> {
> set_rect(&rect, 0, 0, resource->width, resource->height);
> }
> - else if (sscanf(line, "( %d , %d , %d , %d )%n", &left, &top, &right, &bottom, &len) == 4)
> + else if (sscanf(line, " ( %d , %d , %d , %d )%n", &left, &top, &right, &bottom, &len) == 4)
> {
> set_rect(&rect, left, top, right, bottom);
> line += len;
> }
> - else if (sscanf(line, "( %u , %u )%n", &left, &top, &len) == 2)
> + else if (sscanf(line, " ( %u , %u )%n", &left, &top, &len) == 2)
> {
> set_rect(&rect, left, top, left + 1, top + 1);
> line += len;
> diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c
> index b916de3c2..02d625c64 100644
> --- a/tests/shader_runner_d3d12.c
> +++ b/tests/shader_runner_d3d12.c
> @@ -381,16 +381,20 @@ static struct resource_readback *d3d12_runner_get_resource_readback(struct shade
> struct test_context *test_context = &runner->test_context;
> struct d3d12_resource_readback *rb = malloc(sizeof(*rb));
> struct d3d12_resource *resource = d3d12_resource(res);
> + D3D12_RESOURCE_STATES state;
>
> - assert(resource->r.type == RESOURCE_TYPE_RENDER_TARGET);
> + if (resource->r.type == RESOURCE_TYPE_RENDER_TARGET)
> + state = D3D12_RESOURCE_STATE_RENDER_TARGET;
> + else
> + state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
>
> transition_resource_state(test_context->list, resource->resource,
> - D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
> + state, D3D12_RESOURCE_STATE_COPY_SOURCE);
> get_texture_readback_with_command_list(resource->resource, 0, rb,
> test_context->queue, test_context->list);
> reset_command_list(test_context->list, test_context->allocator);
> transition_resource_state(test_context->list, resource->resource,
> - D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
> + D3D12_RESOURCE_STATE_COPY_SOURCE, state);
>
> return &rb->rb;
> }
> diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c
> index adb69a7ce..190441263 100644
> --- a/tests/shader_runner_vulkan.c
> +++ b/tests/shader_runner_vulkan.c
> @@ -943,8 +943,12 @@ static struct resource_readback *vulkan_runner_get_resource_readback(struct shad
> struct vulkan_resource *resource = vulkan_resource(res);
> VkDevice device = runner->device;
> VkBufferImageCopy region = {0};
> + VkImageLayout layout;
>
> - assert(resource->r.type == RESOURCE_TYPE_RENDER_TARGET);
> + if (resource->r.type == RESOURCE_TYPE_RENDER_TARGET)
> + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> + else
> + layout = VK_IMAGE_LAYOUT_GENERAL;
>
> rb->rb.width = resource->r.width;
> rb->rb.height = resource->r.height;
> @@ -957,8 +961,7 @@ static struct resource_readback *vulkan_runner_get_resource_readback(struct shad
>
> begin_command_buffer(runner);
>
> - transition_image_layout(runner, resource->image,
> - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
> + transition_image_layout(runner, resource->image, layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
>
> region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
> region.imageSubresource.layerCount = 1;
> @@ -969,8 +972,7 @@ static struct resource_readback *vulkan_runner_get_resource_readback(struct shad
> VK_CALL(vkCmdCopyImageToBuffer(runner->cmd_buffer, resource->image,
> VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, rb->buffer, 1, ®ion));
>
> - transition_image_layout(runner, resource->image,
> - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
> + transition_image_layout(runner, resource->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layout);
>
> end_command_buffer(runner);
>
> diff --git a/tests/uav.shader_test b/tests/uav.shader_test
> new file mode 100644
> index 000000000..09ca05ece
> --- /dev/null
> +++ b/tests/uav.shader_test
> @@ -0,0 +1,56 @@
> +[require]
> +shader model >= 5.0
> +
> +[pixel shader fail]
> +RWTexture2D<float4> u;
> +
> +float4 main() : sv_target
> +{
> + /* All four components must be written in a single statement. */
> + u[uint2(0, 0)].xy = float4(1, 2);
> + u[uint2(0, 0)].zw = float4(3, 4);
> + return 0;
> +}
> +
> +[pixel shader fail]
> +Texture2D<float4> u;
> +
> +float4 main() : sv_target
> +{
> + /* SRVs are not writable. */
> + u[uint2(0, 0)].xyzw = float4(1, 2, 3, 4);
> + return 0;
> +}
> +
> +[uav 1]
> +format r32 float
> +size (2, 2)
> +
> +0.1 0.2
> +0.3 0.4
> +
> +[uav 2]
> +size (1, 1)
> +
> +0.5 0.6 0.7 0.8
> +
> +[pixel shader]
> +RWTexture2D<float> u;
> +RWTexture2D<float4> v;
> +
> +float4 main() : sv_target
> +{
> + u[uint2(0, 0)] = 0.5;
> + u[uint2(0, 1)].x = 0.6;
> + u[uint2(1, 1)] = 0.7;
> + v[uint2(0, 0)].yxwz = float4(1, 2, 3, 4);
> + return 0;
> +}
> +
> +[test]
> +todo draw quad
> +probe uav 1 (0, 0) r (0.5)
> +probe uav 1 (0, 1) r (0.6)
> +probe uav 1 (1, 0) r (0.2)
> +probe uav 1 (1, 1) r (0.7)
> +probe uav 2 (0, 0) rgba (2.0, 1.0, 4.0, 3.0)
June 8, 2022
Re: [PATCH vkd3d v5 05/14] tests/shader_runner: Make the render target into a resource.
by Giovanni Mascellani
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Il 07/06/22 23:29, Zebediah Figura ha scritto:
> Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
> ---
> v5: New patch.
>
> tests/shader_runner.c | 57 ++++++++++++++-
> tests/shader_runner.h | 6 +-
> tests/shader_runner_d3d11.c | 70 +++++++++---------
> tests/shader_runner_d3d12.c | 86 ++++++++++++++++------
> tests/shader_runner_d3d9.c | 69 +++++++++---------
> tests/shader_runner_vulkan.c | 133 ++++++++++++++++++++---------------
> 6 files changed, 270 insertions(+), 151 deletions(-)
>
> diff --git a/tests/shader_runner.c b/tests/shader_runner.c
> index 83f804ad3..f367027f7 100644
> --- a/tests/shader_runner.c
> +++ b/tests/shader_runner.c
> @@ -317,7 +317,27 @@ void init_resource(struct resource *resource, const struct resource_params *para
> {
> resource->type = params->type;
> resource->slot = params->slot;
> + resource->format = params->format;
> resource->size = params->data_size;
> + resource->texel_size = params->texel_size;
> + resource->width = params->width;
> + resource->height = params->height;
> +}
> +
> +static struct resource *get_resource(struct shader_runner *runner, enum resource_type type, unsigned int slot)
> +{
> + struct resource *resource;
> + size_t i;
> +
> + for (i = 0; i < runner->resource_count; ++i)
> + {
> + resource = runner->resources[i];
> +
> + if (resource->type == type && resource->slot == slot)
> + return resource;
> + }
> +
> + return NULL;
> }
>
> static void set_resource(struct shader_runner *runner, struct resource *resource)
> @@ -373,6 +393,20 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> "{\n"
> "}";
>
> + if (!get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0))
> + {
> + memset(¶ms, 0, sizeof(params));
> + params.slot = 0;
> + params.type = RESOURCE_TYPE_RENDER_TARGET;
> + params.format = DXGI_FORMAT_R32G32B32A32_FLOAT;
> + params.data_type = TEXTURE_DATA_FLOAT;
> + params.texel_size = 16;
> + params.width = RENDER_TARGET_WIDTH;
> + params.height = RENDER_TARGET_HEIGHT;
> +
> + set_resource(runner, runner->ops->create_resource(runner, ¶ms));
> + }
> +
> vkd3d_array_reserve((void **)&runner->input_elements, &runner->input_element_capacity,
> 1, sizeof(*runner->input_elements));
> element = &runner->input_elements[0];
> @@ -399,9 +433,24 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> else if (match_string(line, "draw", &line))
> {
> D3D_PRIMITIVE_TOPOLOGY topology;
> + struct resource_params params;
> unsigned int vertex_count;
> char *rest;
>
> + if (!get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0))
> + {
> + memset(¶ms, 0, sizeof(params));
> + params.slot = 0;
> + params.type = RESOURCE_TYPE_RENDER_TARGET;
> + params.format = DXGI_FORMAT_R32G32B32A32_FLOAT;
> + params.data_type = TEXTURE_DATA_FLOAT;
> + params.texel_size = 16;
> + params.width = RENDER_TARGET_WIDTH;
> + params.height = RENDER_TARGET_HEIGHT;
> +
> + set_resource(runner, runner->ops->create_resource(runner, ¶ms));
> + }
> +
> if (match_string(line, "triangle list", &line))
> topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
> else if (match_string(line, "triangle strip", &line))
> @@ -419,15 +468,19 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> {
> unsigned int left, top, right, bottom, ulps;
> struct resource_readback *rb;
> + struct resource *resource;
> int ret, len;
> RECT rect;
>
> if (runner->last_render_failed)
> return;
>
> + resource = get_resource(runner, RESOURCE_TYPE_RENDER_TARGET, 0);
> + rb = runner->ops->get_resource_readback(runner, resource);
> +
> if (match_string(line, "all", &line))
> {
> - set_rect(&rect, 0, 0, RENDER_TARGET_WIDTH, RENDER_TARGET_HEIGHT);
> + set_rect(&rect, 0, 0, resource->width, resource->height);
> }
> else if (sscanf(line, "( %d , %d , %d , %d )%n", &left, &top, &right, &bottom, &len) == 4)
> {
> @@ -444,8 +497,6 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
> fatal_error("Malformed probe arguments '%s'.\n", line);
> }
>
> - rb = runner->ops->get_rt_readback(runner);
> -
> if (match_string(line, "rgba", &line))
> {
> struct vec4 v;
> diff --git a/tests/shader_runner.h b/tests/shader_runner.h
> index 60f894583..19a48ee85 100644
> --- a/tests/shader_runner.h
> +++ b/tests/shader_runner.h
> @@ -53,6 +53,7 @@ struct sampler
>
> enum resource_type
> {
> + RESOURCE_TYPE_RENDER_TARGET,
> RESOURCE_TYPE_TEXTURE,
> RESOURCE_TYPE_UAV,
> RESOURCE_TYPE_VERTEX_BUFFER,
> @@ -76,7 +77,10 @@ struct resource
> unsigned int slot;
> enum resource_type type;
>
> + DXGI_FORMAT format;
> unsigned int size;
> + unsigned int texel_size;
> + unsigned int width, height;
> };
>
> struct input_element
> @@ -124,7 +128,7 @@ struct shader_runner_ops
> struct resource *(*create_resource)(struct shader_runner *runner, const struct resource_params *params);
> void (*destroy_resource)(struct shader_runner *runner, struct resource *resource);
> bool (*draw)(struct shader_runner *runner, D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count);
> - struct resource_readback *(*get_rt_readback)(struct shader_runner *runner);
> + struct resource_readback *(*get_resource_readback)(struct shader_runner *runner, struct resource *resource);
> void (*release_readback)(struct shader_runner *runner, struct resource_readback *rb);
> };
>
> diff --git a/tests/shader_runner_d3d11.c b/tests/shader_runner_d3d11.c
> index b80a8b65f..8999622d3 100644
> --- a/tests/shader_runner_d3d11.c
> +++ b/tests/shader_runner_d3d11.c
> @@ -43,6 +43,8 @@ struct d3d11_resource
> struct resource r;
>
> ID3D11Resource *resource;
> + ID3D11Texture2D *texture;
> + ID3D11RenderTargetView *rtv;
> ID3D11ShaderResourceView *srv;
> ID3D11UnorderedAccessView *uav;
> };
> @@ -59,8 +61,6 @@ struct d3d11_shader_runner
> ID3D11Device *device;
> HWND window;
> IDXGISwapChain *swapchain;
> - ID3D11Texture2D *rt;
> - ID3D11RenderTargetView *rtv;
> ID3D11DeviceContext *immediate_context;
> };
>
> @@ -276,20 +276,8 @@ static IDXGISwapChain *create_swapchain(ID3D11Device *device, HWND window)
>
> static BOOL init_test_context(struct d3d11_shader_runner *runner)
> {
> - const D3D11_TEXTURE2D_DESC texture_desc =
> - {
> - .Width = RENDER_TARGET_WIDTH,
> - .Height = RENDER_TARGET_HEIGHT,
> - .MipLevels = 1,
> - .ArraySize = 1,
> - .Format = DXGI_FORMAT_R32G32B32A32_FLOAT,
> - .SampleDesc.Count = 1,
> - .Usage = D3D11_USAGE_DEFAULT,
> - .BindFlags = D3D11_BIND_RENDER_TARGET,
> - };
> unsigned int rt_width, rt_height;
> D3D11_VIEWPORT vp;
> - HRESULT hr;
> RECT rect;
>
> memset(runner, 0, sizeof(*runner));
> @@ -308,16 +296,8 @@ static BOOL init_test_context(struct d3d11_shader_runner *runner)
> 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL);
> runner->swapchain = create_swapchain(runner->device, runner->window);
>
> - hr = ID3D11Device_CreateTexture2D(runner->device, &texture_desc, NULL, &runner->rt);
> - ok(hr == S_OK, "Failed to create texture, hr %#lx.\n", hr);
> -
> - hr = ID3D11Device_CreateRenderTargetView(runner->device, (ID3D11Resource *)runner->rt, NULL, &runner->rtv);
> - ok(hr == S_OK, "Failed to create rendertarget view, hr %#lx.\n", hr);
> -
> ID3D11Device_GetImmediateContext(runner->device, &runner->immediate_context);
>
> - ID3D11DeviceContext_OMSetRenderTargets(runner->immediate_context, 1, &runner->rtv, NULL);
> -
> vp.TopLeftX = 0.0f;
> vp.TopLeftY = 0.0f;
> vp.Width = rt_width;
> @@ -334,8 +314,6 @@ static void destroy_test_context(struct d3d11_shader_runner *runner)
> ULONG ref;
>
> ID3D11DeviceContext_Release(runner->immediate_context);
> - ID3D11RenderTargetView_Release(runner->rtv);
> - ID3D11Texture2D_Release(runner->rt);
> IDXGISwapChain_Release(runner->swapchain);
> DestroyWindow(runner->window);
>
> @@ -379,6 +357,7 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co
>
> switch (params->type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> case RESOURCE_TYPE_TEXTURE:
> case RESOURCE_TYPE_UAV:
> {
> @@ -393,17 +372,29 @@ static struct resource *d3d11_runner_create_resource(struct shader_runner *r, co
> desc.Usage = D3D11_USAGE_DEFAULT;
> if (params->type == RESOURCE_TYPE_UAV)
> desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
> + else if (params->type == RESOURCE_TYPE_RENDER_TARGET)
> + desc.BindFlags = D3D11_BIND_RENDER_TARGET;
> else
> desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
>
> - resource_data.pSysMem = params->data;
> - resource_data.SysMemPitch = params->width * params->texel_size;
> - resource_data.SysMemSlicePitch = params->height * resource_data.SysMemPitch;
> -
> - hr = ID3D11Device_CreateTexture2D(device, &desc, &resource_data, (ID3D11Texture2D **)&resource->resource);
> + if (params->data)
> + {
> + resource_data.pSysMem = params->data;
> + resource_data.SysMemPitch = params->width * params->texel_size;
> + resource_data.SysMemSlicePitch = params->height * resource_data.SysMemPitch;
> + hr = ID3D11Device_CreateTexture2D(device, &desc, &resource_data, &resource->texture);
> + }
> + else
> + {
> + hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &resource->texture);
> + }
> ok(hr == S_OK, "Failed to create texture, hr %#lx.\n", hr);
> +
> + resource->resource = (ID3D11Resource *)resource->texture;
> if (params->type == RESOURCE_TYPE_UAV)
> hr = ID3D11Device_CreateUnorderedAccessView(device, resource->resource, NULL, &resource->uav);
> + else if (params->type == RESOURCE_TYPE_RENDER_TARGET)
> + hr = ID3D11Device_CreateRenderTargetView(device, resource->resource, NULL, &resource->rtv);
> else
> hr = ID3D11Device_CreateShaderResourceView(device, resource->resource, NULL, &resource->srv);
> ok(hr == S_OK, "Failed to create view, hr %#lx.\n", hr);
> @@ -424,6 +415,8 @@ static void d3d11_runner_destroy_resource(struct shader_runner *r, struct resour
> struct d3d11_resource *resource = d3d11_resource(res);
>
> ID3D11Resource_Release(resource->resource);
> + if (resource->rtv)
> + ID3D11RenderTargetView_Release(resource->rtv);
> if (resource->srv)
> ID3D11ShaderResourceView_Release(resource->srv);
> if (resource->uav)
> @@ -435,11 +428,13 @@ static bool d3d11_runner_draw(struct shader_runner *r,
> D3D_PRIMITIVE_TOPOLOGY primitive_topology, unsigned int vertex_count)
> {
> ID3D11UnorderedAccessView *uavs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0};
> + ID3D11RenderTargetView *rtvs[D3D11_PS_CS_UAV_REGISTER_COUNT] = {0};
> struct d3d11_shader_runner *runner = d3d11_shader_runner(r);
> ID3D11DeviceContext *context = runner->immediate_context;
> unsigned int min_uav_slot = ARRAY_SIZE(uavs);
> ID3D11Device *device = runner->device;
> ID3D10Blob *vs_code, *ps_code;
> + unsigned int rtv_count = 0;
> ID3D11Buffer *cb = NULL;
> ID3D11VertexShader *vs;
> ID3D11PixelShader *ps;
> @@ -478,6 +473,11 @@ static bool d3d11_runner_draw(struct shader_runner *r,
>
> switch (resource->r.type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + rtvs[resource->r.slot] = resource->rtv;
> + rtv_count = max(rtv_count, resource->r.slot + 1);
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> ID3D11DeviceContext_PSSetShaderResources(context, resource->r.slot, 1, &resource->srv);
> break;
> @@ -494,8 +494,7 @@ static bool d3d11_runner_draw(struct shader_runner *r,
> }
> }
>
> - ID3D11DeviceContext_OMSetRenderTargetsAndUnorderedAccessViews(context,
> - D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, NULL, NULL,
> + ID3D11DeviceContext_OMSetRenderTargetsAndUnorderedAccessViews(context, rtv_count, rtvs, NULL,
> min_uav_slot, ARRAY_SIZE(uavs) - min_uav_slot, &uavs[min_uav_slot], NULL);
>
> for (i = 0; i < runner->r.sampler_count; ++i)
> @@ -565,15 +564,16 @@ struct d3d11_resource_readback
> ID3D11Resource *resource;
> };
>
> -static struct resource_readback *d3d11_runner_get_rt_readback(struct shader_runner *r)
> +static struct resource_readback *d3d11_runner_get_resource_readback(struct shader_runner *r, struct resource *res)
> {
> struct d3d11_shader_runner *runner = d3d11_shader_runner(r);
> struct d3d11_resource_readback *rb = malloc(sizeof(*rb));
> + struct d3d11_resource *resource = d3d11_resource(res);
> D3D11_TEXTURE2D_DESC texture_desc;
> D3D11_MAPPED_SUBRESOURCE map_desc;
> HRESULT hr;
>
> - ID3D11Texture2D_GetDesc(runner->rt, &texture_desc);
> + ID3D11Texture2D_GetDesc(resource->texture, &texture_desc);
> texture_desc.Usage = D3D11_USAGE_STAGING;
> texture_desc.BindFlags = 0;
> texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
> @@ -581,7 +581,7 @@ static struct resource_readback *d3d11_runner_get_rt_readback(struct shader_runn
> hr = ID3D11Device_CreateTexture2D(runner->device, &texture_desc, NULL, (ID3D11Texture2D **)&rb->resource);
> ok(hr == S_OK, "Failed to create texture, hr %#lx.\n", hr);
>
> - ID3D11DeviceContext_CopyResource(runner->immediate_context, rb->resource, (ID3D11Resource *)runner->rt);
> + ID3D11DeviceContext_CopyResource(runner->immediate_context, rb->resource, resource->resource);
> hr = ID3D11DeviceContext_Map(runner->immediate_context, rb->resource, 0, D3D11_MAP_READ, 0, &map_desc);
> ok(hr == S_OK, "Failed to map texture, hr %#lx.\n", hr);
>
> @@ -608,7 +608,7 @@ static const struct shader_runner_ops d3d11_runner_ops =
> .create_resource = d3d11_runner_create_resource,
> .destroy_resource = d3d11_runner_destroy_resource,
> .draw = d3d11_runner_draw,
> - .get_rt_readback = d3d11_runner_get_rt_readback,
> + .get_resource_readback = d3d11_runner_get_resource_readback,
> .release_readback = d3d11_runner_release_readback,
> };
>
> diff --git a/tests/shader_runner_d3d12.c b/tests/shader_runner_d3d12.c
> index f97e7bde9..b916de3c2 100644
> --- a/tests/shader_runner_d3d12.c
> +++ b/tests/shader_runner_d3d12.c
> @@ -44,7 +44,7 @@ struct d3d12_shader_runner
>
> struct test_context test_context;
>
> - ID3D12DescriptorHeap *heap;
> + ID3D12DescriptorHeap *heap, *rtv_heap;
> };
>
> static struct d3d12_shader_runner *d3d12_shader_runner(struct shader_runner *r)
> @@ -94,6 +94,20 @@ static struct resource *d3d12_runner_create_resource(struct shader_runner *r, co
>
> switch (params->type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + if (!runner->rtv_heap)
> + runner->rtv_heap = create_cpu_descriptor_heap(device,
> + D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_RESOURCE_DESCRIPTORS);
> +
> + if (params->slot >= D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT)
> + fatal_error("RTV slot %u is too high.\n", params->slot);
> +
> + resource->resource = create_default_texture(device, params->width, params->height,
> + params->format, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET);
> + ID3D12Device_CreateRenderTargetView(device, resource->resource,
> + NULL, get_cpu_rtv_handle(test_context, runner->rtv_heap, resource->r.slot));
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> if (!runner->heap)
> runner->heap = create_gpu_descriptor_heap(device,
> @@ -157,18 +171,19 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> struct d3d12_shader_runner *runner = d3d12_shader_runner(r);
> struct test_context *test_context = &runner->test_context;
>
> + D3D12_CPU_DESCRIPTOR_HANDLE rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0};
> ID3D12GraphicsCommandList *command_list = test_context->list;
> D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {0};
> + D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {0};
> D3D12_ROOT_PARAMETER root_params[3], *root_param;
> ID3D12CommandQueue *queue = test_context->queue;
> D3D12_INPUT_ELEMENT_DESC *input_element_descs;
> D3D12_STATIC_SAMPLER_DESC static_samplers[1];
> ID3D12Device *device = test_context->device;
> - D3D12_INPUT_LAYOUT_DESC input_layout;
> static const float clear_color[4];
> + unsigned int uniform_index = 0;
> ID3D10Blob *vs_code, *ps_code;
> - D3D12_SHADER_BYTECODE vs, ps;
> - unsigned int uniform_index;
> + unsigned int rtv_count = 0;
> ID3D12PipelineState *pso;
> HRESULT hr;
> size_t i;
> @@ -192,6 +207,16 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> root_signature_desc.pStaticSamplers = static_samplers;
> root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
>
> + pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs_code);
> + pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs_code);
> + pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_code);
> + pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_code);
> + pso_desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
> + pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
> + pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
> + pso_desc.SampleDesc.Count = 1;
> + pso_desc.SampleMask = ~(UINT)0;
> +
> if (runner->r.uniform_count)
> {
> uniform_index = root_signature_desc.NumParameters++;
> @@ -231,6 +256,12 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> range->OffsetInDescriptorsFromTableStart = 0;
> break;
>
> + case RESOURCE_TYPE_RENDER_TARGET:
> + pso_desc.RTVFormats[resource->r.slot] = resource->r.format;
> + pso_desc.NumRenderTargets = max(pso_desc.NumRenderTargets, resource->r.slot + 1);
> + pso_desc.BlendState.RenderTarget[resource->r.slot].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
> + break;
> +
> case RESOURCE_TYPE_VERTEX_BUFFER:
> break;
> }
> @@ -258,6 +289,8 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> hr = create_root_signature(device, &root_signature_desc, &test_context->root_signature);
> ok(hr == S_OK, "Failed to create root signature, hr %#x.\n", hr);
>
> + pso_desc.pRootSignature = test_context->root_signature;
> +
> input_element_descs = calloc(runner->r.input_element_count, sizeof(*input_element_descs));
> for (i = 0; i < runner->r.input_element_count; ++i)
> {
> @@ -272,15 +305,12 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> desc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
> }
>
> - input_layout.pInputElementDescs = input_element_descs;
> - input_layout.NumElements = runner->r.input_element_count;
> + pso_desc.InputLayout.pInputElementDescs = input_element_descs;
> + pso_desc.InputLayout.NumElements = runner->r.input_element_count;
>
> - vs.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs_code);
> - vs.BytecodeLength = ID3D10Blob_GetBufferSize(vs_code);
> - ps.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_code);
> - ps.BytecodeLength = ID3D10Blob_GetBufferSize(ps_code);
> - pso = create_pipeline_state(device, test_context->root_signature,
> - test_context->render_target_desc.Format, &vs, &ps, &input_layout);
> + hr = ID3D12Device_CreateGraphicsPipelineState(device, &pso_desc,
> + &IID_ID3D12PipelineState, (void **)&pso);
> + ok(hr == S_OK, "Failed to create state, hr %#x.\n", hr);
> ID3D10Blob_Release(vs_code);
> ID3D10Blob_Release(ps_code);
> free(input_element_descs);
> @@ -299,6 +329,13 @@ static bool d3d12_runner_draw(struct shader_runner *r,
>
> switch (resource->r.type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + rtvs[resource->r.slot] = get_cpu_rtv_handle(test_context, runner->rtv_heap, resource->r.slot);
> + ID3D12GraphicsCommandList_ClearRenderTargetView(command_list,
> + rtvs[resource->r.slot], clear_color, 0, NULL);
> + rtv_count = max(rtv_count, resource->r.slot + 1);
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, resource->root_index,
> get_gpu_descriptor_handle(test_context, runner->heap, resource->r.slot));
> @@ -320,11 +357,11 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> }
> }
>
> - ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &test_context->rtv, false, NULL);
> + ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, rtv_count, rtvs, false, NULL);
> +
> ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &test_context->scissor_rect);
> ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &test_context->viewport);
> ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, primitive_topology);
> - ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, test_context->rtv, clear_color, 0, NULL);
> ID3D12GraphicsCommandList_SetPipelineState(command_list, pso);
> ID3D12GraphicsCommandList_DrawInstanced(command_list, vertex_count, 1, 0, 0);
>
> @@ -338,16 +375,22 @@ static bool d3d12_runner_draw(struct shader_runner *r,
> return true;
> }
>
> -static struct resource_readback *d3d12_runner_get_rt_readback(struct shader_runner *r)
> +static struct resource_readback *d3d12_runner_get_resource_readback(struct shader_runner *r, struct resource *res)
> {
> struct d3d12_shader_runner *runner = d3d12_shader_runner(r);
> struct test_context *test_context = &runner->test_context;
> struct d3d12_resource_readback *rb = malloc(sizeof(*rb));
> + struct d3d12_resource *resource = d3d12_resource(res);
>
> - transition_resource_state(test_context->list, test_context->render_target,
> + assert(resource->r.type == RESOURCE_TYPE_RENDER_TARGET);
> +
> + transition_resource_state(test_context->list, resource->resource,
> D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE);
> - get_texture_readback_with_command_list(test_context->render_target, 0, rb,
> + get_texture_readback_with_command_list(resource->resource, 0, rb,
> test_context->queue, test_context->list);
> + reset_command_list(test_context->list, test_context->allocator);
> + transition_resource_state(test_context->list, resource->resource,
> + D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
>
> return &rb->rb;
> }
> @@ -355,13 +398,8 @@ static struct resource_readback *d3d12_runner_get_rt_readback(struct shader_runn
> static void d3d12_runner_release_readback(struct shader_runner *r, struct resource_readback *rb)
> {
> struct d3d12_resource_readback *d3d12_rb = CONTAINING_RECORD(rb, struct d3d12_resource_readback, rb);
> - struct d3d12_shader_runner *runner = d3d12_shader_runner(r);
> - struct test_context *test_context = &runner->test_context;
>
> release_resource_readback(d3d12_rb);
> - reset_command_list(test_context->list, test_context->allocator);
> - transition_resource_state(test_context->list, test_context->render_target,
> - D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
> free(d3d12_rb);
> }
>
> @@ -370,7 +408,7 @@ static const struct shader_runner_ops d3d12_runner_ops =
> .create_resource = d3d12_runner_create_resource,
> .destroy_resource = d3d12_runner_destroy_resource,
> .draw = d3d12_runner_draw,
> - .get_rt_readback = d3d12_runner_get_rt_readback,
> + .get_resource_readback = d3d12_runner_get_resource_readback,
> .release_readback = d3d12_runner_release_readback,
> };
>
> @@ -394,5 +432,7 @@ void run_shader_tests_d3d12(int argc, char **argv)
>
> if (runner.heap)
> ID3D12DescriptorHeap_Release(runner.heap);
> + if (runner.rtv_heap)
> + ID3D12DescriptorHeap_Release(runner.rtv_heap);
> destroy_test_context(&runner.test_context);
> }
> diff --git a/tests/shader_runner_d3d9.c b/tests/shader_runner_d3d9.c
> index 417d68750..583b7ca73 100644
> --- a/tests/shader_runner_d3d9.c
> +++ b/tests/shader_runner_d3d9.c
> @@ -29,6 +29,7 @@ struct d3d9_resource
> {
> struct resource r;
>
> + IDirect3DSurface9 *surface;
> IDirect3DTexture9 *texture;
> IDirect3DVertexBuffer9 *vb;
> };
> @@ -43,7 +44,6 @@ struct d3d9_shader_runner
> struct shader_runner r;
>
> IDirect3DDevice9 *device;
> - IDirect3DSurface9 *rt;
> HWND window;
> };
>
> @@ -151,18 +151,6 @@ static bool init_test_context(struct d3d9_shader_runner *runner)
> return false;
> }
>
> - if (FAILED(hr = IDirect3DDevice9_CreateRenderTarget(runner->device, RENDER_TARGET_WIDTH, RENDER_TARGET_HEIGHT,
> - D3DFMT_A32B32G32R32F, D3DMULTISAMPLE_NONE, 0, FALSE, &runner->rt, NULL)))
> - {
> - skip("Failed to create an A32B32G32R32F surface, hr %#lx.\n", hr);
> - IDirect3DDevice9_Release(runner->device);
> - DestroyWindow(runner->window);
> - return false;
> - }
> - ok(hr == D3D_OK, "Got unexpected hr %#lx.\n", hr);
> - hr = IDirect3DDevice9_SetRenderTarget(runner->device, 0, runner->rt);
> - ok(hr == D3D_OK, "Failed to set render target, hr %#lx.\n", hr);
> -
> return true;
> }
>
> @@ -170,7 +158,6 @@ static void destroy_test_context(struct d3d9_shader_runner *runner)
> {
> ULONG ref;
>
> - IDirect3DSurface9_Release(runner->rt);
> ref = IDirect3DDevice9_Release(runner->device);
> ok(!ref, "Device has %lu references left.\n", ref);
> DestroyWindow(runner->window);
> @@ -224,24 +211,30 @@ static struct resource *d3d9_runner_create_resource(struct shader_runner *r, con
> resource = calloc(1, sizeof(*resource));
> init_resource(&resource->r, params);
>
> + switch (params->format)
> + {
> + case DXGI_FORMAT_R32G32B32A32_FLOAT:
> + format = D3DFMT_A32B32G32R32F;
> + break;
> +
> + case DXGI_FORMAT_R32_FLOAT:
> + format = D3DFMT_R32F;
> + break;
> +
> + default:
> + format = D3DFMT_UNKNOWN;
> + break;
> + }
> +
> switch (params->type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + hr = IDirect3DDevice9_CreateRenderTarget(device, params->width, params->height,
> + format, D3DMULTISAMPLE_NONE, 0, FALSE, &resource->surface, NULL);
> + ok(hr == D3D_OK, "Failed to create render target, hr %#lx.\n", hr);
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> - switch (params->format)
> - {
> - case DXGI_FORMAT_R32G32B32A32_FLOAT:
> - format = D3DFMT_A32B32G32R32F;
> - break;
> -
> - case DXGI_FORMAT_R32_FLOAT:
> - format = D3DFMT_R32F;
> - break;
> -
> - default:
> - format = D3DFMT_UNKNOWN;
> - break;
> - }
> -
> hr = IDirect3DDevice9_CreateTexture(device, params->width, params->height,
> 1, D3DUSAGE_DYNAMIC, format, D3DPOOL_DEFAULT, &resource->texture, NULL);
> ok(hr == D3D_OK, "Failed to create texture, hr %#lx.\n", hr);
> @@ -279,6 +272,8 @@ static void d3d9_runner_destroy_resource(struct shader_runner *r, struct resourc
> {
> struct d3d9_resource *resource = d3d9_resource(res);
>
> + if (resource->surface)
> + IDirect3DSurface9_Release(resource->surface);
> if (resource->texture)
> IDirect3DTexture9_Release(resource->texture);
> if (resource->vb)
> @@ -363,6 +358,11 @@ static bool d3d9_runner_draw(struct shader_runner *r,
>
> switch (resource->r.type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + hr = IDirect3DDevice9_SetRenderTarget(device, resource->r.slot, resource->surface);
> + ok(hr == D3D_OK, "Failed to set render target, hr %#lx.\n", hr);
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> hr = IDirect3DDevice9_SetTexture(device, resource->r.slot, (IDirect3DBaseTexture9 *)resource->texture);
> ok(hr == D3D_OK, "Failed to set texture, hr %#lx.\n", hr);
> @@ -461,21 +461,24 @@ struct d3d9_resource_readback
> IDirect3DSurface9 *surface;
> };
>
> -static struct resource_readback *d3d9_runner_get_rt_readback(struct shader_runner *r)
> +static struct resource_readback *d3d9_runner_get_resource_readback(struct shader_runner *r, struct resource *res)
> {
> struct d3d9_shader_runner *runner = d3d9_shader_runner(r);
> struct d3d9_resource_readback *rb = malloc(sizeof(*rb));
> + struct d3d9_resource *resource = d3d9_resource(res);
> D3DLOCKED_RECT map_desc;
> D3DSURFACE_DESC desc;
> HRESULT hr;
>
> - hr = IDirect3DSurface9_GetDesc(runner->rt, &desc);
> + assert(resource->r.type == RESOURCE_TYPE_RENDER_TARGET);
> +
> + hr = IDirect3DSurface9_GetDesc(resource->surface, &desc);
> ok(hr == D3D_OK, "Failed to get surface desc, hr %#lx.\n", hr);
> hr = IDirect3DDevice9Ex_CreateOffscreenPlainSurface(runner->device, desc.Width,
> desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &rb->surface, NULL);
> ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr);
>
> - hr = IDirect3DDevice9Ex_GetRenderTargetData(runner->device, runner->rt, rb->surface);
> + hr = IDirect3DDevice9Ex_GetRenderTargetData(runner->device, resource->surface, rb->surface);
> ok(hr == D3D_OK, "Failed to get render target data, hr %#lx.\n", hr);
>
> hr = IDirect3DSurface9_LockRect(rb->surface, &map_desc, NULL, D3DLOCK_READONLY);
> @@ -504,7 +507,7 @@ static const struct shader_runner_ops d3d9_runner_ops =
> .create_resource = d3d9_runner_create_resource,
> .destroy_resource = d3d9_runner_destroy_resource,
> .draw = d3d9_runner_draw,
> - .get_rt_readback = d3d9_runner_get_rt_readback,
> + .get_resource_readback = d3d9_runner_get_resource_readback,
> .release_readback = d3d9_runner_release_readback,
> };
>
> diff --git a/tests/shader_runner_vulkan.c b/tests/shader_runner_vulkan.c
> index d62792d65..adb69a7ce 100644
> --- a/tests/shader_runner_vulkan.c
> +++ b/tests/shader_runner_vulkan.c
> @@ -60,10 +60,6 @@ struct vulkan_shader_runner
> VkCommandBuffer cmd_buffer;
> VkDescriptorPool descriptor_pool;
>
> - VkImage render_target;
> - VkDeviceMemory rt_memory;
> - VkImageView rtv;
> -
> struct vulkan_sampler
> {
> VkSampler vk_sampler;
> @@ -247,6 +243,19 @@ static struct resource *vulkan_runner_create_resource(struct shader_runner *r, c
>
> switch (params->type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> + format = vkd3d_get_vk_format(params->format);
> +
> + resource->image = create_2d_image(runner, params->width, params->height,
> + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, format, &resource->memory);
> + resource->view = create_2d_image_view(runner, resource->image, format);
> +
> + begin_command_buffer(runner);
> + transition_image_layout(runner, resource->image,
> + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
> + end_command_buffer(runner);
> + break;
> +
> case RESOURCE_TYPE_TEXTURE:
> case RESOURCE_TYPE_UAV:
> {
> @@ -385,6 +394,7 @@ static bool compile_shader(const struct vulkan_shader_runner *runner, const char
>
> switch (resource->r.type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> case RESOURCE_TYPE_VERTEX_BUFFER:
> break;
>
> @@ -514,7 +524,7 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkR
> VkPipelineViewportStateCreateInfo vp_desc = {.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
> static const VkRect2D rt_rect = {.extent.width = RENDER_TARGET_WIDTH, .extent.height = RENDER_TARGET_HEIGHT};
> VkGraphicsPipelineCreateInfo pipeline_desc = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
> - VkPipelineColorBlendAttachmentState attachment_desc = {0};
> + VkPipelineColorBlendAttachmentState attachment_desc[MAX_RESOURCES] = {0};
> VkVertexInputAttributeDescription input_attributes[32];
> VkVertexInputBindingDescription input_bindings[32];
> struct vkd3d_shader_signature vs_input_signature;
> @@ -560,6 +570,9 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkR
> input_desc.pVertexAttributeDescriptions = input_attributes;
> input_desc.pVertexBindingDescriptions = input_bindings;
>
> + blend_desc.attachmentCount = 0;
> + blend_desc.pAttachments = attachment_desc;
> +
> for (i = 0; i < runner->r.resource_count; ++i)
> {
> const struct vulkan_resource *resource = vulkan_resource(runner->r.resources[i]);
> @@ -570,6 +583,12 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkR
> case RESOURCE_TYPE_UAV:
> break;
>
> + case RESOURCE_TYPE_RENDER_TARGET:
> + attachment_desc[blend_desc.attachmentCount++].colorWriteMask =
> + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
> + | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
> + break;
> +
> case RESOURCE_TYPE_VERTEX_BUFFER:
> {
> VkVertexInputBindingDescription *binding = &input_bindings[input_desc.vertexBindingDescriptionCount++];
> @@ -603,12 +622,6 @@ static VkPipeline create_pipeline(const struct vulkan_shader_runner *runner, VkR
>
> ms_desc.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
>
> - blend_desc.attachmentCount = 1;
> - blend_desc.pAttachments = &attachment_desc;
> -
> - attachment_desc.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
> - | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
> -
> pipeline_desc.stageCount = ARRAY_SIZE(stage_desc);
> pipeline_desc.pStages = stage_desc;
> pipeline_desc.pVertexInputState = &input_desc;
> @@ -669,6 +682,7 @@ static VkDescriptorSetLayout create_descriptor_set_layout(struct vulkan_shader_r
>
> switch (resource->r.type)
> {
> + case RESOURCE_TYPE_RENDER_TARGET:
> case RESOURCE_TYPE_VERTEX_BUFFER:
> break;
>
> @@ -768,6 +782,9 @@ static void bind_resources(struct vulkan_shader_runner *runner, VkPipelineBindPo
> if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS)
> VK_CALL(vkCmdBindVertexBuffers(cmd_buffer, resource->r.slot, 1, &resource->buffer, &zero_offset));
> break;
> +
> + case RESOURCE_TYPE_RENDER_TARGET:
> + break;
> }
> }
>
> @@ -785,36 +802,53 @@ static void create_render_pass_and_framebuffer(struct vulkan_shader_runner *runn
> {
> VkRenderPassCreateInfo render_pass_desc = {.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
> VkFramebufferCreateInfo fb_desc = {.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO};
> - VkAttachmentDescription attachment_desc = {0};
> + VkAttachmentDescription attachment_descs[MAX_RESOURCES] = {0};
> + VkAttachmentReference color_refs[MAX_RESOURCES] = {0};
> VkSubpassDescription subpass_desc = {0};
> - VkAttachmentReference color_ref = {0};
> + VkImageView rtvs[MAX_RESOURCES];
> + unsigned int rt_count = 0;
> + unsigned int i;
>
> - attachment_desc.format = VK_FORMAT_R32G32B32A32_SFLOAT;
> - attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT;
> - attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
> - attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
> - attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
> - attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
> - attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> - attachment_desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> + for (i = 0; i < runner->r.resource_count; ++i)
> + {
> + const struct vulkan_resource *resource = vulkan_resource(runner->r.resources[i]);
> + VkAttachmentDescription *attachment_desc = &attachment_descs[rt_count];
> + VkAttachmentReference *color_ref = &color_refs[rt_count];
>
> - color_ref.attachment = 0;
> - color_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> + if (resource->r.type != RESOURCE_TYPE_RENDER_TARGET)
> + continue;
> +
> + attachment_desc->format = vkd3d_get_vk_format(resource->r.format);
> + attachment_desc->samples = VK_SAMPLE_COUNT_1_BIT;
> + attachment_desc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
> + attachment_desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
> + attachment_desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
> + attachment_desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
> + attachment_desc->initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> + attachment_desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> +
> + color_ref->attachment = rt_count;
> + color_ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
> +
> + rtvs[rt_count] = resource->view;
> +
> + ++rt_count;
> + }
>
> subpass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
> - subpass_desc.colorAttachmentCount = 1;
> - subpass_desc.pColorAttachments = &color_ref;
> + subpass_desc.colorAttachmentCount = rt_count;
> + subpass_desc.pColorAttachments = color_refs;
>
> - render_pass_desc.attachmentCount = 1;
> - render_pass_desc.pAttachments = &attachment_desc;
> + render_pass_desc.attachmentCount = rt_count;
> + render_pass_desc.pAttachments = attachment_descs;
> render_pass_desc.subpassCount = 1;
> render_pass_desc.pSubpasses = &subpass_desc;
>
> VK_CALL(vkCreateRenderPass(runner->device, &render_pass_desc, NULL, render_pass));
>
> fb_desc.renderPass = *render_pass;
> - fb_desc.attachmentCount = 1;
> - fb_desc.pAttachments = &runner->rtv;
> + fb_desc.attachmentCount = rt_count;
> + fb_desc.pAttachments = rtvs;
> fb_desc.width = RENDER_TARGET_WIDTH;
> fb_desc.height = RENDER_TARGET_HEIGHT;
> fb_desc.layers = 1;
> @@ -902,37 +936,40 @@ struct vulkan_resource_readback
> VkBuffer buffer;
> };
>
> -static struct resource_readback *vulkan_runner_get_rt_readback(struct shader_runner *r)
> +static struct resource_readback *vulkan_runner_get_resource_readback(struct shader_runner *r, struct resource *res)
> {
> struct vulkan_shader_runner *runner = vulkan_shader_runner(r);
> struct vulkan_resource_readback *rb = malloc(sizeof(*rb));
> + struct vulkan_resource *resource = vulkan_resource(res);
> VkDevice device = runner->device;
> VkBufferImageCopy region = {0};
>
> - rb->rb.width = RENDER_TARGET_WIDTH;
> - rb->rb.height = RENDER_TARGET_HEIGHT;
> + assert(resource->r.type == RESOURCE_TYPE_RENDER_TARGET);
> +
> + rb->rb.width = resource->r.width;
> + rb->rb.height = resource->r.height;
> rb->rb.depth = 1;
>
> - rb->rb.row_pitch = rb->rb.width * sizeof(struct vec4);
> + rb->rb.row_pitch = rb->rb.width * resource->r.texel_size;
>
> - rb->buffer = create_buffer(runner, rb->rb.row_pitch * RENDER_TARGET_HEIGHT,
> + rb->buffer = create_buffer(runner, rb->rb.row_pitch * rb->rb.height,
> VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &rb->memory);
>
> begin_command_buffer(runner);
>
> - transition_image_layout(runner, runner->render_target,
> + transition_image_layout(runner, resource->image,
> VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
>
> region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
> region.imageSubresource.layerCount = 1;
> - region.imageExtent.width = RENDER_TARGET_WIDTH;
> - region.imageExtent.height = RENDER_TARGET_HEIGHT;
> + region.imageExtent.width = resource->r.width;
> + region.imageExtent.height = resource->r.height;
> region.imageExtent.depth = 1;
>
> - VK_CALL(vkCmdCopyImageToBuffer(runner->cmd_buffer, runner->render_target,
> + VK_CALL(vkCmdCopyImageToBuffer(runner->cmd_buffer, resource->image,
> VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, rb->buffer, 1, ®ion));
>
> - transition_image_layout(runner, runner->render_target,
> + transition_image_layout(runner, resource->image,
> VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
>
> end_command_buffer(runner);
> @@ -959,7 +996,7 @@ static const struct shader_runner_ops vulkan_runner_ops =
> .create_resource = vulkan_runner_create_resource,
> .destroy_resource = vulkan_runner_destroy_resource,
> .draw = vulkan_runner_draw,
> - .get_rt_readback = vulkan_runner_get_rt_readback,
> + .get_resource_readback = vulkan_runner_get_resource_readback,
> .release_readback = vulkan_runner_release_readback,
> };
>
> @@ -1141,11 +1178,6 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner)
>
> VK_CALL(vkAllocateCommandBuffers(device, &cmd_buffer_desc, &runner->cmd_buffer));
>
> - runner->render_target = create_2d_image(runner, RENDER_TARGET_WIDTH, RENDER_TARGET_HEIGHT,
> - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
> - VK_FORMAT_R32G32B32A32_SFLOAT, &runner->rt_memory);
> - runner->rtv = create_2d_image_view(runner, runner->render_target, VK_FORMAT_R32G32B32A32_SFLOAT);
> -
> descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
> descriptor_pool_sizes[0].descriptorCount = MAX_RESOURCES;
> descriptor_pool_sizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLER;
> @@ -1159,13 +1191,6 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner)
>
> VK_CALL(vkCreateDescriptorPool(device, &descriptor_pool_desc, NULL, &runner->descriptor_pool));
>
> - begin_command_buffer(runner);
> -
> - transition_image_layout(runner, runner->render_target,
> - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
> -
> - end_command_buffer(runner);
> -
> return true;
>
> out_destroy_instance:
> @@ -1177,10 +1202,6 @@ static void cleanup_vulkan_runner(struct vulkan_shader_runner *runner)
> {
> VkDevice device = runner->device;
>
> - VK_CALL(vkFreeMemory(device, runner->rt_memory, NULL));
> - VK_CALL(vkDestroyImageView(device, runner->rtv, NULL));
> - VK_CALL(vkDestroyImage(device, runner->render_target, NULL));
> -
> VK_CALL(vkDestroyDescriptorPool(device, runner->descriptor_pool, NULL));
> VK_CALL(vkFreeCommandBuffers(device, runner->command_pool, 1, &runner->cmd_buffer));
> VK_CALL(vkDestroyCommandPool(device, runner->command_pool, NULL));
June 8, 2022