Wine-Devel
Threads by month
- ----- 2026 -----
- 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
January 2021
- 74 participants
- 438 discussions
Signed-off-by: Floris Renaud <jkfloris(a)dds.nl>
---
po/nl.po | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/po/nl.po b/po/nl.po
index c4012a6cb0b..27ef0b5aaba 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -5,7 +5,7 @@ msgstr ""
"Project-Id-Version: Wine\n"
"Report-Msgid-Bugs-To: https://bugs.winehq.org\n"
"POT-Creation-Date: N/A\n"
-"PO-Revision-Date: 2021-01-26 12:00+0100\n"
+"PO-Revision-Date: 2021-01-30 22:00+0100\n"
"Last-Translator: Floris Renaud <jkfloris(a)dds.nl>\n"
"Language-Team: Dutch\n"
"Language: nl\n"
@@ -37,7 +37,7 @@ msgid ""
msgstr ""
"De volgende software kan automatisch verwijderd worden. Om een programma te "
"verwijderen of de geïnstalleerde onderdelen te wijzigen, selecteer het in de "
-"lijst en druk op Wijzigen/Verwijderen."
+"lijst en druk op Wijzigen of Verwijderen."
#: dlls/appwiz.cpl/appwiz.rc:67
msgid "&Support Information"
@@ -7018,7 +7018,7 @@ msgstr "De sink is niet voltooid.\n"
#: dlls/mferror/mferror.mc:732
msgid "Clock was stopped\n"
-msgstr "Klok is gestopt.\n"
+msgstr "Klok is gestopt\n"
#: dlls/mferror/mferror.mc:32
msgid "Media Foundation platform is not initialized.\n"
@@ -7844,7 +7844,7 @@ msgstr "Dienst: [1]"
#: dlls/msi/msi.rc:167 dlls/msi/msi.rc:170 dlls/msi/msi.rc:174
msgid "File: [1], Directory: [9], Size: [6]"
-msgstr "Bestand: [1], Map: [9], Grootte: [6]"
+msgstr "Bestand: [1], Map: [9], Grootte: [6]"
#: dlls/msi/msi.rc:168
msgid "Found application: [1]"
@@ -7860,7 +7860,7 @@ msgstr "Dienst: [2]"
#: dlls/msi/msi.rc:172
msgid "File: [1], Dependencies: [2]"
-msgstr "Bestand: [1], Afhankelijkheden: [2]"
+msgstr "Bestand: [1], Afhankelijkheden: [2]"
#: dlls/msi/msi.rc:173
msgid "Application: [1]"
@@ -7872,7 +7872,7 @@ msgstr "Toepassingscontext:[1], Assemblynaam:[2]"
#: dlls/msi/msi.rc:177
msgid "File: [1], Directory: [2], Size: [3]"
-msgstr "Bestand: [1], Map: [2], Grootte: [3]"
+msgstr "Bestand: [1], Map: [2], Grootte: [3]"
#: dlls/msi/msi.rc:178 dlls/msi/msi.rc:199
msgid "Component ID: [1], Qualifier: [2]"
@@ -7924,7 +7924,7 @@ msgstr "Programma: [1], Opdrachtregel: [2]"
#: dlls/msi/msi.rc:192 dlls/msi/msi.rc:209
msgid "File: [1], Section: [2], Key: [3], Value: [4]"
-msgstr "Bestand: [1], Selectie: [2], Sleutel: [3], Waarde; [4]"
+msgstr "Bestand: [1], Selectie: [2], Sleutel: [3], Waarde; [4]"
#: dlls/msi/msi.rc:193
msgid "Key: [1], Name: [2]"
@@ -9336,7 +9336,7 @@ msgstr "Ja op &alles"
#: dlls/shell32/shell32.rc:319
msgid "About %s"
-msgstr "Info %s"
+msgstr "Over %s"
#: dlls/shell32/shell32.rc:323
msgid "Wine &license"
@@ -9794,6 +9794,7 @@ msgstr ""
"binnen de voorwaarden van de GNU Lesser General Public License zoals "
"gepubliceerd door de Free Software Foundation; versie 2.1 van de licentie, "
"of (naar keuze) een latere versie.\n"
+"\n"
"Wine is gemaakt in de hoop dat het nuttig is, maar komt met GEEN ENKELE "
"GARANTIE; zelfs zonder de impliciete garantie van VERKOOPBAARHEID of "
"GESCHIKTHEID VOOR EEN BEPAALD DOEL. Lees de GNU Lesser General Public "
@@ -12307,8 +12308,7 @@ msgid ""
"It is mainly useful in batch files to allow the user to read the output of\n"
"a previous command before it scrolls off the screen.\n"
msgstr ""
-"PAUSE toont een bericht op het scherm waarin de gebruiker word gevraagd een\n"
-"toets in te drukken.\n"
+"PAUSE toont een bericht waarin wordt gevraagd een toets in te drukken.\n"
"\n"
"Dit is vooral handig in batchbestanden om de gebruiker in staat te stellen\n"
"om de uitvoer van een voorafgaande opdracht te bekijken, voordat het van\n"
@@ -15040,7 +15040,8 @@ msgid ""
msgstr ""
"Wine DLL Registratie Hulpprogramma\n"
"\n"
-"Biedt DLL-registratiediensten\n"
+"Biedt DLL-registratiediensten.\n"
+"\n"
#: programs/regsvr32/regsvr32.rc:40
msgid ""
@@ -16778,7 +16779,7 @@ msgstr "&Naam wijzigen..."
#: programs/winefile/winefile.rc:34
msgid "Propert&ies\tAlt+Enter"
-msgstr "&Eigenschappent\tAlt+Enter"
+msgstr "&Eigenschappen\tAlt+Enter"
#: programs/winefile/winefile.rc:38
msgid "Cr&eate Directory..."
--
2.30.0
1
0
Jan. 30, 2021
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/winemac.drv/systray.c | 2 +-
dlls/winex11.drv/systray.c | 2 +-
include/shellapi.h | 4 ++--
programs/explorer/systray.c | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/winemac.drv/systray.c b/dlls/winemac.drv/systray.c
index 75bca5e3d51..90d2430869d 100644
--- a/dlls/winemac.drv/systray.c
+++ b/dlls/winemac.drv/systray.c
@@ -283,7 +283,7 @@ static BOOL notify_owner(struct tray_icon *icon, UINT msg, int x, int y)
WPARAM wp = icon->id;
LPARAM lp = msg;
- if (icon->version >= NOTIFY_VERSION_4)
+ if (icon->version >= NOTIFYICON_VERSION_4)
{
wp = MAKEWPARAM(x, y);
lp = MAKELPARAM(msg, icon->id);
diff --git a/dlls/winex11.drv/systray.c b/dlls/winex11.drv/systray.c
index 3be4bd65347..952bc1ef266 100644
--- a/dlls/winex11.drv/systray.c
+++ b/dlls/winex11.drv/systray.c
@@ -441,7 +441,7 @@ static BOOL notify_owner( struct tray_icon *icon, UINT msg, LPARAM lparam )
WPARAM wp = icon->id;
LPARAM lp = msg;
- if (icon->version >= NOTIFY_VERSION_4)
+ if (icon->version >= NOTIFYICON_VERSION_4)
{
POINT pt = { (short)LOWORD(lparam), (short)HIWORD(lparam) };
diff --git a/include/shellapi.h b/include/shellapi.h
index 0f10690f7e0..e02869f14e8 100644
--- a/include/shellapi.h
+++ b/include/shellapi.h
@@ -378,8 +378,8 @@ void WINAPI WinExecErrorW(HWND hwnd,INT error, LPCWSTR lpstrFileName, LPCWSTR lp
#define NIM_SETFOCUS 0x00000003
#define NIM_SETVERSION 0x00000004
-#define NOTIFY_VERSION 3 /* supported by Windows 2000 and later */
-#define NOTIFY_VERSION_4 4 /* supported by Windows Vista */
+#define NOTIFYICON_VERSION 3
+#define NOTIFYICON_VERSION_4 4
/* callback message lParam values */
#define NIN_SELECT (WM_USER+0)
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
index dcd75f4e763..5f4fc60dbf3 100644
--- a/programs/explorer/systray.c
+++ b/programs/explorer/systray.c
@@ -723,7 +723,7 @@ static BOOL notify_owner( struct icon *icon, UINT msg, POINT pt )
WPARAM wp = icon->id;
LPARAM lp = msg;
- if (icon->version >= NOTIFY_VERSION_4)
+ if (icon->version >= NOTIFYICON_VERSION_4)
{
ClientToScreen( tray_window, &pt );
wp = MAKEWPARAM( pt.x, pt.y );
--
2.30.0
1
3
Jan. 30, 2021
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50576
Signed-off-by: Vijay Kiran Kamuju <infyquest(a)gmail.com>
1
0
Jan. 30, 2021
Some applications pass this and crash when BIDI_Reorder can't allocate
the memory.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/gdi32/font.c | 1 +
dlls/gdi32/tests/font.c | 2 ++
dlls/gdi32/tests/metafile.c | 8 +++++++-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 74ca482..c0517f5 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -5932,6 +5932,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
static int quietfixme = 0;
if (!dc) return FALSE;
+ if (count == -1) return FALSE;
align = dc->textAlign;
breakRem = dc->breakRem;
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 461eecf..3e1f1e9 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -6916,6 +6916,8 @@ static void test_bitmap_font_glyph_index(void)
hBmpPrev = SelectObject(hdc, hBmp[j]);
switch (j) {
case 0:
+ ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, -1, NULL);
+ ok(!ret, "ExtTextOutW succeeded\n");
ret = ExtTextOutW(hdc, 0, 0, 0, NULL, text, lstrlenW(text), NULL);
break;
case 1:
diff --git a/dlls/gdi32/tests/metafile.c b/dlls/gdi32/tests/metafile.c
index 8dae908..15af24a 100644
--- a/dlls/gdi32/tests/metafile.c
+++ b/dlls/gdi32/tests/metafile.c
@@ -222,7 +222,13 @@ static void test_ExtTextOut(void)
ret = ExtTextOutA(hdcMetafile, 0, 40, 0, NULL, text, lstrlenA(text), NULL);
ok( ret, "ExtTextOutA error %d\n", GetLastError());
- /* 4. test with unmatched BeginPath/EndPath calls */
+ /* 4. pass -1 to length */
+ SetLastError(0xdeadbeef);
+ ret = ExtTextOutA(hdcMetafile, 0, 0, 0, &rc, text, -1, NULL);
+ ok( !ret, "ExtTextOutA succeeded\n");
+ ok( GetLastError() == 0xdeadbeef, "ExtTextOutA error %d\n", GetLastError());
+
+ /* 5. test with unmatched BeginPath/EndPath calls */
ret = BeginPath(hdcMetafile);
ok( ret, "BeginPath error %d\n", GetLastError());
ret = BeginPath(hdcMetafile);
--
2.29.2
2
4
[PATCH 1/5] winegstreamer: Move the "bus" field of struct parser to a new "wg_parser" object.
by Zebediah Figura Jan. 30, 2021
by Zebediah Figura Jan. 30, 2021
Jan. 30, 2021
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/winegstreamer/gstdemux.c | 70 ++++++++++++++++++++++++++++++-----
1 file changed, 60 insertions(+), 10 deletions(-)
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index ea6808ec113..f2b015d99db 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -46,6 +46,11 @@ GST_DEBUG_CATEGORY_STATIC(wine);
static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+struct wg_parser
+{
+ GstBus *bus;
+};
+
struct parser
{
struct strmbase_filter filter;
@@ -60,6 +65,8 @@ struct parser
LONGLONG filesize;
+ struct wg_parser *wg_parser;
+
/* FIXME: It would be nice to avoid duplicating these with strmbase.
* However, synchronization is tricky; we need access to be protected by a
* separate lock. */
@@ -67,7 +74,6 @@ struct parser
GstElement *container;
GstPad *my_src, *their_sink;
- GstBus *bus;
guint64 start, nextofs, nextpullofs, stop;
pthread_mutex_t mutex;
@@ -1556,6 +1562,7 @@ static LONGLONG query_duration(GstPad *pad)
static HRESULT GST_Connect(struct parser *This, IPin *pConnectPin)
{
+ struct wg_parser *parser = This->wg_parser;
unsigned int i;
LONGLONG avail;
GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
@@ -1570,13 +1577,14 @@ static HRESULT GST_Connect(struct parser *This, IPin *pConnectPin)
This->read_thread = CreateThread(NULL, 0, read_thread, This, 0, NULL);
- if (!This->bus) {
- This->bus = gst_bus_new();
- gst_bus_set_sync_handler(This->bus, watch_bus, This, NULL);
+ if (!parser->bus)
+ {
+ parser->bus = gst_bus_new();
+ gst_bus_set_sync_handler(parser->bus, watch_bus, This, NULL);
}
This->container = gst_bin_new(NULL);
- gst_element_set_bus(This->container, This->bus);
+ gst_element_set_bus(This->container, parser->bus);
This->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
gst_pad_set_getrange_function(This->my_src, request_buffer_src);
@@ -1639,6 +1647,17 @@ static struct strmbase_pin *parser_get_pin(struct strmbase_filter *base, unsigne
return NULL;
}
+static void wg_parser_destroy(struct wg_parser *parser)
+{
+ if (parser->bus)
+ {
+ gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
+ gst_object_unref(parser->bus);
+ }
+
+ free(parser);
+}
+
static void parser_destroy(struct strmbase_filter *iface)
{
struct parser *filter = impl_from_strmbase_filter(iface);
@@ -1657,11 +1676,7 @@ static void parser_destroy(struct strmbase_filter *iface)
IAsyncReader_Release(filter->reader);
filter->reader = NULL;
- if (filter->bus)
- {
- gst_bus_set_sync_handler(filter->bus, NULL, NULL, NULL);
- gst_object_unref(filter->bus);
- }
+ wg_parser_destroy(filter->wg_parser);
pthread_cond_destroy(&filter->read_cond);
pthread_cond_destroy(&filter->read_done_cond);
@@ -1966,6 +1981,17 @@ static void parser_init_common(struct parser *object)
object->flushing = true;
}
+static struct wg_parser *wg_parser_create(void)
+{
+ struct wg_parser *parser;
+
+ if (!(parser = calloc(1, sizeof(*parser))))
+ return NULL;
+
+ TRACE("Created winegstreamer parser %p.\n", parser);
+ return parser;
+}
+
HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
{
struct parser *object;
@@ -1978,6 +2004,12 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
+ if (!(object->wg_parser = wg_parser_create()))
+ {
+ heap_free(object);
+ return E_OUTOFMEMORY;
+ }
+
parser_init_common(object);
strmbase_filter_init(&object->filter, outer, &CLSID_decodebin_parser, &filter_ops);
@@ -2632,6 +2664,12 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
+ if (!(object->wg_parser = wg_parser_create()))
+ {
+ heap_free(object);
+ return E_OUTOFMEMORY;
+ }
+
parser_init_common(object);
strmbase_filter_init(&object->filter, outer, &CLSID_WAVEParser, &filter_ops);
@@ -2745,6 +2783,12 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
+ if (!(object->wg_parser = wg_parser_create()))
+ {
+ heap_free(object);
+ return E_OUTOFMEMORY;
+ }
+
parser_init_common(object);
strmbase_filter_init(&object->filter, outer, &CLSID_AviSplitter, &filter_ops);
@@ -2889,6 +2933,12 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out)
if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY;
+ if (!(object->wg_parser = wg_parser_create()))
+ {
+ heap_free(object);
+ return E_OUTOFMEMORY;
+ }
+
parser_init_common(object);
strmbase_filter_init(&object->filter, outer, &CLSID_MPEG1Splitter, &mpeg_splitter_ops);
--
2.30.0
1
4
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
tools/widl/parser.l | 1 +
tools/widl/parser.y | 3 +++
tools/widl/widltypes.h | 1 +
3 files changed, 5 insertions(+)
diff --git a/tools/widl/parser.l b/tools/widl/parser.l
index 6bbfed5e80b..450d92f5926 100644
--- a/tools/widl/parser.l
+++ b/tools/widl/parser.l
@@ -362,6 +362,7 @@ static const struct keyword attr_keywords[] =
{"exclusiveto", tEXCLUSIVETO, 1},
{"explicit_handle", tEXPLICITHANDLE, 0},
{"fault_status", tFAULTSTATUS, 0},
+ {"flags", tFLAGS, 1},
{"force_allocate", tFORCEALLOCATE, 0},
{"free", tFREE, 0},
{"handle", tHANDLE, 0},
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index d12caa06b63..ef54bf13ded 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -201,6 +201,7 @@ static typelib_t *current_typelib;
%token tEXPLICITHANDLE tEXTERN
%token tFALSE
%token tFASTCALL tFAULTSTATUS
+%token tFLAGS
%token tFLOAT tFORCEALLOCATE
%token tHANDLE
%token tHANDLET
@@ -576,6 +577,7 @@ attribute: { $$ = NULL; }
$$ = make_attrp(ATTR_EXCLUSIVETO, $3->type); }
| tEXPLICITHANDLE { $$ = make_attr(ATTR_EXPLICIT_HANDLE); }
| tFAULTSTATUS { $$ = make_attr(ATTR_FAULTSTATUS); }
+ | tFLAGS { $$ = make_attr(ATTR_FLAGS); }
| tFORCEALLOCATE { $$ = make_attr(ATTR_FORCEALLOCATE); }
| tHANDLE { $$ = make_attr(ATTR_HANDLE); }
| tHELPCONTEXT '(' expr_int_const ')' { $$ = make_attrp(ATTR_HELPCONTEXT, $3); }
@@ -2259,6 +2261,7 @@ struct allowed_attr allowed_attr[] =
/* ATTR_EXCLUSIVETO */ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "exclusive_to" },
/* ATTR_EXPLICIT_HANDLE */ { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "explicit_handle" },
/* ATTR_FAULTSTATUS */ { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "fault_status" },
+ /* ATTR_FLAGS */ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "flags" },
/* ATTR_FORCEALLOCATE */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "force_allocate" },
/* ATTR_HANDLE */ { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "handle" },
/* ATTR_HELPCONTEXT */ { 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, "helpcontext" },
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 46a44dac039..7b634c82242 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -106,6 +106,7 @@ enum attr_type
ATTR_EXCLUSIVETO,
ATTR_EXPLICIT_HANDLE,
ATTR_FAULTSTATUS,
+ ATTR_FLAGS,
ATTR_FORCEALLOCATE,
ATTR_HANDLE,
ATTR_HELPCONTEXT,
--
2.30.0
3
9
Jan. 29, 2021
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
This basically shows that the initial plan is a dead-end, and that
I'll have to implement device context swap through wined3d_state
swapping instead.
So, just sending the tests for now.
dlls/d3d11/tests/d3d11.c | 79 +++++++++++++++++++++++++++++++++++-----
1 file changed, 69 insertions(+), 10 deletions(-)
diff --git a/dlls/d3d11/tests/d3d11.c b/dlls/d3d11/tests/d3d11.c
index 7220be73ac7..20bf62b792e 100644
--- a/dlls/d3d11/tests/d3d11.c
+++ b/dlls/d3d11/tests/d3d11.c
@@ -6673,19 +6673,19 @@ static void test_device_context_state(void)
0x00000000, 0x00101e46, 0x00000000, 0x0100003e,
};
- ID3DDeviceContextState *context_state, *previous_context_state;
+ ID3DDeviceContextState *context_state, *previous_context_state, *tmp_context_state, *context_state2;
ID3D11SamplerState *sampler, *tmp_sampler;
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
ID3D11ShaderResourceView *tmp_srv, *srv;
D3D11_DEVICE_CONTEXT_TYPE context_type;
- ID3D11DeviceContext1 *context = NULL;
+ ID3D11DeviceContext1 *context = NULL, *context2;
D3D11_SAMPLER_DESC sampler_desc;
D3D_FEATURE_LEVEL feature_level;
ID3D11GeometryShader *tmp_gs, *gs;
- ID3D11VertexShader *tmp_vs, *vs;
+ ID3D11VertexShader *tmp_vs, *vs, *vs2;
ID3D11PixelShader *tmp_ps, *ps;
- ID3D11Device *d3d11_device;
- ID3D11Device1 *device;
+ ID3D11Device *d3d11_device, *d3d11_device2;
+ ID3D11Device1 *device, *device2;
struct vec4 constant;
ID3D11Buffer *cb, *srvb, *tmp_cb;
ULONG refcount;
@@ -6809,6 +6809,8 @@ static void test_device_context_state(void)
ID3D11DeviceContext1_VSSetSamplers(context, 0, 1, &sampler);
ID3D11DeviceContext1_VSSetShader(context, vs, NULL, 0);
ID3D11DeviceContext1_VSSetShaderResources(context, 0, 1, &srv);
+ refcount = get_refcount(vs);
+ ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
ID3D11DeviceContext1_GSSetConstantBuffers(context, 0, 1, &cb);
ID3D11DeviceContext1_GSSetSamplers(context, 0, 1, &sampler);
@@ -6820,11 +6822,15 @@ static void test_device_context_state(void)
ID3D11DeviceContext1_PSSetShader(context, ps, NULL, 0);
ID3D11DeviceContext1_PSSetShaderResources(context, 0, 1, &srv);
+ previous_context_state = (ID3DDeviceContextState *)0xdeadbeef;
+ ID3D11DeviceContext1_SwapDeviceContextState(context, NULL, &previous_context_state);
+ todo_wine ok(previous_context_state == NULL, "Got unexpected state pointer.\n");
+ if (previous_context_state) ID3DDeviceContextState_Release(previous_context_state);
previous_context_state = NULL;
ID3D11DeviceContext1_SwapDeviceContextState(context, context_state, &previous_context_state);
- refcount = ID3DDeviceContextState_Release(context_state);
- ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
ok(previous_context_state != NULL, "Failed to get previous context state\n");
+ refcount = get_refcount(vs);
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
context_type = ID3D11DeviceContext1_GetType(context);
ok(context_type == D3D11_DEVICE_CONTEXT_IMMEDIATE, "Unexpected context type %u.\n", context_type);
@@ -6868,11 +6874,64 @@ static void test_device_context_state(void)
ID3D11DeviceContext1_PSGetShaderResources(context, 0, 1, &tmp_srv);
ok(!tmp_srv, "Got unexpected srv %p.\n", tmp_srv);
- ID3D11DeviceContext1_SwapDeviceContextState(context, previous_context_state, &context_state);
- refcount = ID3DDeviceContextState_Release(context_state);
- ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
+ /* updating the device context should also update the device context state */
+ hr = ID3D11Device1_CreateVertexShader(device, simple_vs, sizeof(simple_vs), NULL, &vs2);
+ ok(SUCCEEDED(hr), "Failed to create vertex shader, hr %#x.\n", hr);
+ ID3D11DeviceContext1_VSSetShader(context, vs2, NULL, 0);
+ ID3D11DeviceContext1_SwapDeviceContextState(context, context_state, &tmp_context_state);
+ refcount = ID3DDeviceContextState_Release(tmp_context_state);
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+ todo_wine ok(tmp_context_state == context_state, "Got unexpected state pointer.\n");
+ tmp_vs = (ID3D11VertexShader *)0xdeadbeef;
+ ID3D11DeviceContext1_VSGetShader(context, &tmp_vs, NULL, NULL);
+ todo_wine ok(tmp_vs == vs2, "Got shader %p, expected %p.\n", tmp_vs, vs2);
+ if (tmp_vs) refcount = ID3D11VertexShader_Release(tmp_vs);
+ else refcount = 0;
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+
+ /* context states may be used with other devices instances too */
+ d3d11_device2 = create_device(NULL);
+ ok(!!d3d11_device2, "Failed to create device.\n");
+ hr = ID3D11Device_QueryInterface(d3d11_device2, &IID_ID3D11Device1, (void **)&device2);
+ ok(SUCCEEDED(hr), "Failed to query device interface, hr %#x.\n", hr);
+ ID3D11Device_Release(d3d11_device2);
+ ID3D11Device1_GetImmediateContext1(device2, &context2);
+ ok(!!context2, "Failed to get immediate context.\n");
+
+ ID3D11DeviceContext1_SwapDeviceContextState(context2, context_state, &tmp_context_state);
+ ok(!!tmp_context_state, "Failed to get context state.\n");
+ tmp_vs = (ID3D11VertexShader *)0xdeadbeef;
+ ID3D11DeviceContext1_VSGetShader(context, &tmp_vs, NULL, NULL);
+ todo_wine ok(tmp_vs == vs2, "Got shader %p, expected %p.\n", tmp_vs, vs2);
+ if (tmp_vs) refcount = ID3D11VertexShader_Release(tmp_vs);
+ else refcount = 0;
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+ ID3D11DeviceContext1_SwapDeviceContextState(context2, tmp_context_state, &context_state2);
+ refcount = ID3DDeviceContextState_Release(tmp_context_state);
+ ok(refcount == 0, "Got refcount %u, expected 1.\n", refcount);
+ refcount = ID3DDeviceContextState_Release(context_state2);
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+ todo_wine ok(context_state2 == context_state, "Got unexpected state pointer.\n");
+
+ refcount = ID3D11DeviceContext1_Release(context2);
+ ok(refcount == 0, "Got refcount %u, expected 0.\n", refcount);
+ refcount = ID3D11Device1_Release(device2);
+ ok(refcount == 0, "Got refcount %u, expected 0.\n", refcount);
+
+ ID3D11DeviceContext1_VSSetShader(context, NULL, NULL, 0);
+ refcount = ID3D11VertexShader_Release(vs2);
+ ok(refcount == 0, "Got refcount %u, expected 0.\n", refcount);
+
+ ID3D11DeviceContext1_SwapDeviceContextState(context, previous_context_state, &tmp_context_state);
refcount = ID3DDeviceContextState_Release(previous_context_state);
ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
+ refcount = ID3DDeviceContextState_Release(tmp_context_state);
+ todo_wine ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
+ refcount = ID3DDeviceContextState_Release(context_state);
+ ok(!refcount, "Got refcount %u, expected 0.\n", refcount);
+ todo_wine ok(tmp_context_state == context_state, "Got unexpected state pointer.\n");
+ refcount = get_refcount(vs);
+ ok(refcount == 1, "Got refcount %u, expected 1.\n", refcount);
/* ID3DDeviceContextState retains the previous state. */
--
2.30.0
4
12
Jan. 29, 2021
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/d2d1/tests/d2d1.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 3e7df715dda..7c1ff9dc197 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -412,7 +412,7 @@ static void get_d3d11_surface_readback(IDXGISurface *surface, struct resource_re
ID3D11Resource_Release(src_resource);
ID3D11Device_Release(device);
- hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)rb->u.d3d11_resource, 0, D3D11_MAP_READ, 0, &map_desc);
+ hr = ID3D11DeviceContext_Map(context, rb->u.d3d11_resource, 0, D3D11_MAP_READ, 0, &map_desc);
ok(SUCCEEDED(hr), "Failed to map texture, hr %#x.\n", hr);
ID3D11DeviceContext_Release(context);
--
2.26.2
2
1
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/ddraw/device.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index 3f1fe08c11e..4d24c22650e 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -3179,8 +3179,7 @@ static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
wined3d_mutex_lock();
multiply_matrix(&projection, &device->legacy_clipspace, (struct wined3d_matrix *)matrix);
- wined3d_stateblock_set_transform(device->state,
- WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
+ wined3d_stateblock_set_transform(device->state, WINED3D_TS_PROJECTION, &projection);
memcpy(&device->legacy_projection, matrix, sizeof(*matrix));
wined3d_mutex_unlock();
--
2.26.2
3
2
Jan. 29, 2021
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
Used by "Atelier Lydie & Suelle ~The Alchemists and the Mysterious Paintings~".
dlls/wined3d/glsl_shader.c | 6 ++++++
dlls/wined3d/shader.c | 5 +++++
dlls/wined3d/wined3d_private.h | 1 +
3 files changed, 12 insertions(+)
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index c68bb2e9b06..605dc130e0c 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -5744,6 +5744,12 @@ static void shader_glsl_sync(const struct wined3d_shader_instruction *ins)
sync_flags &= ~WINED3DSSF_GROUP_SHARED_MEMORY;
}
+ if (sync_flags & WINED3DSSF_GLOBAL_UAV)
+ {
+ shader_addline(buffer, "memoryBarrier();\n");
+ sync_flags &= ~WINED3DSSF_GLOBAL_UAV;
+ }
+
if (sync_flags)
FIXME("Unhandled sync flags %#x.\n", sync_flags);
}
diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c
index 8843e6883fc..9052d217148 100644
--- a/dlls/wined3d/shader.c
+++ b/dlls/wined3d/shader.c
@@ -1910,6 +1910,11 @@ static void shader_dump_global_flags(struct wined3d_string_buffer *buffer, DWORD
static void shader_dump_sync_flags(struct wined3d_string_buffer *buffer, DWORD sync_flags)
{
+ if (sync_flags & WINED3DSSF_GLOBAL_UAV)
+ {
+ shader_addline(buffer, "_uglobal");
+ sync_flags &= ~WINED3DSSF_GLOBAL_UAV;
+ }
if (sync_flags & WINED3DSSF_GROUP_SHARED_MEMORY)
{
shader_addline(buffer, "_g");
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b3934f0d8e4..4fcfd2fb7c7 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -656,6 +656,7 @@ enum wined3d_shader_sync_flags
{
WINED3DSSF_THREAD_GROUP = 0x1,
WINED3DSSF_GROUP_SHARED_MEMORY = 0x2,
+ WINED3DSSF_GLOBAL_UAV = 0x8,
};
enum wined3d_shader_uav_flags
--
2.29.2
2
1
Jan. 29, 2021
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
include/ddk/ndis.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/ddk/ndis.h b/include/ddk/ndis.h
index 38eec8a7ac4..872b43b5824 100644
--- a/include/ddk/ndis.h
+++ b/include/ddk/ndis.h
@@ -25,7 +25,7 @@
typedef ULONG NDIS_AF, *PNDIS_AF;
typedef MDL NDIS_BUFFER, *PNDIS_BUFFER;
-typedef void *NDIS_HANDLE, *PNDIS_HANDLE, *PNDIS_PACKET_POOL;
+typedef void *NDIS_HANDLE, **PNDIS_HANDLE, *PNDIS_PACKET_POOL;
typedef ULONG NDIS_OID, *PNDIS_OID;
typedef int NDIS_STATUS, *PNDIS_STATUS;
typedef UNICODE_STRING NDIS_STRING, *PNDIS_STRING;
--
2.30.0
1
1
Jan. 29, 2021
This library is the JPEG-XR / Windows Media Photo / HD Photo reference
implementation from Microsoft, released under BSD 2-Clause license:
https://archive.codeplex.com/?p=jxrlib
It is available for most Linux distributions already, and is also an
optional dependency for imagemagick, freeimage or calibre:
* https://packages.debian.org/source/sid/jxrlib
* https://rpmfind.net/linux/rpm2html/search.php?query=jxrlib
* https://packages.ubuntu.com/source/xenial/jxrlib
* https://www.archlinux.org/packages/community/x86_64/jxrlib/
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
v2: * Check for short reads in PATCH 3, and WARN in such case. Some
jxrlib calls don't care about the returned value so ERR would be
verbose.
* Add an ERR message when jxrlib support isn't compiled in.
Supersedes: 198075-198079 and 198035-198039
configure.ac | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/configure.ac b/configure.ac
index 0f8b9f6c080..4f95a1325d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,6 +58,7 @@ AC_ARG_WITH(gstreamer, AS_HELP_STRING([--without-gstreamer],[do not use GStreame
AC_ARG_WITH(hal, AS_HELP_STRING([--without-hal],[do not use HAL (dynamic device support)]))
AC_ARG_WITH(inotify, AS_HELP_STRING([--without-inotify],[do not use inotify (filesystem change notifications)]))
AC_ARG_WITH(jpeg, AS_HELP_STRING([--without-jpeg],[do not use JPEG]))
+AC_ARG_WITH(jxrlib, AS_HELP_STRING([--without-jxrlib],[do not use JPEG-XR]))
AC_ARG_WITH(krb5, AS_HELP_STRING([--without-krb5],[do not use krb5 (Kerberos)]))
AC_ARG_WITH(ldap, AS_HELP_STRING([--without-ldap],[do not use LDAP]),
[if test "x$withval" = "xno"; then ac_cv_header_ldap_h=no; ac_cv_header_lber_h=no; fi])
@@ -1829,6 +1830,21 @@ fi
WINE_WARNING_WITH(jpeg,[test "x$ac_cv_lib_soname_jpeg" = "x"],
[libjpeg ${notice_platform}development files not found, JPEG won't be supported.])
+dnl **** Check for libjxrglue ****
+if test "x$with_jxrlib" != "xno"
+then
+ WINE_PACKAGE_FLAGS(JXRLIB,[jxrlib],,[${JXRLIB_CFLAGS:--I/usr/include/jxrlib}],,
+ [AC_CHECK_HEADERS([JXRGlue.h],,,[#define FAR])
+ if test "$ac_cv_header_JXRGlue_h" = "yes"
+ then
+ WINE_CHECK_SONAME(jxrglue,PKImageDecode_Create_WMP,,[JXRLIB_CFLAGS=""],[$JXRLIB_LIBS])
+ else
+ JXRLIB_CFLAGS=""
+ fi])
+fi
+WINE_WARNING_WITH(jxrlib,[test "x$ac_cv_lib_soname_jxrglue" = "x"],
+ [jxrlib ${notice_platform}development files not found, JPEG-XR won't be supported.])
+
dnl **** Check for libpng ****
if test "x$with_png" != "xno"
then
--
2.30.0
3
6
[PATCH vkd3d 1/2] vkd3d-compiler: Set default source type before handling --print-target-types.
by Matteo Bruni Jan. 29, 2021
by Matteo Bruni Jan. 29, 2021
Jan. 29, 2021
Signed-off-by: Matteo Bruni <mbruni(a)codeweavers.com>
---
programs/vkd3d-compiler/main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/programs/vkd3d-compiler/main.c b/programs/vkd3d-compiler/main.c
index 94cce20..e98e713 100644
--- a/programs/vkd3d-compiler/main.c
+++ b/programs/vkd3d-compiler/main.c
@@ -480,14 +480,14 @@ static bool parse_command_line(int argc, char **argv, struct options *options)
}
}
- if (options->print_target_types)
- return true;
-
if (options->source_type == VKD3D_SHADER_SOURCE_NONE)
options->source_type = options->preprocess_only ? VKD3D_SHADER_SOURCE_HLSL : VKD3D_SHADER_SOURCE_DXBC_TPF;
if (options->target_type == VKD3D_SHADER_TARGET_NONE && !options->preprocess_only)
options->target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
+ if (options->print_target_types)
+ return true;
+
if (!options->preprocess_only && !validate_target_type(options->source_type, options->target_type))
{
fprintf(stderr, "Target type '%s' is invalid for source type '%s'.\n",
--
2.26.2
3
5
Jan. 29, 2021
This corresponds to Wine commit 9f9fec18799bf59df6211b7294f8d338caa7f4db.
Note that for the moment, compilation messages have not been ported.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v4: Default to "main" if the entry point is NULL.
Makefile.am | 16 +-
libs/vkd3d-shader/hlsl.c | 1672 ++++++++++++
libs/vkd3d-shader/hlsl.h | 644 +++++
libs/vkd3d-shader/hlsl.l | 288 +++
libs/vkd3d-shader/hlsl.y | 2961 ++++++++++++++++++++++
libs/vkd3d-shader/trace.c | 9 +
libs/vkd3d-shader/vkd3d_shader_main.c | 13 +-
libs/vkd3d-shader/vkd3d_shader_private.h | 9 +
8 files changed, 5609 insertions(+), 3 deletions(-)
create mode 100644 libs/vkd3d-shader/hlsl.c
create mode 100644 libs/vkd3d-shader/hlsl.h
create mode 100644 libs/vkd3d-shader/hlsl.l
create mode 100644 libs/vkd3d-shader/hlsl.y
diff --git a/Makefile.am b/Makefile.am
index 27d933c9..96d6140d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,9 +126,22 @@ libs/vkd3d-shader/preproc.tab.c libs/vkd3d-shader/preproc.tab.h &: libs/vkd3d-sh
@$(MKDIR_P) libs/vkd3d-shader
$(VKD3D_V_BISON)$(BISON) $(YFLAGS) -d -o libs/vkd3d-shader/preproc.tab.c $<
-BUILT_SOURCES += libs/vkd3d-shader/preproc.tab.h
+libs/vkd3d-shader/hlsl.yy.c: $(srcdir)/libs/vkd3d-shader/hlsl.l
+ @$(MKDIR_P) libs/vkd3d-shader
+ $(VKD3D_V_FLEX)$(FLEX) $(LFLAGS) -o $@ $<
+
+libs/vkd3d-shader/hlsl.tab.c libs/vkd3d-shader/hlsl.tab.h &: libs/vkd3d-shader/hlsl.y
+ @$(MKDIR_P) libs/vkd3d-shader
+ $(VKD3D_V_BISON)$(BISON) $(YFLAGS) -d -o libs/vkd3d-shader/hlsl.tab.c $<
+
+BUILT_SOURCES += \
+ libs/vkd3d-shader/hlsl.tab.h \
+ libs/vkd3d-shader/preproc.tab.h
vkd3d_shader_yyfiles = \
+ libs/vkd3d-shader/hlsl.tab.c \
+ libs/vkd3d-shader/hlsl.tab.h \
+ libs/vkd3d-shader/hlsl.yy.c \
libs/vkd3d-shader/preproc.tab.c \
libs/vkd3d-shader/preproc.tab.h \
libs/vkd3d-shader/preproc.yy.c
@@ -146,6 +159,7 @@ libvkd3d_shader_la_SOURCES = \
include/vkd3d_shader.h \
libs/vkd3d-shader/checksum.c \
libs/vkd3d-shader/dxbc.c \
+ libs/vkd3d-shader/hlsl.c \
libs/vkd3d-shader/spirv.c \
libs/vkd3d-shader/trace.c \
libs/vkd3d-shader/vkd3d_shader.map \
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
new file mode 100644
index 00000000..cd0d9cbc
--- /dev/null
+++ b/libs/vkd3d-shader/hlsl.c
@@ -0,0 +1,1672 @@
+/*
+ * Copyright 2012 Matteo Bruni for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "hlsl.h"
+
+BOOL add_declaration(struct hlsl_scope *scope, struct hlsl_ir_var *decl, BOOL local_var)
+{
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (!strcmp(decl->name, var->name))
+ return FALSE;
+ }
+ if (local_var && scope->upper->upper == hlsl_ctx.globals)
+ {
+ /* Check whether the variable redefines a function parameter. */
+ LIST_FOR_EACH_ENTRY(var, &scope->upper->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (!strcmp(decl->name, var->name))
+ return FALSE;
+ }
+ }
+
+ list_add_tail(&scope->vars, &decl->scope_entry);
+ return TRUE;
+}
+
+struct hlsl_ir_var *get_variable(struct hlsl_scope *scope, const char *name)
+{
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ {
+ if (!strcmp(name, var->name))
+ return var;
+ }
+ if (!scope->upper)
+ return NULL;
+ return get_variable(scope->upper, name);
+}
+
+void free_declaration(struct hlsl_ir_var *decl)
+{
+ vkd3d_free((void *)decl->name);
+ vkd3d_free((void *)decl->semantic);
+ vkd3d_free((void *)decl->reg_reservation);
+ vkd3d_free(decl);
+}
+
+struct hlsl_type *new_hlsl_type(const char *name, enum hlsl_type_class type_class,
+ enum hlsl_base_type base_type, unsigned dimx, unsigned dimy)
+{
+ struct hlsl_type *type;
+
+ if (!(type = vkd3d_calloc(1, sizeof(*type))))
+ return NULL;
+ type->name = name;
+ type->type = type_class;
+ type->base_type = base_type;
+ type->dimx = dimx;
+ type->dimy = dimy;
+ if (type_class == HLSL_CLASS_MATRIX)
+ type->reg_size = is_row_major(type) ? dimy : dimx;
+ else
+ type->reg_size = 1;
+
+ list_add_tail(&hlsl_ctx.types, &type->entry);
+
+ return type;
+}
+
+struct hlsl_type *new_array_type(struct hlsl_type *basic_type, unsigned int array_size)
+{
+ struct hlsl_type *type = new_hlsl_type(NULL, HLSL_CLASS_ARRAY, HLSL_TYPE_FLOAT, 1, 1);
+
+ if (!type)
+ return NULL;
+
+ type->modifiers = basic_type->modifiers;
+ type->e.array.elements_count = array_size;
+ type->e.array.type = basic_type;
+ type->reg_size = basic_type->reg_size * array_size;
+ type->dimx = basic_type->dimx;
+ type->dimy = basic_type->dimy;
+ return type;
+}
+
+struct hlsl_type *get_type(struct hlsl_scope *scope, const char *name, BOOL recursive)
+{
+ struct rb_entry *entry = rb_get(&scope->types, name);
+
+ if (entry)
+ return RB_ENTRY_VALUE(entry, struct hlsl_type, scope_entry);
+
+ if (recursive && scope->upper)
+ return get_type(scope->upper, name, recursive);
+ return NULL;
+}
+
+BOOL find_function(const char *name)
+{
+ return rb_get(&hlsl_ctx.functions, name) != NULL;
+}
+
+unsigned int components_count_type(struct hlsl_type *type)
+{
+ struct hlsl_struct_field *field;
+ unsigned int count = 0;
+
+ if (type->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ return type->dimx * type->dimy;
+ }
+ if (type->type == HLSL_CLASS_ARRAY)
+ {
+ return components_count_type(type->e.array.type) * type->e.array.elements_count;
+ }
+ if (type->type != HLSL_CLASS_STRUCT)
+ {
+ ERR("Unexpected data type %s.\n", debug_hlsl_type(type));
+ return 0;
+ }
+
+ LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry)
+ {
+ count += components_count_type(field->type);
+ }
+ return count;
+}
+
+BOOL compare_hlsl_types(const struct hlsl_type *t1, const struct hlsl_type *t2)
+{
+ if (t1 == t2)
+ return TRUE;
+
+ if (t1->type != t2->type)
+ return FALSE;
+ if (t1->base_type != t2->base_type)
+ return FALSE;
+ if (t1->base_type == HLSL_TYPE_SAMPLER && t1->sampler_dim != t2->sampler_dim)
+ return FALSE;
+ if ((t1->modifiers & HLSL_MODIFIERS_MAJORITY_MASK)
+ != (t2->modifiers & HLSL_MODIFIERS_MAJORITY_MASK))
+ return FALSE;
+ if (t1->dimx != t2->dimx)
+ return FALSE;
+ if (t1->dimy != t2->dimy)
+ return FALSE;
+ if (t1->type == HLSL_CLASS_STRUCT)
+ {
+ struct list *t1cur, *t2cur;
+ struct hlsl_struct_field *t1field, *t2field;
+
+ t1cur = list_head(t1->e.elements);
+ t2cur = list_head(t2->e.elements);
+ while (t1cur && t2cur)
+ {
+ t1field = LIST_ENTRY(t1cur, struct hlsl_struct_field, entry);
+ t2field = LIST_ENTRY(t2cur, struct hlsl_struct_field, entry);
+ if (!compare_hlsl_types(t1field->type, t2field->type))
+ return FALSE;
+ if (strcmp(t1field->name, t2field->name))
+ return FALSE;
+ t1cur = list_next(t1->e.elements, t1cur);
+ t2cur = list_next(t2->e.elements, t2cur);
+ }
+ if (t1cur != t2cur)
+ return FALSE;
+ }
+ if (t1->type == HLSL_CLASS_ARRAY)
+ return t1->e.array.elements_count == t2->e.array.elements_count
+ && compare_hlsl_types(t1->e.array.type, t2->e.array.type);
+
+ return TRUE;
+}
+
+struct hlsl_type *clone_hlsl_type(struct hlsl_type *old, unsigned int default_majority)
+{
+ struct hlsl_struct_field *old_field, *field;
+ struct hlsl_type *type;
+
+ if (!(type = vkd3d_calloc(1, sizeof(*type))))
+ return NULL;
+
+ if (old->name)
+ {
+ type->name = vkd3d_strdup(old->name);
+ if (!type->name)
+ {
+ vkd3d_free(type);
+ return NULL;
+ }
+ }
+ type->type = old->type;
+ type->base_type = old->base_type;
+ type->dimx = old->dimx;
+ type->dimy = old->dimy;
+ type->modifiers = old->modifiers;
+ if (!(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK))
+ type->modifiers |= default_majority;
+ type->sampler_dim = old->sampler_dim;
+ switch (old->type)
+ {
+ case HLSL_CLASS_ARRAY:
+ type->e.array.type = clone_hlsl_type(old->e.array.type, default_majority);
+ type->e.array.elements_count = old->e.array.elements_count;
+ type->reg_size = type->e.array.elements_count * type->e.array.type->reg_size;
+ break;
+
+ case HLSL_CLASS_STRUCT:
+ {
+ unsigned int reg_size = 0;
+
+ if (!(type->e.elements = vkd3d_malloc(sizeof(*type->e.elements))))
+ {
+ vkd3d_free((void *)type->name);
+ vkd3d_free(type);
+ return NULL;
+ }
+ list_init(type->e.elements);
+ LIST_FOR_EACH_ENTRY(old_field, old->e.elements, struct hlsl_struct_field, entry)
+ {
+ if (!(field = vkd3d_calloc(1, sizeof(*field))))
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(field, old_field, type->e.elements, struct hlsl_struct_field, entry)
+ {
+ vkd3d_free((void *)field->semantic);
+ vkd3d_free((void *)field->name);
+ vkd3d_free(field);
+ }
+ vkd3d_free(type->e.elements);
+ vkd3d_free((void *)type->name);
+ vkd3d_free(type);
+ return NULL;
+ }
+ field->type = clone_hlsl_type(old_field->type, default_majority);
+ field->name = vkd3d_strdup(old_field->name);
+ if (old_field->semantic)
+ field->semantic = vkd3d_strdup(old_field->semantic);
+ field->modifiers = old_field->modifiers;
+ field->reg_offset = reg_size;
+ reg_size += field->type->reg_size;
+ list_add_tail(type->e.elements, &field->entry);
+ }
+ type->reg_size = reg_size;
+ break;
+ }
+
+ case HLSL_CLASS_MATRIX:
+ type->reg_size = is_row_major(type) ? type->dimy : type->dimx;
+ break;
+
+ default:
+ type->reg_size = 1;
+ break;
+ }
+
+ list_add_tail(&hlsl_ctx.types, &type->entry);
+ return type;
+}
+
+static BOOL convertible_data_type(struct hlsl_type *type)
+{
+ return type->type != HLSL_CLASS_OBJECT;
+}
+
+BOOL compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2)
+{
+ if (!convertible_data_type(t1) || !convertible_data_type(t2))
+ return FALSE;
+
+ if (t1->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ /* Scalar vars can be cast to pretty much everything */
+ if (t1->dimx == 1 && t1->dimy == 1)
+ return TRUE;
+
+ if (t1->type == HLSL_CLASS_VECTOR && t2->type == HLSL_CLASS_VECTOR)
+ return t1->dimx >= t2->dimx;
+ }
+
+ /* The other way around is true too i.e. whatever to scalar */
+ if (t2->type <= HLSL_CLASS_LAST_NUMERIC && t2->dimx == 1 && t2->dimy == 1)
+ return TRUE;
+
+ if (t1->type == HLSL_CLASS_ARRAY)
+ {
+ if (compare_hlsl_types(t1->e.array.type, t2))
+ /* e.g. float4[3] to float4 is allowed */
+ return TRUE;
+
+ if (t2->type == HLSL_CLASS_ARRAY || t2->type == HLSL_CLASS_STRUCT)
+ return components_count_type(t1) >= components_count_type(t2);
+ else
+ return components_count_type(t1) == components_count_type(t2);
+ }
+
+ if (t1->type == HLSL_CLASS_STRUCT)
+ return components_count_type(t1) >= components_count_type(t2);
+
+ if (t2->type == HLSL_CLASS_ARRAY || t2->type == HLSL_CLASS_STRUCT)
+ return components_count_type(t1) == components_count_type(t2);
+
+ if (t1->type == HLSL_CLASS_MATRIX || t2->type == HLSL_CLASS_MATRIX)
+ {
+ if (t1->type == HLSL_CLASS_MATRIX && t2->type == HLSL_CLASS_MATRIX && t1->dimx >= t2->dimx && t1->dimy >= t2->dimy)
+ return TRUE;
+
+ /* Matrix-vector conversion is apparently allowed if they have the same components count */
+ if ((t1->type == HLSL_CLASS_VECTOR || t2->type == HLSL_CLASS_VECTOR)
+ && components_count_type(t1) == components_count_type(t2))
+ return TRUE;
+ return FALSE;
+ }
+
+ if (components_count_type(t1) >= components_count_type(t2))
+ return TRUE;
+ return FALSE;
+}
+
+static BOOL implicit_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2)
+{
+ if (!convertible_data_type(t1) || !convertible_data_type(t2))
+ return FALSE;
+
+ if (t1->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ /* Scalar vars can be converted to any other numeric data type */
+ if (t1->dimx == 1 && t1->dimy == 1 && t2->type <= HLSL_CLASS_LAST_NUMERIC)
+ return TRUE;
+ /* The other way around is true too */
+ if (t2->dimx == 1 && t2->dimy == 1 && t2->type <= HLSL_CLASS_LAST_NUMERIC)
+ return TRUE;
+ }
+
+ if (t1->type == HLSL_CLASS_ARRAY && t2->type == HLSL_CLASS_ARRAY)
+ {
+ return components_count_type(t1) == components_count_type(t2);
+ }
+
+ if ((t1->type == HLSL_CLASS_ARRAY && t2->type <= HLSL_CLASS_LAST_NUMERIC)
+ || (t1->type <= HLSL_CLASS_LAST_NUMERIC && t2->type == HLSL_CLASS_ARRAY))
+ {
+ /* e.g. float4[3] to float4 is allowed */
+ if (t1->type == HLSL_CLASS_ARRAY && compare_hlsl_types(t1->e.array.type, t2))
+ return TRUE;
+ if (components_count_type(t1) == components_count_type(t2))
+ return TRUE;
+ return FALSE;
+ }
+
+ if (t1->type <= HLSL_CLASS_VECTOR && t2->type <= HLSL_CLASS_VECTOR)
+ {
+ if (t1->dimx >= t2->dimx)
+ return TRUE;
+ return FALSE;
+ }
+
+ if (t1->type == HLSL_CLASS_MATRIX || t2->type == HLSL_CLASS_MATRIX)
+ {
+ if (t1->type == HLSL_CLASS_MATRIX && t2->type == HLSL_CLASS_MATRIX
+ && t1->dimx >= t2->dimx && t1->dimy >= t2->dimy)
+ return TRUE;
+
+ /* Matrix-vector conversion is apparently allowed if they have the same components count */
+ if ((t1->type == HLSL_CLASS_VECTOR || t2->type == HLSL_CLASS_VECTOR)
+ && components_count_type(t1) == components_count_type(t2))
+ return TRUE;
+ return FALSE;
+ }
+
+ if (t1->type == HLSL_CLASS_STRUCT && t2->type == HLSL_CLASS_STRUCT)
+ return compare_hlsl_types(t1, t2);
+
+ return FALSE;
+}
+
+static BOOL expr_compatible_data_types(struct hlsl_type *t1, struct hlsl_type *t2)
+{
+ if (t1->base_type > HLSL_TYPE_LAST_SCALAR || t2->base_type > HLSL_TYPE_LAST_SCALAR)
+ return FALSE;
+
+ /* Scalar vars can be converted to pretty much everything */
+ if ((t1->dimx == 1 && t1->dimy == 1) || (t2->dimx == 1 && t2->dimy == 1))
+ return TRUE;
+
+ if (t1->type == HLSL_CLASS_VECTOR && t2->type == HLSL_CLASS_VECTOR)
+ return TRUE;
+
+ if (t1->type == HLSL_CLASS_MATRIX || t2->type == HLSL_CLASS_MATRIX)
+ {
+ /* Matrix-vector conversion is apparently allowed if either they have the same components
+ count or the matrix is nx1 or 1xn */
+ if (t1->type == HLSL_CLASS_VECTOR || t2->type == HLSL_CLASS_VECTOR)
+ {
+ if (components_count_type(t1) == components_count_type(t2))
+ return TRUE;
+
+ return (t1->type == HLSL_CLASS_MATRIX && (t1->dimx == 1 || t1->dimy == 1))
+ || (t2->type == HLSL_CLASS_MATRIX && (t2->dimx == 1 || t2->dimy == 1));
+ }
+
+ /* Both matrices */
+ if ((t1->dimx >= t2->dimx && t1->dimy >= t2->dimy)
+ || (t1->dimx <= t2->dimx && t1->dimy <= t2->dimy))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static enum hlsl_base_type expr_common_base_type(enum hlsl_base_type t1, enum hlsl_base_type t2)
+{
+ static const enum hlsl_base_type types[] =
+ {
+ HLSL_TYPE_BOOL,
+ HLSL_TYPE_INT,
+ HLSL_TYPE_UINT,
+ HLSL_TYPE_HALF,
+ HLSL_TYPE_FLOAT,
+ HLSL_TYPE_DOUBLE,
+ };
+ int t1_idx = -1, t2_idx = -1, i;
+
+ for (i = 0; i < ARRAY_SIZE(types); ++i)
+ {
+ /* Always convert away from HLSL_TYPE_HALF */
+ if (t1 == types[i])
+ t1_idx = t1 == HLSL_TYPE_HALF ? i + 1 : i;
+ if (t2 == types[i])
+ t2_idx = t2 == HLSL_TYPE_HALF ? i + 1 : i;
+
+ if (t1_idx != -1 && t2_idx != -1)
+ break;
+ }
+ if (t1_idx == -1 || t2_idx == -1)
+ {
+ FIXME("Unexpected base type.\n");
+ return HLSL_TYPE_FLOAT;
+ }
+ return t1_idx >= t2_idx ? t1 : t2;
+}
+
+static struct hlsl_type *expr_common_type(struct hlsl_type *t1, struct hlsl_type *t2,
+ struct source_location *loc)
+{
+ enum hlsl_type_class type;
+ enum hlsl_base_type base;
+ unsigned int dimx, dimy;
+
+ if (t1->type > HLSL_CLASS_LAST_NUMERIC || t2->type > HLSL_CLASS_LAST_NUMERIC)
+ {
+ hlsl_report_message(*loc, HLSL_LEVEL_ERROR, "non scalar/vector/matrix data type in expression");
+ return NULL;
+ }
+
+ if (compare_hlsl_types(t1, t2))
+ return t1;
+
+ if (!expr_compatible_data_types(t1, t2))
+ {
+ hlsl_report_message(*loc, HLSL_LEVEL_ERROR, "expression data types are incompatible");
+ return NULL;
+ }
+
+ if (t1->base_type == t2->base_type)
+ base = t1->base_type;
+ else
+ base = expr_common_base_type(t1->base_type, t2->base_type);
+
+ if (t1->dimx == 1 && t1->dimy == 1)
+ {
+ type = t2->type;
+ dimx = t2->dimx;
+ dimy = t2->dimy;
+ }
+ else if (t2->dimx == 1 && t2->dimy == 1)
+ {
+ type = t1->type;
+ dimx = t1->dimx;
+ dimy = t1->dimy;
+ }
+ else if (t1->type == HLSL_CLASS_MATRIX && t2->type == HLSL_CLASS_MATRIX)
+ {
+ type = HLSL_CLASS_MATRIX;
+ dimx = min(t1->dimx, t2->dimx);
+ dimy = min(t1->dimy, t2->dimy);
+ }
+ else
+ {
+ /* Two vectors or a vector and a matrix (matrix must be 1xn or nx1) */
+ unsigned int max_dim_1, max_dim_2;
+
+ max_dim_1 = max(t1->dimx, t1->dimy);
+ max_dim_2 = max(t2->dimx, t2->dimy);
+ if (t1->dimx * t1->dimy == t2->dimx * t2->dimy)
+ {
+ type = HLSL_CLASS_VECTOR;
+ dimx = max(t1->dimx, t2->dimx);
+ dimy = 1;
+ }
+ else if (max_dim_1 <= max_dim_2)
+ {
+ type = t1->type;
+ if (type == HLSL_CLASS_VECTOR)
+ {
+ dimx = max_dim_1;
+ dimy = 1;
+ }
+ else
+ {
+ dimx = t1->dimx;
+ dimy = t1->dimy;
+ }
+ }
+ else
+ {
+ type = t2->type;
+ if (type == HLSL_CLASS_VECTOR)
+ {
+ dimx = max_dim_2;
+ dimy = 1;
+ }
+ else
+ {
+ dimx = t2->dimx;
+ dimy = t2->dimy;
+ }
+ }
+ }
+
+ if (type == HLSL_CLASS_SCALAR)
+ return hlsl_ctx.builtin_types.scalar[base];
+ if (type == HLSL_CLASS_VECTOR)
+ return hlsl_ctx.builtin_types.vector[base][dimx - 1];
+ return new_hlsl_type(NULL, type, base, dimx, dimy);
+}
+
+struct hlsl_ir_node *add_implicit_conversion(struct list *instrs, struct hlsl_ir_node *node,
+ struct hlsl_type *dst_type, struct source_location *loc)
+{
+ struct hlsl_type *src_type = node->data_type;
+ struct hlsl_ir_expr *cast;
+
+ if (compare_hlsl_types(src_type, dst_type))
+ return node;
+
+ if (!implicit_compatible_data_types(src_type, dst_type))
+ {
+ hlsl_report_message(*loc, HLSL_LEVEL_ERROR, "can't implicitly convert %s to %s",
+ debug_hlsl_type(src_type), debug_hlsl_type(dst_type));
+ return NULL;
+ }
+
+ if (dst_type->dimx * dst_type->dimy < src_type->dimx * src_type->dimy)
+ hlsl_report_message(*loc, HLSL_LEVEL_WARNING, "implicit truncation of vector type");
+
+ TRACE("Implicit conversion from %s to %s.\n", debug_hlsl_type(src_type), debug_hlsl_type(dst_type));
+
+ if (!(cast = new_cast(node, dst_type, loc)))
+ return NULL;
+ list_add_tail(instrs, &cast->node.entry);
+ return &cast->node;
+}
+
+struct hlsl_ir_expr *add_expr(struct list *instrs, enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[3],
+ struct source_location *loc)
+{
+ struct hlsl_ir_expr *expr;
+ struct hlsl_type *type;
+ unsigned int i;
+
+ type = operands[0]->data_type;
+ for (i = 1; i <= 2; ++i)
+ {
+ if (!operands[i])
+ break;
+ type = expr_common_type(type, operands[i]->data_type, loc);
+ if (!type)
+ return NULL;
+ }
+ for (i = 0; i <= 2; ++i)
+ {
+ struct hlsl_ir_expr *cast;
+
+ if (!operands[i])
+ break;
+ if (compare_hlsl_types(operands[i]->data_type, type))
+ continue;
+ TRACE("Implicitly converting %s into %s in an expression.\n", debug_hlsl_type(operands[i]->data_type), debug_hlsl_type(type));
+ if (operands[i]->data_type->dimx * operands[i]->data_type->dimy != 1
+ && operands[i]->data_type->dimx * operands[i]->data_type->dimy != type->dimx * type->dimy)
+ {
+ hlsl_report_message(operands[i]->loc, HLSL_LEVEL_WARNING, "implicit truncation of vector/matrix type");
+ }
+
+ if (!(cast = new_cast(operands[i], type, &operands[i]->loc)))
+ return NULL;
+ list_add_after(&operands[i]->entry, &cast->node.entry);
+ operands[i] = &cast->node;
+ }
+
+ if (!(expr = vkd3d_calloc(1, sizeof(*expr))))
+ return NULL;
+ init_node(&expr->node, HLSL_IR_EXPR, type, *loc);
+ expr->op = op;
+ for (i = 0; i <= 2; ++i)
+ hlsl_src_from_node(&expr->operands[i], operands[i]);
+ list_add_tail(instrs, &expr->node.entry);
+
+ return expr;
+}
+
+struct hlsl_ir_expr *new_cast(struct hlsl_ir_node *node, struct hlsl_type *type,
+ struct source_location *loc)
+{
+ struct hlsl_ir_node *cast;
+
+ cast = new_unary_expr(HLSL_IR_UNOP_CAST, node, *loc);
+ if (cast)
+ cast->data_type = type;
+ return expr_from_node(cast);
+}
+
+static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op)
+{
+ static const enum hlsl_ir_expr_op ops[] =
+ {
+ 0,
+ HLSL_IR_BINOP_ADD,
+ HLSL_IR_BINOP_SUB,
+ HLSL_IR_BINOP_MUL,
+ HLSL_IR_BINOP_DIV,
+ HLSL_IR_BINOP_MOD,
+ HLSL_IR_BINOP_LSHIFT,
+ HLSL_IR_BINOP_RSHIFT,
+ HLSL_IR_BINOP_BIT_AND,
+ HLSL_IR_BINOP_BIT_OR,
+ HLSL_IR_BINOP_BIT_XOR,
+ };
+
+ return ops[op];
+}
+
+static BOOL invert_swizzle(unsigned int *swizzle, unsigned int *writemask, unsigned int *ret_width)
+{
+ unsigned int i, j, bit = 0, inverted = 0, width, new_writemask = 0, new_swizzle = 0;
+
+ /* Apply the writemask to the swizzle to get a new writemask and swizzle. */
+ for (i = 0; i < 4; ++i)
+ {
+ if (*writemask & (1 << i))
+ {
+ unsigned int s = (*swizzle >> (i * 2)) & 3;
+ new_swizzle |= s << (bit++ * 2);
+ if (new_writemask & (1 << s))
+ return FALSE;
+ new_writemask |= 1 << s;
+ }
+ }
+ width = bit;
+
+ /* Invert the swizzle. */
+ bit = 0;
+ for (i = 0; i < 4; ++i)
+ {
+ for (j = 0; j < width; ++j)
+ {
+ unsigned int s = (new_swizzle >> (j * 2)) & 3;
+ if (s == i)
+ inverted |= j << (bit++ * 2);
+ }
+ }
+
+ *swizzle = inverted;
+ *writemask = new_writemask;
+ *ret_width = width;
+ return TRUE;
+}
+
+struct hlsl_ir_node *add_assignment(struct list *instrs, struct hlsl_ir_node *lhs,
+ enum parse_assign_op assign_op, struct hlsl_ir_node *rhs)
+{
+ struct hlsl_ir_assignment *assign;
+ struct hlsl_type *lhs_type;
+ DWORD writemask = 0;
+
+ lhs_type = lhs->data_type;
+ if (lhs_type->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ writemask = (1 << lhs_type->dimx) - 1;
+
+ if (!(rhs = add_implicit_conversion(instrs, rhs, lhs_type, &rhs->loc)))
+ return NULL;
+ }
+
+ if (!(assign = vkd3d_malloc(sizeof(*assign))))
+ return NULL;
+
+ while (lhs->type != HLSL_IR_LOAD)
+ {
+ struct hlsl_ir_node *lhs_inner;
+
+ if (lhs->type == HLSL_IR_EXPR && expr_from_node(lhs)->op == HLSL_IR_UNOP_CAST)
+ {
+ FIXME("Cast on the lhs.\n");
+ vkd3d_free(assign);
+ return NULL;
+ }
+ else if (lhs->type == HLSL_IR_SWIZZLE)
+ {
+ struct hlsl_ir_swizzle *swizzle = swizzle_from_node(lhs);
+ const struct hlsl_type *swizzle_type = swizzle->node.data_type;
+ unsigned int width;
+
+ if (lhs->data_type->type == HLSL_CLASS_MATRIX)
+ FIXME("Assignments with writemasks and matrices on lhs are not supported yet.\n");
+
+ lhs_inner = swizzle->val.node;
+ hlsl_src_remove(&swizzle->val);
+ list_remove(&lhs->entry);
+
+ list_add_after(&rhs->entry, &lhs->entry);
+ hlsl_src_from_node(&swizzle->val, rhs);
+ if (!invert_swizzle(&swizzle->swizzle, &writemask, &width))
+ {
+ hlsl_report_message(lhs->loc, HLSL_LEVEL_ERROR, "invalid writemask");
+ vkd3d_free(assign);
+ return NULL;
+ }
+ assert(swizzle_type->type == HLSL_CLASS_VECTOR);
+ if (swizzle_type->dimx != width)
+ swizzle->node.data_type = hlsl_ctx.builtin_types.vector[swizzle_type->base_type][width - 1];
+ rhs = &swizzle->node;
+ }
+ else
+ {
+ hlsl_report_message(lhs->loc, HLSL_LEVEL_ERROR, "invalid lvalue");
+ vkd3d_free(assign);
+ return NULL;
+ }
+
+ lhs = lhs_inner;
+ }
+
+ init_node(&assign->node, HLSL_IR_ASSIGNMENT, lhs_type, lhs->loc);
+ assign->writemask = writemask;
+ assign->lhs.var = load_from_node(lhs)->src.var;
+ hlsl_src_from_node(&assign->lhs.offset, load_from_node(lhs)->src.offset.node);
+ if (assign_op != ASSIGN_OP_ASSIGN)
+ {
+ enum hlsl_ir_expr_op op = op_from_assignment(assign_op);
+ struct hlsl_ir_node *expr;
+
+ TRACE("Adding an expression for the compound assignment.\n");
+ expr = new_binary_expr(op, lhs, rhs);
+ list_add_after(&rhs->entry, &expr->entry);
+ rhs = expr;
+ }
+ hlsl_src_from_node(&assign->rhs, rhs);
+ list_add_tail(instrs, &assign->node.entry);
+
+ return &assign->node;
+}
+
+static int compare_hlsl_types_rb(const void *key, const struct rb_entry *entry)
+{
+ const struct hlsl_type *type = RB_ENTRY_VALUE(entry, const struct hlsl_type, scope_entry);
+ const char *name = key;
+
+ if (name == type->name)
+ return 0;
+
+ if (!name || !type->name)
+ {
+ ERR("hlsl_type without a name in a scope?\n");
+ return -1;
+ }
+ return strcmp(name, type->name);
+}
+
+void push_scope(struct hlsl_parse_ctx *ctx)
+{
+ struct hlsl_scope *new_scope;
+
+ if (!(new_scope = vkd3d_malloc(sizeof(*new_scope))))
+ return;
+ TRACE("Pushing a new scope.\n");
+ list_init(&new_scope->vars);
+ rb_init(&new_scope->types, compare_hlsl_types_rb);
+ new_scope->upper = ctx->cur_scope;
+ ctx->cur_scope = new_scope;
+ list_add_tail(&ctx->scopes, &new_scope->entry);
+}
+
+BOOL pop_scope(struct hlsl_parse_ctx *ctx)
+{
+ struct hlsl_scope *prev_scope = ctx->cur_scope->upper;
+
+ if (!prev_scope)
+ return FALSE;
+ TRACE("Popping current scope.\n");
+ ctx->cur_scope = prev_scope;
+ return TRUE;
+}
+
+static int compare_param_hlsl_types(const struct hlsl_type *t1, const struct hlsl_type *t2)
+{
+ if (t1->type != t2->type)
+ {
+ if (!((t1->type == HLSL_CLASS_SCALAR && t2->type == HLSL_CLASS_VECTOR)
+ || (t1->type == HLSL_CLASS_VECTOR && t2->type == HLSL_CLASS_SCALAR)))
+ return t1->type - t2->type;
+ }
+ if (t1->base_type != t2->base_type)
+ return t1->base_type - t2->base_type;
+ if (t1->base_type == HLSL_TYPE_SAMPLER && t1->sampler_dim != t2->sampler_dim)
+ return t1->sampler_dim - t2->sampler_dim;
+ if (t1->dimx != t2->dimx)
+ return t1->dimx - t2->dimx;
+ if (t1->dimy != t2->dimy)
+ return t1->dimx - t2->dimx;
+ if (t1->type == HLSL_CLASS_STRUCT)
+ {
+ struct list *t1cur, *t2cur;
+ struct hlsl_struct_field *t1field, *t2field;
+ int r;
+
+ t1cur = list_head(t1->e.elements);
+ t2cur = list_head(t2->e.elements);
+ while (t1cur && t2cur)
+ {
+ t1field = LIST_ENTRY(t1cur, struct hlsl_struct_field, entry);
+ t2field = LIST_ENTRY(t2cur, struct hlsl_struct_field, entry);
+ if ((r = compare_param_hlsl_types(t1field->type, t2field->type)))
+ return r;
+ if ((r = strcmp(t1field->name, t2field->name)))
+ return r;
+ t1cur = list_next(t1->e.elements, t1cur);
+ t2cur = list_next(t2->e.elements, t2cur);
+ }
+ if (t1cur != t2cur)
+ return t1cur ? 1 : -1;
+ return 0;
+ }
+ if (t1->type == HLSL_CLASS_ARRAY)
+ {
+ if (t1->e.array.elements_count != t2->e.array.elements_count)
+ return t1->e.array.elements_count - t2->e.array.elements_count;
+ return compare_param_hlsl_types(t1->e.array.type, t2->e.array.type);
+ }
+
+ return 0;
+}
+
+static int compare_function_decl_rb(const void *key, const struct rb_entry *entry)
+{
+ const struct list *params = key;
+ const struct hlsl_ir_function_decl *decl = RB_ENTRY_VALUE(entry, const struct hlsl_ir_function_decl, entry);
+ int decl_params_count = decl->parameters ? list_count(decl->parameters) : 0;
+ int params_count = params ? list_count(params) : 0;
+ struct list *p1cur, *p2cur;
+ int r;
+
+ if (params_count != decl_params_count)
+ return params_count - decl_params_count;
+
+ p1cur = params ? list_head(params) : NULL;
+ p2cur = decl->parameters ? list_head(decl->parameters) : NULL;
+ while (p1cur && p2cur)
+ {
+ struct hlsl_ir_var *p1, *p2;
+ p1 = LIST_ENTRY(p1cur, struct hlsl_ir_var, param_entry);
+ p2 = LIST_ENTRY(p2cur, struct hlsl_ir_var, param_entry);
+ if ((r = compare_param_hlsl_types(p1->data_type, p2->data_type)))
+ return r;
+ p1cur = list_next(params, p1cur);
+ p2cur = list_next(decl->parameters, p2cur);
+ }
+ return 0;
+}
+
+static int compare_function_rb(const void *key, const struct rb_entry *entry)
+{
+ const char *name = key;
+ const struct hlsl_ir_function *func = RB_ENTRY_VALUE(entry, const struct hlsl_ir_function,entry);
+
+ return strcmp(name, func->name);
+}
+
+void init_functions_tree(struct rb_tree *funcs)
+{
+ rb_init(&hlsl_ctx.functions, compare_function_rb);
+}
+
+const char *debug_base_type(const struct hlsl_type *type)
+{
+ const char *name = "(unknown)";
+
+ switch (type->base_type)
+ {
+ case HLSL_TYPE_FLOAT: name = "float"; break;
+ case HLSL_TYPE_HALF: name = "half"; break;
+ case HLSL_TYPE_DOUBLE: name = "double"; break;
+ case HLSL_TYPE_INT: name = "int"; break;
+ case HLSL_TYPE_UINT: name = "uint"; break;
+ case HLSL_TYPE_BOOL: name = "bool"; break;
+ case HLSL_TYPE_SAMPLER:
+ switch (type->sampler_dim)
+ {
+ case HLSL_SAMPLER_DIM_GENERIC: name = "sampler"; break;
+ case HLSL_SAMPLER_DIM_1D: name = "sampler1D"; break;
+ case HLSL_SAMPLER_DIM_2D: name = "sampler2D"; break;
+ case HLSL_SAMPLER_DIM_3D: name = "sampler3D"; break;
+ case HLSL_SAMPLER_DIM_CUBE: name = "samplerCUBE"; break;
+ }
+ break;
+ default:
+ FIXME("Unhandled case %u.\n", type->base_type);
+ }
+ return name;
+}
+
+const char *debug_hlsl_type(const struct hlsl_type *type)
+{
+ const char *name;
+
+ if (type->name)
+ return debugstr_a(type->name);
+
+ if (type->type == HLSL_CLASS_STRUCT)
+ return "<anonymous struct>";
+
+ if (type->type == HLSL_CLASS_ARRAY)
+ {
+ name = debug_base_type(type->e.array.type);
+ return vkd3d_dbg_sprintf("%s[%u]", name, type->e.array.elements_count);
+ }
+
+ name = debug_base_type(type);
+
+ if (type->type == HLSL_CLASS_SCALAR)
+ return vkd3d_dbg_sprintf("%s", name);
+ if (type->type == HLSL_CLASS_VECTOR)
+ return vkd3d_dbg_sprintf("%s%u", name, type->dimx);
+ if (type->type == HLSL_CLASS_MATRIX)
+ return vkd3d_dbg_sprintf("%s%ux%u", name, type->dimx, type->dimy);
+ return "unexpected_type";
+}
+
+const char *debug_modifiers(DWORD modifiers)
+{
+ char string[110];
+
+ string[0] = 0;
+ if (modifiers & HLSL_STORAGE_EXTERN)
+ strcat(string, " extern"); /* 7 */
+ if (modifiers & HLSL_STORAGE_NOINTERPOLATION)
+ strcat(string, " nointerpolation"); /* 16 */
+ if (modifiers & HLSL_MODIFIER_PRECISE)
+ strcat(string, " precise"); /* 8 */
+ if (modifiers & HLSL_STORAGE_SHARED)
+ strcat(string, " shared"); /* 7 */
+ if (modifiers & HLSL_STORAGE_GROUPSHARED)
+ strcat(string, " groupshared"); /* 12 */
+ if (modifiers & HLSL_STORAGE_STATIC)
+ strcat(string, " static"); /* 7 */
+ if (modifiers & HLSL_STORAGE_UNIFORM)
+ strcat(string, " uniform"); /* 8 */
+ if (modifiers & HLSL_STORAGE_VOLATILE)
+ strcat(string, " volatile"); /* 9 */
+ if (modifiers & HLSL_MODIFIER_CONST)
+ strcat(string, " const"); /* 6 */
+ if (modifiers & HLSL_MODIFIER_ROW_MAJOR)
+ strcat(string, " row_major"); /* 10 */
+ if (modifiers & HLSL_MODIFIER_COLUMN_MAJOR)
+ strcat(string, " column_major"); /* 13 */
+ if ((modifiers & (HLSL_STORAGE_IN | HLSL_STORAGE_OUT)) == (HLSL_STORAGE_IN | HLSL_STORAGE_OUT))
+ strcat(string, " inout"); /* 6 */
+ else if (modifiers & HLSL_STORAGE_IN)
+ strcat(string, " in"); /* 3 */
+ else if (modifiers & HLSL_STORAGE_OUT)
+ strcat(string, " out"); /* 4 */
+
+ return vkd3d_dbg_sprintf("%s", string[0] ? string + 1 : "");
+}
+
+const char *debug_node_type(enum hlsl_ir_node_type type)
+{
+ static const char * const names[] =
+ {
+ "HLSL_IR_ASSIGNMENT",
+ "HLSL_IR_CONSTANT",
+ "HLSL_IR_EXPR",
+ "HLSL_IR_IF",
+ "HLSL_IR_LOAD",
+ "HLSL_IR_LOOP",
+ "HLSL_IR_JUMP",
+ "HLSL_IR_SWIZZLE",
+ };
+
+ if (type >= ARRAY_SIZE(names))
+ return "Unexpected node type";
+ return names[type];
+}
+
+static void debug_dump_instr(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_node *instr);
+
+static void debug_dump_instr_list(struct vkd3d_string_buffer *buffer, const struct list *list)
+{
+ struct hlsl_ir_node *instr;
+
+ LIST_FOR_EACH_ENTRY(instr, list, struct hlsl_ir_node, entry)
+ {
+ debug_dump_instr(buffer, instr);
+ vkd3d_string_buffer_printf(buffer, "\n");
+ }
+}
+
+static void debug_dump_src(struct vkd3d_string_buffer *buffer, const struct hlsl_src *src)
+{
+ if (src->node->index)
+ vkd3d_string_buffer_printf(buffer, "@%u", src->node->index);
+ else
+ vkd3d_string_buffer_printf(buffer, "%p", src->node);
+}
+
+static void debug_dump_ir_var(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_var *var)
+{
+ if (var->modifiers)
+ vkd3d_string_buffer_printf(buffer, "%s ", debug_modifiers(var->modifiers));
+ vkd3d_string_buffer_printf(buffer, "%s %s", debug_hlsl_type(var->data_type), var->name);
+ if (var->semantic)
+ vkd3d_string_buffer_printf(buffer, " : %s", var->semantic);
+}
+
+static void debug_dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_deref *deref)
+{
+ if (deref->offset.node)
+ /* Print the variable's type for convenience. */
+ vkd3d_string_buffer_printf(buffer, "(%s %s)", debug_hlsl_type(deref->var->data_type), deref->var->name);
+ else
+ vkd3d_string_buffer_printf(buffer, "%s", deref->var->name);
+ if (deref->offset.node)
+ {
+ vkd3d_string_buffer_printf(buffer, "[");
+ debug_dump_src(buffer, &deref->offset);
+ vkd3d_string_buffer_printf(buffer, "]");
+ }
+}
+
+static const char *debug_writemask(DWORD writemask)
+{
+ static const char components[] = {'x', 'y', 'z', 'w'};
+ char string[5];
+ unsigned int i = 0, pos = 0;
+
+ assert(!(writemask & ~VKD3DSP_WRITEMASK_ALL));
+
+ while (writemask)
+ {
+ if (writemask & 1)
+ string[pos++] = components[i];
+ writemask >>= 1;
+ i++;
+ }
+ string[pos] = '\0';
+ return vkd3d_dbg_sprintf(".%s", string);
+}
+
+static void debug_dump_ir_assignment(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_assignment *assign)
+{
+ vkd3d_string_buffer_printf(buffer, "= (");
+ debug_dump_deref(buffer, &assign->lhs);
+ if (assign->writemask != VKD3DSP_WRITEMASK_ALL)
+ vkd3d_string_buffer_printf(buffer, "%s", debug_writemask(assign->writemask));
+ vkd3d_string_buffer_printf(buffer, " ");
+ debug_dump_src(buffer, &assign->rhs);
+ vkd3d_string_buffer_printf(buffer, ")");
+}
+
+static void debug_dump_ir_constant(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_constant *constant)
+{
+ struct hlsl_type *type = constant->node.data_type;
+ unsigned int x;
+
+ if (type->dimx != 1)
+ vkd3d_string_buffer_printf(buffer, "{");
+ for (x = 0; x < type->dimx; ++x)
+ {
+ switch (type->base_type)
+ {
+ case HLSL_TYPE_BOOL:
+ vkd3d_string_buffer_printf(buffer, "%s ", constant->value.b[x] ? "true" : "false");
+ break;
+
+ case HLSL_TYPE_DOUBLE:
+ vkd3d_string_buffer_printf(buffer, "%.16e ", constant->value.d[x]);
+ break;
+
+ case HLSL_TYPE_FLOAT:
+ vkd3d_string_buffer_printf(buffer, "%.8e ", constant->value.f[x]);
+ break;
+
+ case HLSL_TYPE_INT:
+ vkd3d_string_buffer_printf(buffer, "%d ", constant->value.i[x]);
+ break;
+
+ case HLSL_TYPE_UINT:
+ vkd3d_string_buffer_printf(buffer, "%u ", constant->value.u[x]);
+ break;
+
+ default:
+ vkd3d_string_buffer_printf(buffer, "Constants of type %s not supported\n", debug_base_type(type));
+ }
+ }
+ if (type->dimx != 1)
+ vkd3d_string_buffer_printf(buffer, "}");
+}
+
+static const char *debug_expr_op(const struct hlsl_ir_expr *expr)
+{
+ static const char * const op_names[] =
+ {
+ "~",
+ "!",
+ "-",
+ "abs",
+ "sign",
+ "rcp",
+ "rsq",
+ "sqrt",
+ "nrm",
+ "exp2",
+ "log2",
+
+ "cast",
+
+ "fract",
+
+ "sin",
+ "cos",
+ "sin_reduced",
+ "cos_reduced",
+
+ "dsx",
+ "dsy",
+
+ "sat",
+
+ "pre++",
+ "pre--",
+ "post++",
+ "post--",
+
+ "+",
+ "-",
+ "*",
+ "/",
+
+ "%",
+
+ "<",
+ ">",
+ "<=",
+ ">=",
+ "==",
+ "!=",
+
+ "&&",
+ "||",
+
+ "<<",
+ ">>",
+ "&",
+ "|",
+ "^",
+
+ "dot",
+ "crs",
+ "min",
+ "max",
+
+ "pow",
+
+ "lerp",
+
+ ",",
+ };
+
+ if (expr->op == HLSL_IR_UNOP_CAST)
+ return debug_hlsl_type(expr->node.data_type);
+
+ return op_names[expr->op];
+}
+
+/* Dumps the expression in a prefix "operator (operands)" form */
+static void debug_dump_ir_expr(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_expr *expr)
+{
+ unsigned int i;
+
+ vkd3d_string_buffer_printf(buffer, "%s (", debug_expr_op(expr));
+ for (i = 0; i < 3 && expr->operands[i].node; ++i)
+ {
+ debug_dump_src(buffer, &expr->operands[i]);
+ vkd3d_string_buffer_printf(buffer, " ");
+ }
+ vkd3d_string_buffer_printf(buffer, ")");
+}
+
+static void debug_dump_ir_if(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_if *if_node)
+{
+ vkd3d_string_buffer_printf(buffer, "if (");
+ debug_dump_src(buffer, &if_node->condition);
+ vkd3d_string_buffer_printf(buffer, ")\n{\n");
+ debug_dump_instr_list(buffer, &if_node->then_instrs);
+ vkd3d_string_buffer_printf(buffer, "}\nelse\n{\n");
+ debug_dump_instr_list(buffer, &if_node->else_instrs);
+ vkd3d_string_buffer_printf(buffer, "}\n");
+}
+
+static void debug_dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_jump *jump)
+{
+ switch (jump->type)
+ {
+ case HLSL_IR_JUMP_BREAK:
+ vkd3d_string_buffer_printf(buffer, "break");
+ break;
+
+ case HLSL_IR_JUMP_CONTINUE:
+ vkd3d_string_buffer_printf(buffer, "continue");
+ break;
+
+ case HLSL_IR_JUMP_DISCARD:
+ vkd3d_string_buffer_printf(buffer, "discard");
+ break;
+
+ case HLSL_IR_JUMP_RETURN:
+ vkd3d_string_buffer_printf(buffer, "return");
+ break;
+ }
+}
+
+static void debug_dump_ir_loop(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_loop *loop)
+{
+ vkd3d_string_buffer_printf(buffer, "for (;;)\n{\n");
+ debug_dump_instr_list(buffer, &loop->body);
+ vkd3d_string_buffer_printf(buffer, "}\n");
+}
+
+static void debug_dump_ir_swizzle(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_swizzle *swizzle)
+{
+ unsigned int i;
+
+ debug_dump_src(buffer, &swizzle->val);
+ vkd3d_string_buffer_printf(buffer, ".");
+ if (swizzle->val.node->data_type->dimy > 1)
+ {
+ for (i = 0; i < swizzle->node.data_type->dimx; ++i)
+ vkd3d_string_buffer_printf(buffer, "_m%u%u", (swizzle->swizzle >> i * 8) & 0xf, (swizzle->swizzle >> (i * 8 + 4)) & 0xf);
+ }
+ else
+ {
+ static const char c[] = {'x', 'y', 'z', 'w'};
+
+ for (i = 0; i < swizzle->node.data_type->dimx; ++i)
+ vkd3d_string_buffer_printf(buffer, "%c", c[(swizzle->swizzle >> i * 2) & 0x3]);
+ }
+}
+
+static void debug_dump_instr(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_node *instr)
+{
+ if (instr->index)
+ vkd3d_string_buffer_printf(buffer, "%4u: ", instr->index);
+ else
+ vkd3d_string_buffer_printf(buffer, "%p: ", instr);
+
+ vkd3d_string_buffer_printf(buffer, "%10s | ", instr->data_type ? debug_hlsl_type(instr->data_type) : "");
+
+ switch (instr->type)
+ {
+ case HLSL_IR_ASSIGNMENT:
+ debug_dump_ir_assignment(buffer, assignment_from_node(instr));
+ break;
+
+ case HLSL_IR_CONSTANT:
+ debug_dump_ir_constant(buffer, constant_from_node(instr));
+ break;
+
+ case HLSL_IR_EXPR:
+ debug_dump_ir_expr(buffer, expr_from_node(instr));
+ break;
+
+ case HLSL_IR_IF:
+ debug_dump_ir_if(buffer, if_from_node(instr));
+ break;
+
+ case HLSL_IR_JUMP:
+ debug_dump_ir_jump(buffer, jump_from_node(instr));
+ break;
+
+ case HLSL_IR_LOAD:
+ debug_dump_deref(buffer, &load_from_node(instr)->src);
+ break;
+
+ case HLSL_IR_LOOP:
+ debug_dump_ir_loop(buffer, loop_from_node(instr));
+ break;
+
+ case HLSL_IR_SWIZZLE:
+ debug_dump_ir_swizzle(buffer, swizzle_from_node(instr));
+ break;
+
+ default:
+ vkd3d_string_buffer_printf(buffer, "<No dump function for %s>", debug_node_type(instr->type));
+ }
+}
+
+void debug_dump_ir_function_decl(const struct hlsl_ir_function_decl *func)
+{
+ struct vkd3d_string_buffer buffer;
+ struct hlsl_ir_var *param;
+
+ vkd3d_string_buffer_init(&buffer);
+ vkd3d_string_buffer_printf(&buffer, "Dumping function %s.\n", func->func->name);
+ vkd3d_string_buffer_printf(&buffer, "Function parameters:\n");
+ LIST_FOR_EACH_ENTRY(param, func->parameters, struct hlsl_ir_var, param_entry)
+ {
+ debug_dump_ir_var(&buffer, param);
+ vkd3d_string_buffer_printf(&buffer, "\n");
+ }
+ if (func->semantic)
+ vkd3d_string_buffer_printf(&buffer, "Function semantic: %s\n", func->semantic);
+ if (func->body)
+ debug_dump_instr_list(&buffer, func->body);
+
+ vkd3d_string_buffer_trace(&buffer);
+ vkd3d_string_buffer_cleanup(&buffer);
+}
+
+void free_hlsl_type(struct hlsl_type *type)
+{
+ struct hlsl_struct_field *field, *next_field;
+
+ vkd3d_free((void *)type->name);
+ if (type->type == HLSL_CLASS_STRUCT)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(field, next_field, type->e.elements, struct hlsl_struct_field, entry)
+ {
+ vkd3d_free((void *)field->name);
+ vkd3d_free((void *)field->semantic);
+ vkd3d_free(field);
+ }
+ }
+ vkd3d_free(type);
+}
+
+void free_instr_list(struct list *list)
+{
+ struct hlsl_ir_node *node, *next_node;
+
+ if (!list)
+ return;
+ /* Iterate in reverse, to avoid use-after-free when unlinking sources from
+ * the "uses" list. */
+ LIST_FOR_EACH_ENTRY_SAFE_REV(node, next_node, list, struct hlsl_ir_node, entry)
+ free_instr(node);
+ vkd3d_free(list);
+}
+
+static void free_ir_assignment(struct hlsl_ir_assignment *assignment)
+{
+ hlsl_src_remove(&assignment->rhs);
+ hlsl_src_remove(&assignment->lhs.offset);
+ vkd3d_free(assignment);
+}
+
+static void free_ir_constant(struct hlsl_ir_constant *constant)
+{
+ vkd3d_free(constant);
+}
+
+static void free_ir_expr(struct hlsl_ir_expr *expr)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(expr->operands); ++i)
+ hlsl_src_remove(&expr->operands[i]);
+ vkd3d_free(expr);
+}
+
+static void free_ir_if(struct hlsl_ir_if *if_node)
+{
+ struct hlsl_ir_node *node, *next_node;
+
+ LIST_FOR_EACH_ENTRY_SAFE(node, next_node, &if_node->then_instrs, struct hlsl_ir_node, entry)
+ free_instr(node);
+ LIST_FOR_EACH_ENTRY_SAFE(node, next_node, &if_node->else_instrs, struct hlsl_ir_node, entry)
+ free_instr(node);
+ hlsl_src_remove(&if_node->condition);
+ vkd3d_free(if_node);
+}
+
+static void free_ir_jump(struct hlsl_ir_jump *jump)
+{
+ vkd3d_free(jump);
+}
+
+static void free_ir_load(struct hlsl_ir_load *load)
+{
+ hlsl_src_remove(&load->src.offset);
+ vkd3d_free(load);
+}
+
+static void free_ir_loop(struct hlsl_ir_loop *loop)
+{
+ struct hlsl_ir_node *node, *next_node;
+
+ LIST_FOR_EACH_ENTRY_SAFE(node, next_node, &loop->body, struct hlsl_ir_node, entry)
+ free_instr(node);
+ vkd3d_free(loop);
+}
+
+static void free_ir_swizzle(struct hlsl_ir_swizzle *swizzle)
+{
+ hlsl_src_remove(&swizzle->val);
+ vkd3d_free(swizzle);
+}
+
+void free_instr(struct hlsl_ir_node *node)
+{
+ switch (node->type)
+ {
+ case HLSL_IR_ASSIGNMENT:
+ free_ir_assignment(assignment_from_node(node));
+ break;
+
+ case HLSL_IR_CONSTANT:
+ free_ir_constant(constant_from_node(node));
+ break;
+
+ case HLSL_IR_EXPR:
+ free_ir_expr(expr_from_node(node));
+ break;
+
+ case HLSL_IR_IF:
+ free_ir_if(if_from_node(node));
+ break;
+
+ case HLSL_IR_JUMP:
+ free_ir_jump(jump_from_node(node));
+ break;
+
+ case HLSL_IR_LOAD:
+ free_ir_load(load_from_node(node));
+ break;
+
+ case HLSL_IR_LOOP:
+ free_ir_loop(loop_from_node(node));
+ break;
+
+ case HLSL_IR_SWIZZLE:
+ free_ir_swizzle(swizzle_from_node(node));
+ break;
+
+ default:
+ FIXME("Unsupported node type %s.\n", debug_node_type(node->type));
+ }
+}
+
+static void free_function_decl(struct hlsl_ir_function_decl *decl)
+{
+ vkd3d_free((void *)decl->semantic);
+ vkd3d_free(decl->parameters);
+ free_instr_list(decl->body);
+ vkd3d_free(decl);
+}
+
+static void free_function_decl_rb(struct rb_entry *entry, void *context)
+{
+ free_function_decl(RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry));
+}
+
+static void free_function(struct hlsl_ir_function *func)
+{
+ rb_destroy(&func->overloads, free_function_decl_rb, NULL);
+ vkd3d_free((void *)func->name);
+ vkd3d_free(func);
+}
+
+void free_function_rb(struct rb_entry *entry, void *context)
+{
+ free_function(RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry));
+}
+
+void add_function_decl(struct rb_tree *funcs, char *name, struct hlsl_ir_function_decl *decl, BOOL intrinsic)
+{
+ struct hlsl_ir_function *func;
+ struct rb_entry *func_entry, *old_entry;
+
+ func_entry = rb_get(funcs, name);
+ if (func_entry)
+ {
+ func = RB_ENTRY_VALUE(func_entry, struct hlsl_ir_function, entry);
+ if (intrinsic != func->intrinsic)
+ {
+ if (intrinsic)
+ {
+ ERR("Redeclaring a user defined function as an intrinsic.\n");
+ return;
+ }
+ TRACE("Function %s redeclared as a user defined function.\n", debugstr_a(name));
+ func->intrinsic = intrinsic;
+ rb_destroy(&func->overloads, free_function_decl_rb, NULL);
+ rb_init(&func->overloads, compare_function_decl_rb);
+ }
+ decl->func = func;
+ if ((old_entry = rb_get(&func->overloads, decl->parameters)))
+ {
+ struct hlsl_ir_function_decl *old_decl =
+ RB_ENTRY_VALUE(old_entry, struct hlsl_ir_function_decl, entry);
+
+ if (!decl->body)
+ {
+ free_function_decl(decl);
+ vkd3d_free(name);
+ return;
+ }
+ rb_remove(&func->overloads, old_entry);
+ free_function_decl(old_decl);
+ }
+ rb_put(&func->overloads, decl->parameters, &decl->entry);
+ vkd3d_free(name);
+ return;
+ }
+ func = vkd3d_malloc(sizeof(*func));
+ func->name = name;
+ rb_init(&func->overloads, compare_function_decl_rb);
+ decl->func = func;
+ rb_put(&func->overloads, decl->parameters, &decl->entry);
+ func->intrinsic = intrinsic;
+ rb_put(funcs, func->name, &func->entry);
+}
+
+struct hlsl_profile_info
+{
+ const char *name;
+ enum vkd3d_shader_type type;
+ DWORD sm_major;
+ DWORD sm_minor;
+ DWORD level_major;
+ DWORD level_minor;
+ BOOL sw;
+};
+
+static const struct hlsl_profile_info *get_target_info(const char *target)
+{
+ unsigned int i;
+
+ static const struct hlsl_profile_info profiles[] =
+ {
+ {"cs_4_0", VKD3D_SHADER_TYPE_COMPUTE, 4, 0, 0, 0, FALSE},
+ {"cs_4_1", VKD3D_SHADER_TYPE_COMPUTE, 4, 1, 0, 0, FALSE},
+ {"cs_5_0", VKD3D_SHADER_TYPE_COMPUTE, 5, 0, 0, 0, FALSE},
+ {"ds_5_0", VKD3D_SHADER_TYPE_DOMAIN, 5, 0, 0, 0, FALSE},
+ {"fx_2_0", VKD3D_SHADER_TYPE_EFFECT, 2, 0, 0, 0, FALSE},
+ {"fx_4_0", VKD3D_SHADER_TYPE_EFFECT, 4, 0, 0, 0, FALSE},
+ {"fx_4_1", VKD3D_SHADER_TYPE_EFFECT, 4, 1, 0, 0, FALSE},
+ {"fx_5_0", VKD3D_SHADER_TYPE_EFFECT, 5, 0, 0, 0, FALSE},
+ {"gs_4_0", VKD3D_SHADER_TYPE_GEOMETRY, 4, 0, 0, 0, FALSE},
+ {"gs_4_1", VKD3D_SHADER_TYPE_GEOMETRY, 4, 1, 0, 0, FALSE},
+ {"gs_5_0", VKD3D_SHADER_TYPE_GEOMETRY, 5, 0, 0, 0, FALSE},
+ {"hs_5_0", VKD3D_SHADER_TYPE_HULL, 5, 0, 0, 0, FALSE},
+ {"ps.1.0", VKD3D_SHADER_TYPE_PIXEL, 1, 0, 0, 0, FALSE},
+ {"ps.1.1", VKD3D_SHADER_TYPE_PIXEL, 1, 1, 0, 0, FALSE},
+ {"ps.1.2", VKD3D_SHADER_TYPE_PIXEL, 1, 2, 0, 0, FALSE},
+ {"ps.1.3", VKD3D_SHADER_TYPE_PIXEL, 1, 3, 0, 0, FALSE},
+ {"ps.1.4", VKD3D_SHADER_TYPE_PIXEL, 1, 4, 0, 0, FALSE},
+ {"ps.2.0", VKD3D_SHADER_TYPE_PIXEL, 2, 0, 0, 0, FALSE},
+ {"ps.2.a", VKD3D_SHADER_TYPE_PIXEL, 2, 1, 0, 0, FALSE},
+ {"ps.2.b", VKD3D_SHADER_TYPE_PIXEL, 2, 2, 0, 0, FALSE},
+ {"ps.2.sw", VKD3D_SHADER_TYPE_PIXEL, 2, 0, 0, 0, TRUE},
+ {"ps.3.0", VKD3D_SHADER_TYPE_PIXEL, 3, 0, 0, 0, FALSE},
+ {"ps_1_0", VKD3D_SHADER_TYPE_PIXEL, 1, 0, 0, 0, FALSE},
+ {"ps_1_1", VKD3D_SHADER_TYPE_PIXEL, 1, 1, 0, 0, FALSE},
+ {"ps_1_2", VKD3D_SHADER_TYPE_PIXEL, 1, 2, 0, 0, FALSE},
+ {"ps_1_3", VKD3D_SHADER_TYPE_PIXEL, 1, 3, 0, 0, FALSE},
+ {"ps_1_4", VKD3D_SHADER_TYPE_PIXEL, 1, 4, 0, 0, FALSE},
+ {"ps_2_0", VKD3D_SHADER_TYPE_PIXEL, 2, 0, 0, 0, FALSE},
+ {"ps_2_a", VKD3D_SHADER_TYPE_PIXEL, 2, 1, 0, 0, FALSE},
+ {"ps_2_b", VKD3D_SHADER_TYPE_PIXEL, 2, 2, 0, 0, FALSE},
+ {"ps_2_sw", VKD3D_SHADER_TYPE_PIXEL, 2, 0, 0, 0, TRUE},
+ {"ps_3_0", VKD3D_SHADER_TYPE_PIXEL, 3, 0, 0, 0, FALSE},
+ {"ps_3_sw", VKD3D_SHADER_TYPE_PIXEL, 3, 0, 0, 0, TRUE},
+ {"ps_4_0", VKD3D_SHADER_TYPE_PIXEL, 4, 0, 0, 0, FALSE},
+ {"ps_4_0_level_9_0", VKD3D_SHADER_TYPE_PIXEL, 4, 0, 9, 0, FALSE},
+ {"ps_4_0_level_9_1", VKD3D_SHADER_TYPE_PIXEL, 4, 0, 9, 1, FALSE},
+ {"ps_4_0_level_9_3", VKD3D_SHADER_TYPE_PIXEL, 4, 0, 9, 3, FALSE},
+ {"ps_4_1", VKD3D_SHADER_TYPE_PIXEL, 4, 1, 0, 0, FALSE},
+ {"ps_5_0", VKD3D_SHADER_TYPE_PIXEL, 5, 0, 0, 0, FALSE},
+ {"tx_1_0", VKD3D_SHADER_TYPE_TEXTURE, 1, 0, 0, 0, FALSE},
+ {"vs.1.0", VKD3D_SHADER_TYPE_VERTEX, 1, 0, 0, 0, FALSE},
+ {"vs.1.1", VKD3D_SHADER_TYPE_VERTEX, 1, 1, 0, 0, FALSE},
+ {"vs.2.0", VKD3D_SHADER_TYPE_VERTEX, 2, 0, 0, 0, FALSE},
+ {"vs.2.a", VKD3D_SHADER_TYPE_VERTEX, 2, 1, 0, 0, FALSE},
+ {"vs.2.sw", VKD3D_SHADER_TYPE_VERTEX, 2, 0, 0, 0, TRUE},
+ {"vs.3.0", VKD3D_SHADER_TYPE_VERTEX, 3, 0, 0, 0, FALSE},
+ {"vs.3.sw", VKD3D_SHADER_TYPE_VERTEX, 3, 0, 0, 0, TRUE},
+ {"vs_1_0", VKD3D_SHADER_TYPE_VERTEX, 1, 0, 0, 0, FALSE},
+ {"vs_1_1", VKD3D_SHADER_TYPE_VERTEX, 1, 1, 0, 0, FALSE},
+ {"vs_2_0", VKD3D_SHADER_TYPE_VERTEX, 2, 0, 0, 0, FALSE},
+ {"vs_2_a", VKD3D_SHADER_TYPE_VERTEX, 2, 1, 0, 0, FALSE},
+ {"vs_2_sw", VKD3D_SHADER_TYPE_VERTEX, 2, 0, 0, 0, TRUE},
+ {"vs_3_0", VKD3D_SHADER_TYPE_VERTEX, 3, 0, 0, 0, FALSE},
+ {"vs_3_sw", VKD3D_SHADER_TYPE_VERTEX, 3, 0, 0, 0, TRUE},
+ {"vs_4_0", VKD3D_SHADER_TYPE_VERTEX, 4, 0, 0, 0, FALSE},
+ {"vs_4_0_level_9_0", VKD3D_SHADER_TYPE_VERTEX, 4, 0, 9, 0, FALSE},
+ {"vs_4_0_level_9_1", VKD3D_SHADER_TYPE_VERTEX, 4, 0, 9, 1, FALSE},
+ {"vs_4_0_level_9_3", VKD3D_SHADER_TYPE_VERTEX, 4, 0, 9, 3, FALSE},
+ {"vs_4_1", VKD3D_SHADER_TYPE_VERTEX, 4, 1, 0, 0, FALSE},
+ {"vs_5_0", VKD3D_SHADER_TYPE_VERTEX, 5, 0, 0, 0, FALSE},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(profiles); ++i)
+ {
+ if (!strcmp(target, profiles[i].name))
+ return &profiles[i];
+ }
+
+ return NULL;
+}
+
+int hlsl_compile_shader(const char *text, const struct vkd3d_shader_compile_info *compile_info,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context)
+{
+ const struct vkd3d_shader_hlsl_source_info *hlsl_source_info;
+ const struct hlsl_profile_info *profile;
+
+ if (!(hlsl_source_info = vkd3d_find_struct(compile_info->next, HLSL_SOURCE_INFO)))
+ {
+ ERR("No HLSL source info given.\n");
+ return VKD3D_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!(profile = get_target_info(hlsl_source_info->profile)))
+ {
+ FIXME("Unknown compilation target %s.\n", debugstr_a(hlsl_source_info->profile));
+ return VKD3D_ERROR_NOT_IMPLEMENTED;
+ }
+
+ vkd3d_shader_dump_shader(profile->type, &compile_info->source);
+
+ return hlsl_lexer_compile(text, profile->type, profile->sm_major, profile->sm_minor,
+ hlsl_source_info->entry_point ? hlsl_source_info->entry_point : "main", dxbc, message_context);
+}
diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
new file mode 100644
index 00000000..128de1d6
--- /dev/null
+++ b/libs/vkd3d-shader/hlsl.h
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2012 Matteo Bruni for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __VKD3D_SHADER_HLSL_H
+#define __VKD3D_SHADER_HLSL_H
+
+#include "vkd3d_shader_private.h"
+#include "rbtree.h"
+
+enum parse_status
+{
+ PARSE_SUCCESS = 0,
+ PARSE_WARN = 1,
+ PARSE_ERR = 2
+};
+
+/* The general IR structure is inspired by Mesa GLSL hir, even though the code
+ * ends up being quite different in practice. Anyway, here comes the relevant
+ * licensing information.
+ *
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#define HLSL_SWIZZLE_X (0u)
+#define HLSL_SWIZZLE_Y (1u)
+#define HLSL_SWIZZLE_Z (2u)
+#define HLSL_SWIZZLE_W (3u)
+
+#define HLSL_SWIZZLE(x, y, z, w) \
+ (((HLSL_SWIZZLE_ ## x) << 0) \
+ | ((HLSL_SWIZZLE_ ## y) << 2) \
+ | ((HLSL_SWIZZLE_ ## z) << 4) \
+ | ((HLSL_SWIZZLE_ ## w) << 6))
+
+enum hlsl_type_class
+{
+ HLSL_CLASS_SCALAR,
+ HLSL_CLASS_VECTOR,
+ HLSL_CLASS_MATRIX,
+ HLSL_CLASS_LAST_NUMERIC = HLSL_CLASS_MATRIX,
+ HLSL_CLASS_STRUCT,
+ HLSL_CLASS_ARRAY,
+ HLSL_CLASS_OBJECT,
+};
+
+enum hlsl_base_type
+{
+ HLSL_TYPE_FLOAT,
+ HLSL_TYPE_HALF,
+ HLSL_TYPE_DOUBLE,
+ HLSL_TYPE_INT,
+ HLSL_TYPE_UINT,
+ HLSL_TYPE_BOOL,
+ HLSL_TYPE_LAST_SCALAR = HLSL_TYPE_BOOL,
+ HLSL_TYPE_SAMPLER,
+ HLSL_TYPE_TEXTURE,
+ HLSL_TYPE_PIXELSHADER,
+ HLSL_TYPE_VERTEXSHADER,
+ HLSL_TYPE_STRING,
+ HLSL_TYPE_VOID,
+};
+
+enum hlsl_sampler_dim
+{
+ HLSL_SAMPLER_DIM_GENERIC,
+ HLSL_SAMPLER_DIM_1D,
+ HLSL_SAMPLER_DIM_2D,
+ HLSL_SAMPLER_DIM_3D,
+ HLSL_SAMPLER_DIM_CUBE,
+ HLSL_SAMPLER_DIM_MAX = HLSL_SAMPLER_DIM_CUBE
+};
+
+enum hlsl_matrix_majority
+{
+ HLSL_COLUMN_MAJOR,
+ HLSL_ROW_MAJOR
+};
+
+struct hlsl_type
+{
+ struct list entry;
+ struct rb_entry scope_entry;
+ enum hlsl_type_class type;
+ enum hlsl_base_type base_type;
+ enum hlsl_sampler_dim sampler_dim;
+ const char *name;
+ unsigned int modifiers;
+ unsigned int dimx;
+ unsigned int dimy;
+ unsigned int reg_size;
+ union
+ {
+ struct list *elements;
+ struct
+ {
+ struct hlsl_type *type;
+ unsigned int elements_count;
+ } array;
+ } e;
+};
+
+struct hlsl_struct_field
+{
+ struct list entry;
+ struct hlsl_type *type;
+ const char *name;
+ const char *semantic;
+ DWORD modifiers;
+ unsigned int reg_offset;
+};
+
+struct source_location
+{
+ const char *file;
+ unsigned int line;
+ unsigned int col;
+};
+
+enum hlsl_ir_node_type
+{
+ HLSL_IR_ASSIGNMENT = 0,
+ HLSL_IR_CONSTANT,
+ HLSL_IR_EXPR,
+ HLSL_IR_IF,
+ HLSL_IR_LOAD,
+ HLSL_IR_LOOP,
+ HLSL_IR_JUMP,
+ HLSL_IR_SWIZZLE,
+};
+
+struct hlsl_ir_node
+{
+ struct list entry;
+ enum hlsl_ir_node_type type;
+ struct hlsl_type *data_type;
+
+ struct list uses;
+
+ struct source_location loc;
+
+ /* Liveness ranges. "index" is the index of this instruction. Since this is
+ * essentially an SSA value, the earliest live point is the index. This is
+ * true even for loops, since currently we can't have a reference to a
+ * value generated in an earlier iteration of the loop. */
+ unsigned int index, last_read;
+};
+
+struct hlsl_src
+{
+ struct hlsl_ir_node *node;
+ struct list entry;
+};
+
+#define HLSL_STORAGE_EXTERN 0x00000001
+#define HLSL_STORAGE_NOINTERPOLATION 0x00000002
+#define HLSL_MODIFIER_PRECISE 0x00000004
+#define HLSL_STORAGE_SHARED 0x00000008
+#define HLSL_STORAGE_GROUPSHARED 0x00000010
+#define HLSL_STORAGE_STATIC 0x00000020
+#define HLSL_STORAGE_UNIFORM 0x00000040
+#define HLSL_STORAGE_VOLATILE 0x00000080
+#define HLSL_MODIFIER_CONST 0x00000100
+#define HLSL_MODIFIER_ROW_MAJOR 0x00000200
+#define HLSL_MODIFIER_COLUMN_MAJOR 0x00000400
+#define HLSL_STORAGE_IN 0x00000800
+#define HLSL_STORAGE_OUT 0x00001000
+
+#define HLSL_TYPE_MODIFIERS_MASK (HLSL_MODIFIER_PRECISE | HLSL_STORAGE_VOLATILE | \
+ HLSL_MODIFIER_CONST | HLSL_MODIFIER_ROW_MAJOR | \
+ HLSL_MODIFIER_COLUMN_MAJOR)
+
+#define HLSL_MODIFIERS_MAJORITY_MASK (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR)
+
+struct reg_reservation
+{
+ enum vkd3d_shader_register_type type;
+ DWORD regnum;
+};
+
+struct hlsl_ir_var
+{
+ struct hlsl_type *data_type;
+ struct source_location loc;
+ const char *name;
+ const char *semantic;
+ unsigned int modifiers;
+ const struct reg_reservation *reg_reservation;
+ struct list scope_entry, param_entry;
+
+ unsigned int first_write, last_read;
+};
+
+struct hlsl_ir_function
+{
+ struct rb_entry entry;
+ const char *name;
+ struct rb_tree overloads;
+ BOOL intrinsic;
+};
+
+struct hlsl_ir_function_decl
+{
+ struct hlsl_type *return_type;
+ struct hlsl_ir_var *return_var;
+ struct source_location loc;
+ struct rb_entry entry;
+ struct hlsl_ir_function *func;
+ const char *semantic;
+ struct list *parameters;
+ struct list *body;
+};
+
+struct hlsl_ir_if
+{
+ struct hlsl_ir_node node;
+ struct hlsl_src condition;
+ struct list then_instrs;
+ struct list else_instrs;
+};
+
+struct hlsl_ir_loop
+{
+ struct hlsl_ir_node node;
+ /* loop condition is stored in the body (as "if (!condition) break;") */
+ struct list body;
+ unsigned int next_index; /* liveness index of the end of the loop */
+};
+
+enum hlsl_ir_expr_op
+{
+ HLSL_IR_UNOP_BIT_NOT = 0,
+ HLSL_IR_UNOP_LOGIC_NOT,
+ HLSL_IR_UNOP_NEG,
+ HLSL_IR_UNOP_ABS,
+ HLSL_IR_UNOP_SIGN,
+ HLSL_IR_UNOP_RCP,
+ HLSL_IR_UNOP_RSQ,
+ HLSL_IR_UNOP_SQRT,
+ HLSL_IR_UNOP_NRM,
+ HLSL_IR_UNOP_EXP2,
+ HLSL_IR_UNOP_LOG2,
+
+ HLSL_IR_UNOP_CAST,
+
+ HLSL_IR_UNOP_FRACT,
+
+ HLSL_IR_UNOP_SIN,
+ HLSL_IR_UNOP_COS,
+ HLSL_IR_UNOP_SIN_REDUCED, /* Reduced range [-pi, pi] */
+ HLSL_IR_UNOP_COS_REDUCED, /* Reduced range [-pi, pi] */
+
+ HLSL_IR_UNOP_DSX,
+ HLSL_IR_UNOP_DSY,
+
+ HLSL_IR_UNOP_SAT,
+
+ HLSL_IR_UNOP_PREINC,
+ HLSL_IR_UNOP_PREDEC,
+ HLSL_IR_UNOP_POSTINC,
+ HLSL_IR_UNOP_POSTDEC,
+
+ HLSL_IR_BINOP_ADD,
+ HLSL_IR_BINOP_SUB,
+ HLSL_IR_BINOP_MUL,
+ HLSL_IR_BINOP_DIV,
+
+ HLSL_IR_BINOP_MOD,
+
+ HLSL_IR_BINOP_LESS,
+ HLSL_IR_BINOP_GREATER,
+ HLSL_IR_BINOP_LEQUAL,
+ HLSL_IR_BINOP_GEQUAL,
+ HLSL_IR_BINOP_EQUAL,
+ HLSL_IR_BINOP_NEQUAL,
+
+ HLSL_IR_BINOP_LOGIC_AND,
+ HLSL_IR_BINOP_LOGIC_OR,
+
+ HLSL_IR_BINOP_LSHIFT,
+ HLSL_IR_BINOP_RSHIFT,
+ HLSL_IR_BINOP_BIT_AND,
+ HLSL_IR_BINOP_BIT_OR,
+ HLSL_IR_BINOP_BIT_XOR,
+
+ HLSL_IR_BINOP_DOT,
+ HLSL_IR_BINOP_CRS,
+ HLSL_IR_BINOP_MIN,
+ HLSL_IR_BINOP_MAX,
+
+ HLSL_IR_BINOP_POW,
+
+ HLSL_IR_TEROP_LERP,
+
+ HLSL_IR_SEQUENCE,
+};
+
+struct hlsl_ir_expr
+{
+ struct hlsl_ir_node node;
+ enum hlsl_ir_expr_op op;
+ struct hlsl_src operands[3];
+};
+
+enum hlsl_ir_jump_type
+{
+ HLSL_IR_JUMP_BREAK,
+ HLSL_IR_JUMP_CONTINUE,
+ HLSL_IR_JUMP_DISCARD,
+ HLSL_IR_JUMP_RETURN,
+};
+
+struct hlsl_ir_jump
+{
+ struct hlsl_ir_node node;
+ enum hlsl_ir_jump_type type;
+};
+
+struct hlsl_ir_swizzle
+{
+ struct hlsl_ir_node node;
+ struct hlsl_src val;
+ DWORD swizzle;
+};
+
+struct hlsl_deref
+{
+ struct hlsl_ir_var *var;
+ struct hlsl_src offset;
+};
+
+struct hlsl_ir_load
+{
+ struct hlsl_ir_node node;
+ struct hlsl_deref src;
+};
+
+struct hlsl_ir_assignment
+{
+ struct hlsl_ir_node node;
+ struct hlsl_deref lhs;
+ struct hlsl_src rhs;
+ unsigned char writemask;
+};
+
+struct hlsl_ir_constant
+{
+ struct hlsl_ir_node node;
+ union
+ {
+ unsigned u[4];
+ int i[4];
+ float f[4];
+ double d[4];
+ BOOL b[4];
+ } value;
+};
+
+struct hlsl_scope
+{
+ struct list entry;
+ struct list vars;
+ struct rb_tree types;
+ struct hlsl_scope *upper;
+};
+
+/* Structures used only during parsing */
+struct parse_parameter
+{
+ struct hlsl_type *type;
+ const char *name;
+ const char *semantic;
+ const struct reg_reservation *reg_reservation;
+ unsigned int modifiers;
+};
+
+struct parse_colon_attribute
+{
+ const char *semantic;
+ struct reg_reservation *reg_reservation;
+};
+
+struct parse_initializer
+{
+ struct hlsl_ir_node **args;
+ unsigned int args_count;
+ struct list *instrs;
+};
+
+struct parse_variable_def
+{
+ struct list entry;
+ struct source_location loc;
+
+ char *name;
+ unsigned int array_size;
+ const char *semantic;
+ struct reg_reservation *reg_reservation;
+ struct parse_initializer initializer;
+};
+
+struct parse_function
+{
+ char *name;
+ struct hlsl_ir_function_decl *decl;
+};
+
+struct parse_if_body
+{
+ struct list *then_instrs;
+ struct list *else_instrs;
+};
+
+enum parse_unary_op
+{
+ UNARY_OP_PLUS,
+ UNARY_OP_MINUS,
+ UNARY_OP_LOGICNOT,
+ UNARY_OP_BITNOT,
+};
+
+enum parse_assign_op
+{
+ ASSIGN_OP_ASSIGN,
+ ASSIGN_OP_ADD,
+ ASSIGN_OP_SUB,
+ ASSIGN_OP_MUL,
+ ASSIGN_OP_DIV,
+ ASSIGN_OP_MOD,
+ ASSIGN_OP_LSHIFT,
+ ASSIGN_OP_RSHIFT,
+ ASSIGN_OP_AND,
+ ASSIGN_OP_OR,
+ ASSIGN_OP_XOR,
+};
+
+struct hlsl_parse_ctx
+{
+ const char **source_files;
+ unsigned int source_files_count;
+ const char *source_file;
+ unsigned int line_no;
+ unsigned int column;
+ enum parse_status status;
+ struct vkd3d_shader_message_context *message_context;
+
+ struct hlsl_scope *cur_scope;
+ struct hlsl_scope *globals;
+ struct list scopes;
+
+ struct list types;
+ struct rb_tree functions;
+ const struct hlsl_ir_function_decl *cur_function;
+
+ enum hlsl_matrix_majority matrix_majority;
+
+ struct
+ {
+ struct hlsl_type *scalar[HLSL_TYPE_LAST_SCALAR + 1];
+ struct hlsl_type *vector[HLSL_TYPE_LAST_SCALAR + 1][4];
+ struct hlsl_type *sampler[HLSL_SAMPLER_DIM_MAX + 1];
+ struct hlsl_type *Void;
+ } builtin_types;
+
+ struct list static_initializers;
+};
+
+extern struct hlsl_parse_ctx hlsl_ctx DECLSPEC_HIDDEN;
+
+enum hlsl_error_level
+{
+ HLSL_LEVEL_ERROR = 0,
+ HLSL_LEVEL_WARNING,
+ HLSL_LEVEL_NOTE,
+};
+
+void hlsl_message(const char *fmt, ...) VKD3D_PRINTF_FUNC(1,2) DECLSPEC_HIDDEN;
+void hlsl_report_message(const struct source_location loc,
+ enum hlsl_error_level level, const char *fmt, ...) VKD3D_PRINTF_FUNC(3,4) DECLSPEC_HIDDEN;
+
+static inline struct hlsl_ir_assignment *assignment_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_ASSIGNMENT);
+ return CONTAINING_RECORD(node, struct hlsl_ir_assignment, node);
+}
+
+static inline struct hlsl_ir_constant *constant_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_CONSTANT);
+ return CONTAINING_RECORD(node, struct hlsl_ir_constant, node);
+}
+
+static inline struct hlsl_ir_expr *expr_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_EXPR);
+ return CONTAINING_RECORD(node, struct hlsl_ir_expr, node);
+}
+
+static inline struct hlsl_ir_if *if_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_IF);
+ return CONTAINING_RECORD(node, struct hlsl_ir_if, node);
+}
+
+static inline struct hlsl_ir_jump *jump_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_JUMP);
+ return CONTAINING_RECORD(node, struct hlsl_ir_jump, node);
+}
+
+static inline struct hlsl_ir_load *load_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_LOAD);
+ return CONTAINING_RECORD(node, struct hlsl_ir_load, node);
+}
+
+static inline struct hlsl_ir_loop *loop_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_LOOP);
+ return CONTAINING_RECORD(node, struct hlsl_ir_loop, node);
+}
+
+static inline struct hlsl_ir_swizzle *swizzle_from_node(const struct hlsl_ir_node *node)
+{
+ assert(node->type == HLSL_IR_SWIZZLE);
+ return CONTAINING_RECORD(node, struct hlsl_ir_swizzle, node);
+}
+
+static inline void init_node(struct hlsl_ir_node *node, enum hlsl_ir_node_type type,
+ struct hlsl_type *data_type, struct source_location loc)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = type;
+ node->data_type = data_type;
+ node->loc = loc;
+ list_init(&node->uses);
+}
+
+static inline void hlsl_src_from_node(struct hlsl_src *src, struct hlsl_ir_node *node)
+{
+ src->node = node;
+ if (node)
+ list_add_tail(&node->uses, &src->entry);
+}
+
+static inline void hlsl_src_remove(struct hlsl_src *src)
+{
+ if (src->node)
+ list_remove(&src->entry);
+ src->node = NULL;
+}
+
+static inline void set_parse_status(enum parse_status *current, enum parse_status update)
+{
+ if (update == PARSE_ERR)
+ *current = PARSE_ERR;
+ else if (update == PARSE_WARN && *current == PARSE_SUCCESS)
+ *current = PARSE_WARN;
+}
+
+struct hlsl_ir_node *add_assignment(struct list *instrs, struct hlsl_ir_node *lhs,
+ enum parse_assign_op assign_op, struct hlsl_ir_node *rhs) DECLSPEC_HIDDEN;
+struct hlsl_ir_expr *add_expr(struct list *instrs, enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[3],
+ struct source_location *loc) DECLSPEC_HIDDEN;
+struct hlsl_ir_node *add_implicit_conversion(struct list *instrs, struct hlsl_ir_node *node, struct hlsl_type *type,
+ struct source_location *loc) DECLSPEC_HIDDEN;
+
+struct hlsl_ir_expr *new_cast(struct hlsl_ir_node *node, struct hlsl_type *type,
+ struct source_location *loc) DECLSPEC_HIDDEN;
+struct hlsl_ir_node *new_binary_expr(enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1,
+ struct hlsl_ir_node *arg2) DECLSPEC_HIDDEN;
+struct hlsl_ir_node *new_unary_expr(enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg,
+ struct source_location loc) DECLSPEC_HIDDEN;
+
+BOOL add_declaration(struct hlsl_scope *scope, struct hlsl_ir_var *decl, BOOL local_var) DECLSPEC_HIDDEN;
+struct hlsl_ir_var *get_variable(struct hlsl_scope *scope, const char *name) DECLSPEC_HIDDEN;
+void free_declaration(struct hlsl_ir_var *decl) DECLSPEC_HIDDEN;
+struct hlsl_type *new_hlsl_type(const char *name, enum hlsl_type_class type_class,
+ enum hlsl_base_type base_type, unsigned dimx, unsigned dimy) DECLSPEC_HIDDEN;
+struct hlsl_type *new_array_type(struct hlsl_type *basic_type, unsigned int array_size) DECLSPEC_HIDDEN;
+struct hlsl_type *clone_hlsl_type(struct hlsl_type *old, unsigned int default_majority) DECLSPEC_HIDDEN;
+struct hlsl_type *get_type(struct hlsl_scope *scope, const char *name, BOOL recursive) DECLSPEC_HIDDEN;
+BOOL is_row_major(const struct hlsl_type *type) DECLSPEC_HIDDEN;
+BOOL find_function(const char *name) DECLSPEC_HIDDEN;
+unsigned int components_count_type(struct hlsl_type *type) DECLSPEC_HIDDEN;
+BOOL compare_hlsl_types(const struct hlsl_type *t1, const struct hlsl_type *t2) DECLSPEC_HIDDEN;
+BOOL compatible_data_types(struct hlsl_type *s1, struct hlsl_type *s2) DECLSPEC_HIDDEN;
+void push_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN;
+BOOL pop_scope(struct hlsl_parse_ctx *ctx) DECLSPEC_HIDDEN;
+void init_functions_tree(struct rb_tree *funcs) DECLSPEC_HIDDEN;
+void add_function_decl(struct rb_tree *funcs, char *name, struct hlsl_ir_function_decl *decl,
+ BOOL intrinsic) DECLSPEC_HIDDEN;
+
+int hlsl_lexer_compile(const char *text, enum vkd3d_shader_type type, DWORD major, DWORD minor, const char *entrypoint,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+int hlsl_parser_compile(enum vkd3d_shader_type type, DWORD major, DWORD minor, const char *entrypoint,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+
+const char *debug_base_type(const struct hlsl_type *type) DECLSPEC_HIDDEN;
+const char *debug_hlsl_type(const struct hlsl_type *type) DECLSPEC_HIDDEN;
+const char *debug_modifiers(DWORD modifiers) DECLSPEC_HIDDEN;
+const char *debug_node_type(enum hlsl_ir_node_type type) DECLSPEC_HIDDEN;
+void debug_dump_ir_function_decl(const struct hlsl_ir_function_decl *func) DECLSPEC_HIDDEN;
+
+void free_hlsl_type(struct hlsl_type *type) DECLSPEC_HIDDEN;
+void free_instr(struct hlsl_ir_node *node) DECLSPEC_HIDDEN;
+void free_instr_list(struct list *list) DECLSPEC_HIDDEN;
+void free_function_rb(struct rb_entry *entry, void *context) DECLSPEC_HIDDEN;
+
+#endif
diff --git a/libs/vkd3d-shader/hlsl.l b/libs/vkd3d-shader/hlsl.l
new file mode 100644
index 00000000..0bb1ee88
--- /dev/null
+++ b/libs/vkd3d-shader/hlsl.l
@@ -0,0 +1,288 @@
+/*
+ * HLSL parser
+ *
+ * Copyright 2008 Stefan Dösinger
+ * Copyright 2012 Matteo Bruni for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#define YY_NO_UNISTD_H
+#include "hlsl.h"
+#include "hlsl.tab.h"
+
+#define YY_USER_ACTION \
+ do { \
+ hlsl_lloc.first_column = hlsl_ctx.column; \
+ hlsl_lloc.first_line = hlsl_ctx.line_no; \
+ hlsl_ctx.column += yyleng; \
+ } while(0);
+
+%}
+
+%option prefix="hlsl_"
+%option never-interactive
+%option noinput
+%option nounput
+%option noyywrap
+
+%x pp pp_line pp_pragma pp_ignore
+
+RESERVED1 auto|case|catch|char|class|const_cast|default|delete|dynamic_cast|enum
+RESERVED2 explicit|friend|goto|long|mutable|new|operator|private|protected|public
+RESERVED3 reinterpret_cast|short|signed|sizeof|static_cast|template|this|throw|try
+RESERVED4 typename|union|unsigned|using|virtual
+
+WS [ \t]
+NEWLINE (\n)|(\r\n)
+DOUBLESLASHCOMMENT "//"[^\n]*
+STRING \"[^\"]*\"
+IDENTIFIER [A-Za-z_][A-Za-z0-9_]*
+
+ANY (.)
+
+%%
+{RESERVED1} {
+ hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ }
+{RESERVED2} {
+ hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ }
+{RESERVED3} {
+ hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ }
+{RESERVED4} {
+ hlsl_message("Line %u: Reserved keyword \"%s\" used.\n", hlsl_ctx.line_no, yytext);
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ }
+
+BlendState {return KW_BLENDSTATE; }
+break {return KW_BREAK; }
+Buffer {return KW_BUFFER; }
+cbuffer {return KW_CBUFFER; }
+compile {return KW_COMPILE; }
+const {return KW_CONST; }
+continue {return KW_CONTINUE; }
+DepthStencilState {return KW_DEPTHSTENCILSTATE; }
+DepthStencilView {return KW_DEPTHSTENCILVIEW; }
+discard {return KW_DISCARD; }
+do {return KW_DO; }
+double {return KW_DOUBLE; }
+else {return KW_ELSE; }
+extern {return KW_EXTERN; }
+false {return KW_FALSE; }
+for {return KW_FOR; }
+GeometryShader {return KW_GEOMETRYSHADER; }
+groupshared {return KW_GROUPSHARED; }
+if {return KW_IF; }
+in {return KW_IN; }
+inline {return KW_INLINE; }
+inout {return KW_INOUT; }
+matrix {return KW_MATRIX; }
+namespace {return KW_NAMESPACE; }
+nointerpolation {return KW_NOINTERPOLATION; }
+out {return KW_OUT; }
+pass {return KW_PASS; }
+PixelShader {return KW_PIXELSHADER; }
+precise {return KW_PRECISE; }
+RasterizerState {return KW_RASTERIZERSTATE; }
+RenderTargetView {return KW_RENDERTARGETVIEW; }
+return {return KW_RETURN; }
+register {return KW_REGISTER; }
+sampler {return KW_SAMPLER; }
+sampler1D {return KW_SAMPLER1D; }
+sampler2D {return KW_SAMPLER2D; }
+sampler3D {return KW_SAMPLER3D; }
+samplerCUBE {return KW_SAMPLERCUBE; }
+sampler_state {return KW_SAMPLER_STATE; }
+SamplerComparisonState {return KW_SAMPLERCOMPARISONSTATE;}
+shared {return KW_SHARED; }
+stateblock {return KW_STATEBLOCK; }
+stateblock_state {return KW_STATEBLOCK_STATE; }
+static {return KW_STATIC; }
+string {return KW_STRING; }
+struct {return KW_STRUCT; }
+switch {return KW_SWITCH; }
+tbuffer {return KW_TBUFFER; }
+technique {return KW_TECHNIQUE; }
+technique10 {return KW_TECHNIQUE10; }
+texture {return KW_TEXTURE; }
+texture1D {return KW_TEXTURE1D; }
+Texture1DArray {return KW_TEXTURE1DARRAY; }
+texture2D {return KW_TEXTURE2D; }
+Texture2DArray {return KW_TEXTURE2DARRAY; }
+Texture2DMS {return KW_TEXTURE2DMS; }
+Texture2DMSArray {return KW_TEXTURE2DMSARRAY; }
+texture3D {return KW_TEXTURE3D; }
+Texture3DArray {return KW_TEXTURE3DARRAY; }
+textureCUBE {return KW_TEXTURECUBE; }
+true {return KW_TRUE; }
+typedef {return KW_TYPEDEF; }
+uniform {return KW_UNIFORM; }
+vector {return KW_VECTOR; }
+VertexShader {return KW_VERTEXSHADER; }
+void {return KW_VOID; }
+volatile {return KW_VOLATILE; }
+while {return KW_WHILE; }
+
+\+\+ {return OP_INC; }
+\-\- {return OP_DEC; }
+&& {return OP_AND; }
+\|\| {return OP_OR; }
+== {return OP_EQ; }
+\<\< {return OP_LEFTSHIFT; }
+\<\<= {return OP_LEFTSHIFTASSIGN; }
+\>\> {return OP_RIGHTSHIFT; }
+\>\>= {return OP_RIGHTSHIFTASSIGN; }
+\.\.\. {return OP_ELLIPSIS; }
+\<= {return OP_LE; }
+\>= {return OP_GE; }
+!= {return OP_NE; }
+\+= {return OP_ADDASSIGN; }
+\-= {return OP_SUBASSIGN; }
+\*= {return OP_MULASSIGN; }
+\/= {return OP_DIVASSIGN; }
+%= {return OP_MODASSIGN; }
+&= {return OP_ANDASSIGN; }
+\|= {return OP_ORASSIGN; }
+^= {return OP_XORASSIGN; }
+## {return OP_UNKNOWN1; }
+#@ {return OP_UNKNOWN2; }
+:: {return OP_UNKNOWN3; }
+\-\> {return OP_UNKNOWN4; }
+
+column_major {return KW_COLUMN_MAJOR; }
+row_major {return KW_ROW_MAJOR; }
+
+{IDENTIFIER} {
+ hlsl_lval.name = vkd3d_strdup(yytext);
+ if (get_variable(hlsl_ctx.cur_scope, yytext)
+ || find_function(yytext))
+ return VAR_IDENTIFIER;
+ else if (get_type(hlsl_ctx.cur_scope, yytext, TRUE))
+ return TYPE_IDENTIFIER;
+ else
+ return NEW_IDENTIFIER;
+ }
+
+[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[h|H|f|F]? {
+ hlsl_lval.floatval = atof(yytext);
+ return C_FLOAT;
+ }
+[0-9]+\.([eE][+-]?[0-9]+)?[h|H|f|F]? {
+ hlsl_lval.floatval = atof(yytext);
+ return C_FLOAT;
+ }
+[0-9]+([eE][+-]?[0-9]+)?[h|H|f|F] {
+ hlsl_lval.floatval = atof(yytext);
+ return C_FLOAT;
+ }
+0x[0-9a-fA-F]+ {
+ sscanf(yytext, "0x%x", &hlsl_lval.intval);
+ return C_INTEGER;
+ }
+0[0-7]+ {
+ sscanf(yytext, "0%o", &hlsl_lval.intval);
+ return C_INTEGER;
+ }
+[0-9]+ {
+ hlsl_lval.intval = (atoi(yytext));
+ return C_INTEGER;
+ }
+
+{DOUBLESLASHCOMMENT} {}
+
+{WS}+ {}
+{NEWLINE} {
+ hlsl_ctx.line_no++;
+ hlsl_ctx.column = 1;
+ }
+
+^# {
+ BEGIN(pp);
+ }
+
+<pp>pragma{WS}+ {
+ TRACE("Got a #pragma.\n");
+ BEGIN(pp_pragma);
+ }
+<pp_pragma>pack_matrix{WS}*\({WS}*row_major{WS}*\) {
+ TRACE("#pragma setting row_major mode.\n");
+ hlsl_ctx.matrix_majority = HLSL_ROW_MAJOR;
+ BEGIN(pp_ignore);
+ }
+<pp_pragma>pack_matrix{WS}*\({WS}*column_major{WS}*\) {
+ TRACE("#pragma setting column_major mode.\n");
+ hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR;
+ BEGIN(pp_ignore);
+ }
+<pp_pragma>{NEWLINE} {
+ FIXME("Unsupported preprocessor #pragma directive at line %u.\n", hlsl_ctx.line_no);
+ BEGIN(INITIAL);
+ }
+<pp_pragma>{ANY} {}
+<pp>[0-9]+ {
+ TRACE("Preprocessor line info.\n");
+ BEGIN(pp_line);
+ hlsl_lval.intval = (atoi(yytext));
+ return PRE_LINE;
+ }
+<pp_line>{STRING} {
+ char *string = vkd3d_strdup(yytext + 1);
+
+ BEGIN(pp_ignore);
+ string[strlen(string) - 1] = 0;
+ hlsl_lval.name = string;
+ return STRING;
+ }
+<pp_line>{WS}+ {}
+<pp_line>{NEWLINE} {
+ FIXME("Malformed preprocessor line directive?\n");
+ BEGIN(INITIAL);
+ }
+<pp_ignore>{NEWLINE} {
+ BEGIN(INITIAL);
+ }
+<pp_ignore>{ANY} {}
+<pp>{NEWLINE} {
+ FIXME("Unexpected preprocessor directive.\n");
+ BEGIN(INITIAL);
+ }
+<pp>{ANY} {}
+
+{ANY} {
+ return yytext[0];
+ }
+
+%%
+
+int hlsl_lexer_compile(const char *text, enum vkd3d_shader_type type, DWORD major, DWORD minor, const char *entrypoint,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context)
+{
+ YY_BUFFER_STATE buffer;
+ int ret;
+
+ buffer = hlsl__scan_string(text);
+ hlsl__switch_to_buffer(buffer);
+
+ ret = hlsl_parser_compile(type, major, minor, entrypoint, dxbc, message_context);
+
+ hlsl__delete_buffer(buffer);
+ return ret;
+}
diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
new file mode 100644
index 00000000..4e2218c5
--- /dev/null
+++ b/libs/vkd3d-shader/hlsl.y
@@ -0,0 +1,2961 @@
+/*
+ * HLSL parser
+ *
+ * Copyright 2008 Stefan Dösinger
+ * Copyright 2012 Matteo Bruni for CodeWeavers
+ * Copyright 2019-2020 Zebediah Figura for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+%{
+#include "hlsl.h"
+#include <stdio.h>
+
+int hlsl_lex(void);
+
+struct hlsl_parse_ctx hlsl_ctx;
+
+struct YYLTYPE;
+static struct source_location get_location(const struct YYLTYPE *l);
+
+void hlsl_message(const char *fmt, ...)
+{
+ /* FIXME */
+}
+
+void hlsl_report_message(const struct source_location loc,
+ enum hlsl_error_level level, const char *fmt, ...)
+{
+ /* FIXME */
+
+ if (level == HLSL_LEVEL_ERROR)
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ else if (level == HLSL_LEVEL_WARNING)
+ set_parse_status(&hlsl_ctx.status, PARSE_WARN);
+}
+
+static void hlsl_error(const char *s)
+{
+ const struct source_location loc =
+ {
+ .file = hlsl_ctx.source_file,
+ .line = hlsl_ctx.line_no,
+ .col = hlsl_ctx.column,
+ };
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "%s", s);
+}
+
+static struct hlsl_ir_node *node_from_list(struct list *list)
+{
+ return LIST_ENTRY(list_tail(list), struct hlsl_ir_node, entry);
+}
+
+static void debug_dump_decl(struct hlsl_type *type, DWORD modifiers, const char *declname, unsigned int line_no)
+{
+ TRACE("Line %u: ", line_no);
+ if (modifiers)
+ TRACE("%s ", debug_modifiers(modifiers));
+ TRACE("%s %s;\n", debug_hlsl_type(type), declname);
+}
+
+static void check_invalid_matrix_modifiers(DWORD modifiers, struct source_location loc)
+{
+ if (modifiers & HLSL_MODIFIERS_MAJORITY_MASK)
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR,
+ "'row_major' or 'column_major' modifiers are only allowed for matrices.");
+}
+
+static BOOL type_is_single_reg(const struct hlsl_type *type)
+{
+ return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR;
+}
+
+static BOOL declare_variable(struct hlsl_ir_var *decl, BOOL local)
+{
+ BOOL ret;
+
+ TRACE("Declaring variable %s.\n", decl->name);
+ if (decl->data_type->type != HLSL_CLASS_MATRIX)
+ check_invalid_matrix_modifiers(decl->modifiers, decl->loc);
+
+ if (local)
+ {
+ DWORD invalid = decl->modifiers & (HLSL_STORAGE_EXTERN | HLSL_STORAGE_SHARED
+ | HLSL_STORAGE_GROUPSHARED | HLSL_STORAGE_UNIFORM);
+
+ if (invalid)
+ {
+ hlsl_report_message(decl->loc, HLSL_LEVEL_ERROR,
+ "modifier '%s' invalid for local variables", debug_modifiers(invalid));
+ }
+ if (decl->semantic)
+ {
+ hlsl_report_message(decl->loc, HLSL_LEVEL_ERROR,
+ "semantics are not allowed on local variables");
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (find_function(decl->name))
+ {
+ hlsl_report_message(decl->loc, HLSL_LEVEL_ERROR, "redefinition of '%s'", decl->name);
+ return FALSE;
+ }
+ }
+ ret = add_declaration(hlsl_ctx.cur_scope, decl, local);
+ if (!ret)
+ {
+ struct hlsl_ir_var *old = get_variable(hlsl_ctx.cur_scope, decl->name);
+
+ hlsl_report_message(decl->loc, HLSL_LEVEL_ERROR, "\"%s\" already declared", decl->name);
+ hlsl_report_message(old->loc, HLSL_LEVEL_NOTE, "\"%s\" was previously declared here", old->name);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static DWORD add_modifiers(DWORD modifiers, DWORD mod, const struct source_location loc)
+{
+ if (modifiers & mod)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "modifier '%s' already specified", debug_modifiers(mod));
+ return modifiers;
+ }
+ if ((mod & HLSL_MODIFIERS_MAJORITY_MASK) && (modifiers & HLSL_MODIFIERS_MAJORITY_MASK))
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "more than one matrix majority keyword");
+ return modifiers;
+ }
+ return modifiers | mod;
+}
+
+static BOOL add_type_to_scope(struct hlsl_scope *scope, struct hlsl_type *def)
+{
+ if (get_type(scope, def->name, FALSE))
+ return FALSE;
+
+ rb_put(&scope->types, def->name, &def->scope_entry);
+ return TRUE;
+}
+
+static void declare_predefined_types(struct hlsl_scope *scope)
+{
+ struct hlsl_type *type;
+ unsigned int x, y, bt;
+ static const char * const names[] =
+ {
+ "float",
+ "half",
+ "double",
+ "int",
+ "uint",
+ "bool",
+ };
+ char name[10];
+
+ static const char *const sampler_names[] =
+ {
+ "sampler",
+ "sampler1D",
+ "sampler2D",
+ "sampler3D",
+ "samplerCUBE"
+ };
+
+ for (bt = 0; bt <= HLSL_TYPE_LAST_SCALAR; ++bt)
+ {
+ for (y = 1; y <= 4; ++y)
+ {
+ for (x = 1; x <= 4; ++x)
+ {
+ sprintf(name, "%s%ux%u", names[bt], y, x);
+ type = new_hlsl_type(vkd3d_strdup(name), HLSL_CLASS_MATRIX, bt, x, y);
+ add_type_to_scope(scope, type);
+
+ if (y == 1)
+ {
+ sprintf(name, "%s%u", names[bt], x);
+ type = new_hlsl_type(vkd3d_strdup(name), HLSL_CLASS_VECTOR, bt, x, y);
+ add_type_to_scope(scope, type);
+ hlsl_ctx.builtin_types.vector[bt][x - 1] = type;
+
+ if (x == 1)
+ {
+ sprintf(name, "%s", names[bt]);
+ type = new_hlsl_type(vkd3d_strdup(name), HLSL_CLASS_SCALAR, bt, x, y);
+ add_type_to_scope(scope, type);
+ hlsl_ctx.builtin_types.scalar[bt] = type;
+ }
+ }
+ }
+ }
+ }
+
+ for (bt = 0; bt <= HLSL_SAMPLER_DIM_MAX; ++bt)
+ {
+ type = new_hlsl_type(vkd3d_strdup(sampler_names[bt]), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1);
+ type->sampler_dim = bt;
+ hlsl_ctx.builtin_types.sampler[bt] = type;
+ }
+
+ hlsl_ctx.builtin_types.Void = new_hlsl_type(vkd3d_strdup("void"), HLSL_CLASS_OBJECT, HLSL_TYPE_VOID, 1, 1);
+
+ /* DX8 effects predefined types */
+ type = new_hlsl_type(vkd3d_strdup("DWORD"), HLSL_CLASS_SCALAR, HLSL_TYPE_INT, 1, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("FLOAT"), HLSL_CLASS_SCALAR, HLSL_TYPE_FLOAT, 1, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("VECTOR"), HLSL_CLASS_VECTOR, HLSL_TYPE_FLOAT, 4, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("MATRIX"), HLSL_CLASS_MATRIX, HLSL_TYPE_FLOAT, 4, 4);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("STRING"), HLSL_CLASS_OBJECT, HLSL_TYPE_STRING, 1, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("TEXTURE"), HLSL_CLASS_OBJECT, HLSL_TYPE_TEXTURE, 1, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("PIXELSHADER"), HLSL_CLASS_OBJECT, HLSL_TYPE_PIXELSHADER, 1, 1);
+ add_type_to_scope(scope, type);
+ type = new_hlsl_type(vkd3d_strdup("VERTEXSHADER"), HLSL_CLASS_OBJECT, HLSL_TYPE_VERTEXSHADER, 1, 1);
+ add_type_to_scope(scope, type);
+}
+
+static BOOL type_is_void(const struct hlsl_type *type)
+{
+ return type->type == HLSL_CLASS_OBJECT && type->base_type == HLSL_TYPE_VOID;
+}
+
+static struct hlsl_ir_if *new_if(struct hlsl_ir_node *condition, struct source_location loc)
+{
+ struct hlsl_ir_if *iff;
+
+ if (!(iff = vkd3d_malloc(sizeof(*iff))))
+ return NULL;
+ init_node(&iff->node, HLSL_IR_IF, NULL, loc);
+ hlsl_src_from_node(&iff->condition, condition);
+ list_init(&iff->then_instrs);
+ list_init(&iff->else_instrs);
+ return iff;
+}
+
+static BOOL append_conditional_break(struct list *cond_list)
+{
+ struct hlsl_ir_node *condition, *not;
+ struct hlsl_ir_jump *jump;
+ struct hlsl_ir_if *iff;
+
+ /* E.g. "for (i = 0; ; ++i)". */
+ if (!list_count(cond_list))
+ return TRUE;
+
+ condition = node_from_list(cond_list);
+ if (!(not = new_unary_expr(HLSL_IR_UNOP_LOGIC_NOT, condition, condition->loc)))
+ return FALSE;
+ list_add_tail(cond_list, ¬->entry);
+
+ if (!(iff = new_if(not, condition->loc)))
+ return FALSE;
+ list_add_tail(cond_list, &iff->node.entry);
+
+ if (!(jump = vkd3d_malloc(sizeof(*jump))))
+ return FALSE;
+ init_node(&jump->node, HLSL_IR_JUMP, NULL, condition->loc);
+ jump->type = HLSL_IR_JUMP_BREAK;
+ list_add_head(&iff->then_instrs, &jump->node.entry);
+ return TRUE;
+}
+
+enum loop_type
+{
+ LOOP_FOR,
+ LOOP_WHILE,
+ LOOP_DO_WHILE
+};
+
+static struct list *create_loop(enum loop_type type, struct list *init, struct list *cond,
+ struct list *iter, struct list *body, struct source_location loc)
+{
+ struct list *list = NULL;
+ struct hlsl_ir_loop *loop = NULL;
+ struct hlsl_ir_if *cond_jump = NULL;
+
+ if (!(list = vkd3d_malloc(sizeof(*list))))
+ goto oom;
+ list_init(list);
+
+ if (init)
+ list_move_head(list, init);
+
+ if (!(loop = vkd3d_calloc(1, sizeof(*loop))))
+ goto oom;
+ init_node(&loop->node, HLSL_IR_LOOP, NULL, loc);
+ list_add_tail(list, &loop->node.entry);
+ list_init(&loop->body);
+
+ if (!append_conditional_break(cond))
+ goto oom;
+
+ if (type != LOOP_DO_WHILE)
+ list_move_tail(&loop->body, cond);
+
+ list_move_tail(&loop->body, body);
+
+ if (iter)
+ list_move_tail(&loop->body, iter);
+
+ if (type == LOOP_DO_WHILE)
+ list_move_tail(&loop->body, cond);
+
+ vkd3d_free(init);
+ vkd3d_free(cond);
+ vkd3d_free(body);
+ return list;
+
+oom:
+ vkd3d_free(loop);
+ vkd3d_free(cond_jump);
+ vkd3d_free(list);
+ free_instr_list(init);
+ free_instr_list(cond);
+ free_instr_list(iter);
+ free_instr_list(body);
+ return NULL;
+}
+
+static unsigned int initializer_size(const struct parse_initializer *initializer)
+{
+ unsigned int count = 0, i;
+
+ for (i = 0; i < initializer->args_count; ++i)
+ {
+ count += components_count_type(initializer->args[i]->data_type);
+ }
+ TRACE("Initializer size = %u.\n", count);
+ return count;
+}
+
+static void free_parse_initializer(struct parse_initializer *initializer)
+{
+ free_instr_list(initializer->instrs);
+ vkd3d_free(initializer->args);
+}
+
+static struct hlsl_ir_swizzle *new_swizzle(DWORD s, unsigned int components,
+ struct hlsl_ir_node *val, struct source_location *loc)
+{
+ struct hlsl_ir_swizzle *swizzle;
+
+ if (!(swizzle = vkd3d_malloc(sizeof(*swizzle))))
+ return NULL;
+ init_node(&swizzle->node, HLSL_IR_SWIZZLE,
+ new_hlsl_type(NULL, HLSL_CLASS_VECTOR, val->data_type->base_type, components, 1), *loc);
+ hlsl_src_from_node(&swizzle->val, val);
+ swizzle->swizzle = s;
+ return swizzle;
+}
+
+static struct hlsl_ir_swizzle *get_swizzle(struct hlsl_ir_node *value, const char *swizzle,
+ struct source_location *loc)
+{
+ unsigned int len = strlen(swizzle), component = 0;
+ unsigned int i, set, swiz = 0;
+ BOOL valid;
+
+ if (value->data_type->type == HLSL_CLASS_MATRIX)
+ {
+ /* Matrix swizzle */
+ BOOL m_swizzle;
+ unsigned int inc, x, y;
+
+ if (len < 3 || swizzle[0] != '_')
+ return NULL;
+ m_swizzle = swizzle[1] == 'm';
+ inc = m_swizzle ? 4 : 3;
+
+ if (len % inc || len > inc * 4)
+ return NULL;
+
+ for (i = 0; i < len; i += inc)
+ {
+ if (swizzle[i] != '_')
+ return NULL;
+ if (m_swizzle)
+ {
+ if (swizzle[i + 1] != 'm')
+ return NULL;
+ y = swizzle[i + 2] - '0';
+ x = swizzle[i + 3] - '0';
+ }
+ else
+ {
+ y = swizzle[i + 1] - '1';
+ x = swizzle[i + 2] - '1';
+ }
+
+ if (x >= value->data_type->dimx || y >= value->data_type->dimy)
+ return NULL;
+ swiz |= (y << 4 | x) << component * 8;
+ component++;
+ }
+ return new_swizzle(swiz, component, value, loc);
+ }
+
+ /* Vector swizzle */
+ if (len > 4)
+ return NULL;
+
+ for (set = 0; set < 2; ++set)
+ {
+ valid = TRUE;
+ component = 0;
+ for (i = 0; i < len; ++i)
+ {
+ char c[2][4] = {{'x', 'y', 'z', 'w'}, {'r', 'g', 'b', 'a'}};
+ unsigned int s = 0;
+
+ for (s = 0; s < 4; ++s)
+ {
+ if (swizzle[i] == c[set][s])
+ break;
+ }
+ if (s == 4)
+ {
+ valid = FALSE;
+ break;
+ }
+
+ if (s >= value->data_type->dimx)
+ return NULL;
+ swiz |= s << component * 2;
+ component++;
+ }
+ if (valid)
+ return new_swizzle(swiz, component, value, loc);
+ }
+
+ return NULL;
+}
+
+static struct hlsl_ir_var *new_var(const char *name, struct hlsl_type *type, const struct source_location loc,
+ const char *semantic, unsigned int modifiers, const struct reg_reservation *reg_reservation)
+{
+ struct hlsl_ir_var *var;
+
+ if (!(var = vkd3d_calloc(1, sizeof(*var))))
+ {
+ hlsl_ctx.status = PARSE_ERR;
+ return NULL;
+ }
+
+ var->name = name;
+ var->data_type = type;
+ var->loc = loc;
+ var->semantic = semantic;
+ var->modifiers = modifiers;
+ var->reg_reservation = reg_reservation;
+ return var;
+}
+
+static struct hlsl_ir_var *new_synthetic_var(const char *name, struct hlsl_type *type,
+ const struct source_location loc)
+{
+ struct hlsl_ir_var *var = new_var(vkd3d_strdup(name), type, loc, NULL, 0, NULL);
+
+ if (var)
+ list_add_tail(&hlsl_ctx.globals->vars, &var->scope_entry);
+ return var;
+}
+
+static struct hlsl_ir_assignment *new_assignment(struct hlsl_ir_var *var, struct hlsl_ir_node *offset,
+ struct hlsl_ir_node *rhs, unsigned int writemask, struct source_location loc)
+{
+ struct hlsl_ir_assignment *assign;
+
+ if (!writemask && type_is_single_reg(rhs->data_type))
+ writemask = (1 << rhs->data_type->dimx) - 1;
+
+ if (!(assign = vkd3d_malloc(sizeof(*assign))))
+ return NULL;
+
+ init_node(&assign->node, HLSL_IR_ASSIGNMENT, NULL, loc);
+ assign->lhs.var = var;
+ hlsl_src_from_node(&assign->lhs.offset, offset);
+ hlsl_src_from_node(&assign->rhs, rhs);
+ assign->writemask = writemask;
+ return assign;
+}
+
+static struct hlsl_ir_assignment *new_simple_assignment(struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs)
+{
+ return new_assignment(lhs, NULL, rhs, 0, rhs->loc);
+}
+
+static struct hlsl_ir_jump *add_return(struct list *instrs,
+ struct hlsl_ir_node *return_value, struct source_location loc)
+{
+ struct hlsl_type *return_type = hlsl_ctx.cur_function->return_type;
+ struct hlsl_ir_jump *jump;
+
+ if (return_value)
+ {
+ struct hlsl_ir_assignment *assignment;
+
+ if (!(return_value = add_implicit_conversion(instrs, return_value, return_type, &loc)))
+ return NULL;
+
+ if (!(assignment = new_simple_assignment(hlsl_ctx.cur_function->return_var, return_value)))
+ return NULL;
+ list_add_after(&return_value->entry, &assignment->node.entry);
+ }
+ else if (!type_is_void(return_type))
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "non-void function must return a value");
+ return NULL;
+ }
+
+ if (!(jump = vkd3d_malloc(sizeof(*jump))))
+ return NULL;
+ init_node(&jump->node, HLSL_IR_JUMP, NULL, loc);
+ jump->type = HLSL_IR_JUMP_RETURN;
+ list_add_tail(instrs, &jump->node.entry);
+
+ return jump;
+}
+
+static struct hlsl_ir_constant *new_uint_constant(unsigned int n, const struct source_location loc)
+{
+ struct hlsl_ir_constant *c;
+
+ if (!(c = vkd3d_malloc(sizeof(*c))))
+ return NULL;
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_ctx.builtin_types.scalar[HLSL_TYPE_UINT], loc);
+ c->value.u[0] = n;
+ return c;
+}
+
+struct hlsl_ir_node *new_unary_expr(enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, struct source_location loc)
+{
+ struct hlsl_ir_expr *expr;
+
+ if (!(expr = vkd3d_calloc(1, sizeof(*expr))))
+ return NULL;
+ init_node(&expr->node, HLSL_IR_EXPR, arg->data_type, loc);
+ expr->op = op;
+ hlsl_src_from_node(&expr->operands[0], arg);
+ return &expr->node;
+}
+
+struct hlsl_ir_node *new_binary_expr(enum hlsl_ir_expr_op op,
+ struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2)
+{
+ struct hlsl_ir_expr *expr;
+
+ assert(compare_hlsl_types(arg1->data_type, arg2->data_type));
+
+ if (!(expr = vkd3d_calloc(1, sizeof(*expr))))
+ return NULL;
+ init_node(&expr->node, HLSL_IR_EXPR, arg1->data_type, arg1->loc);
+ expr->op = op;
+ hlsl_src_from_node(&expr->operands[0], arg1);
+ hlsl_src_from_node(&expr->operands[1], arg2);
+ return &expr->node;
+}
+
+static struct hlsl_ir_load *new_var_load(struct hlsl_ir_var *var, const struct source_location loc)
+{
+ struct hlsl_ir_load *load;
+
+ if (!(load = vkd3d_calloc(1, sizeof(*load))))
+ return NULL;
+ init_node(&load->node, HLSL_IR_LOAD, var->data_type, loc);
+ load->src.var = var;
+ return load;
+}
+
+static struct hlsl_ir_load *add_load(struct list *instrs, struct hlsl_ir_node *var_node, struct hlsl_ir_node *offset,
+ struct hlsl_type *data_type, const struct source_location loc)
+{
+ struct hlsl_ir_node *add = NULL;
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+
+ if (var_node->type == HLSL_IR_LOAD)
+ {
+ const struct hlsl_deref *src = &load_from_node(var_node)->src;
+
+ var = src->var;
+ if (src->offset.node)
+ {
+ if (!(add = new_binary_expr(HLSL_IR_BINOP_ADD, src->offset.node, offset)))
+ return NULL;
+ list_add_tail(instrs, &add->entry);
+ offset = add;
+ }
+ }
+ else
+ {
+ struct hlsl_ir_assignment *assign;
+ char name[27];
+
+ sprintf(name, "<deref-%p>", var_node);
+ if (!(var = new_synthetic_var(name, var_node->data_type, var_node->loc)))
+ return NULL;
+
+ TRACE("Synthesized variable %p for %s node.\n", var, debug_node_type(var_node->type));
+
+ if (!(assign = new_simple_assignment(var, var_node)))
+ return NULL;
+
+ list_add_tail(instrs, &assign->node.entry);
+ }
+
+ if (!(load = vkd3d_malloc(sizeof(*load))))
+ return NULL;
+ init_node(&load->node, HLSL_IR_LOAD, data_type, loc);
+ load->src.var = var;
+ hlsl_src_from_node(&load->src.offset, offset);
+ list_add_tail(instrs, &load->node.entry);
+ return load;
+}
+
+static struct hlsl_ir_load *add_record_load(struct list *instrs, struct hlsl_ir_node *record,
+ const struct hlsl_struct_field *field, const struct source_location loc)
+{
+ struct hlsl_ir_constant *c;
+
+ if (!(c = new_uint_constant(field->reg_offset * 4, loc)))
+ return NULL;
+ list_add_tail(instrs, &c->node.entry);
+
+ return add_load(instrs, record, &c->node, field->type, loc);
+}
+
+static struct hlsl_ir_load *add_array_load(struct list *instrs, struct hlsl_ir_node *array,
+ struct hlsl_ir_node *index, const struct source_location loc)
+{
+ const struct hlsl_type *expr_type = array->data_type;
+ struct hlsl_type *data_type;
+ struct hlsl_ir_constant *c;
+ struct hlsl_ir_node *mul;
+
+ TRACE("Array load from type %s.\n", debug_hlsl_type(expr_type));
+
+ if (expr_type->type == HLSL_CLASS_ARRAY)
+ {
+ data_type = expr_type->e.array.type;
+ }
+ else if (expr_type->type == HLSL_CLASS_MATRIX || expr_type->type == HLSL_CLASS_VECTOR)
+ {
+ /* This needs to be lowered now, while we still have type information. */
+ FIXME("Index of matrix or vector type.\n");
+ return NULL;
+ }
+ else
+ {
+ if (expr_type->type == HLSL_CLASS_SCALAR)
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "array-indexed expression is scalar");
+ else
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "expression is not array-indexable");
+ return NULL;
+ }
+
+ if (!(c = new_uint_constant(data_type->reg_size * 4, loc)))
+ return NULL;
+ list_add_tail(instrs, &c->node.entry);
+ if (!(mul = new_binary_expr(HLSL_IR_BINOP_MUL, index, &c->node)))
+ return NULL;
+ list_add_tail(instrs, &mul->entry);
+ index = mul;
+
+ return add_load(instrs, array, index, data_type, loc);
+}
+
+static BOOL add_struct_field(struct list *fields, struct hlsl_struct_field *field)
+{
+ struct hlsl_struct_field *f;
+
+ LIST_FOR_EACH_ENTRY(f, fields, struct hlsl_struct_field, entry)
+ {
+ if (!strcmp(f->name, field->name))
+ return FALSE;
+ }
+ list_add_tail(fields, &field->entry);
+ return TRUE;
+}
+
+BOOL is_row_major(const struct hlsl_type *type)
+{
+ /* Default to column-major if the majority isn't explicitly set, which can
+ * happen for anonymous nodes. */
+ return !!(type->modifiers & HLSL_MODIFIER_ROW_MAJOR);
+}
+
+static struct hlsl_type *apply_type_modifiers(struct hlsl_type *type,
+ unsigned int *modifiers, struct source_location loc)
+{
+ unsigned int default_majority = 0;
+ struct hlsl_type *new_type;
+
+ /* This function is only used for declarations (i.e. variables and struct
+ * fields), which should inherit the matrix majority. We only explicitly set
+ * the default majority for declarations—typedefs depend on this—but we
+ * want to always set it, so that an hlsl_type object is never used to
+ * represent two different majorities (and thus can be used to store its
+ * register size, etc.) */
+ if (!(*modifiers & HLSL_MODIFIERS_MAJORITY_MASK)
+ && !(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK)
+ && type->type == HLSL_CLASS_MATRIX)
+ {
+ if (hlsl_ctx.matrix_majority == HLSL_COLUMN_MAJOR)
+ default_majority = HLSL_MODIFIER_COLUMN_MAJOR;
+ else
+ default_majority = HLSL_MODIFIER_ROW_MAJOR;
+ }
+
+ if (!default_majority && !(*modifiers & HLSL_TYPE_MODIFIERS_MASK))
+ return type;
+
+ if (!(new_type = clone_hlsl_type(type, default_majority)))
+ return NULL;
+
+ new_type->modifiers = add_modifiers(new_type->modifiers, *modifiers, loc);
+ *modifiers &= ~HLSL_TYPE_MODIFIERS_MASK;
+
+ if (new_type->type == HLSL_CLASS_MATRIX)
+ new_type->reg_size = is_row_major(new_type) ? new_type->dimy : new_type->dimx;
+ return new_type;
+}
+
+static struct list *gen_struct_fields(struct hlsl_type *type, DWORD modifiers, struct list *fields)
+{
+ struct parse_variable_def *v, *v_next;
+ struct hlsl_struct_field *field;
+ struct list *list;
+
+ if (type->type == HLSL_CLASS_MATRIX)
+ assert(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
+
+ if (!(list = vkd3d_malloc(sizeof(*list))))
+ return NULL;
+ list_init(list);
+ LIST_FOR_EACH_ENTRY_SAFE(v, v_next, fields, struct parse_variable_def, entry)
+ {
+ debug_dump_decl(type, 0, v->name, v->loc.line);
+ if (!(field = vkd3d_calloc(1, sizeof(*field))))
+ {
+ vkd3d_free(v);
+ return list;
+ }
+ if (v->array_size)
+ field->type = new_array_type(type, v->array_size);
+ else
+ field->type = type;
+ field->name = v->name;
+ field->modifiers = modifiers;
+ field->semantic = v->semantic;
+ if (v->initializer.args_count)
+ {
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR, "struct field with an initializer.\n");
+ free_parse_initializer(&v->initializer);
+ }
+ list_add_tail(list, &field->entry);
+ vkd3d_free(v);
+ }
+ vkd3d_free(fields);
+ return list;
+}
+
+static DWORD get_array_size(const struct hlsl_type *type)
+{
+ if (type->type == HLSL_CLASS_ARRAY)
+ return get_array_size(type->e.array.type) * type->e.array.elements_count;
+ return 1;
+}
+
+static struct hlsl_type *new_struct_type(const char *name, struct list *fields)
+{
+ struct hlsl_struct_field *field;
+ unsigned int reg_size = 0;
+ struct hlsl_type *type;
+
+ if (!(type = vkd3d_calloc(1, sizeof(*type))))
+ return NULL;
+ type->type = HLSL_CLASS_STRUCT;
+ type->base_type = HLSL_TYPE_VOID;
+ type->name = name;
+ type->dimx = 0;
+ type->dimy = 1;
+ type->e.elements = fields;
+
+ LIST_FOR_EACH_ENTRY(field, fields, struct hlsl_struct_field, entry)
+ {
+ field->reg_offset = reg_size;
+ reg_size += field->type->reg_size;
+ type->dimx += field->type->dimx * field->type->dimy * get_array_size(field->type);
+ }
+ type->reg_size = reg_size;
+
+ list_add_tail(&hlsl_ctx.types, &type->entry);
+
+ return type;
+}
+
+static BOOL add_typedef(DWORD modifiers, struct hlsl_type *orig_type, struct list *list)
+{
+ struct parse_variable_def *v, *v_next;
+ struct hlsl_type *type;
+ BOOL ret;
+
+ LIST_FOR_EACH_ENTRY_SAFE(v, v_next, list, struct parse_variable_def, entry)
+ {
+ if (v->array_size)
+ type = new_array_type(orig_type, v->array_size);
+ else
+ type = clone_hlsl_type(orig_type, 0);
+ if (!type)
+ return FALSE;
+ vkd3d_free((void *)type->name);
+ type->name = v->name;
+ type->modifiers |= modifiers;
+
+ if (type->type != HLSL_CLASS_MATRIX)
+ check_invalid_matrix_modifiers(type->modifiers, v->loc);
+ else
+ type->reg_size = is_row_major(type) ? type->dimy : type->dimx;
+
+ if ((type->modifiers & HLSL_MODIFIER_COLUMN_MAJOR)
+ && (type->modifiers & HLSL_MODIFIER_ROW_MAJOR))
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR, "more than one matrix majority keyword");
+
+ ret = add_type_to_scope(hlsl_ctx.cur_scope, type);
+ if (!ret)
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR,
+ "redefinition of custom type '%s'", v->name);
+ vkd3d_free(v);
+ }
+ vkd3d_free(list);
+ return TRUE;
+}
+
+static BOOL add_func_parameter(struct list *list, struct parse_parameter *param, const struct source_location loc)
+{
+ struct hlsl_ir_var *var;
+
+ if (param->type->type == HLSL_CLASS_MATRIX)
+ assert(param->type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
+
+ if (!(var = new_var(param->name, param->type, loc, param->semantic, param->modifiers, param->reg_reservation)))
+ return FALSE;
+
+ if (!add_declaration(hlsl_ctx.cur_scope, var, FALSE))
+ {
+ free_declaration(var);
+ return FALSE;
+ }
+ list_add_tail(list, &var->param_entry);
+ return TRUE;
+}
+
+static struct reg_reservation *parse_reg_reservation(const char *reg_string)
+{
+ enum vkd3d_shader_register_type type;
+ struct reg_reservation *reg_res;
+ DWORD regnum = 0;
+
+ switch (reg_string[0])
+ {
+ case 'c':
+ type = VKD3DSPR_CONST;
+ break;
+ case 'i':
+ type = VKD3DSPR_CONSTINT;
+ break;
+ case 'b':
+ type = VKD3DSPR_CONSTBOOL;
+ break;
+ case 's':
+ type = VKD3DSPR_SAMPLER;
+ break;
+ default:
+ FIXME("Unsupported register type.\n");
+ return NULL;
+ }
+
+ if (!sscanf(reg_string + 1, "%u", ®num))
+ {
+ FIXME("Unsupported register reservation syntax.\n");
+ return NULL;
+ }
+
+ if (!(reg_res = vkd3d_malloc(sizeof(*reg_res))))
+ return NULL;
+ reg_res->type = type;
+ reg_res->regnum = regnum;
+ return reg_res;
+}
+
+static const struct hlsl_ir_function_decl *get_overloaded_func(struct rb_tree *funcs, char *name,
+ struct list *params, BOOL exact_signature)
+{
+ struct hlsl_ir_function *func;
+ struct rb_entry *entry;
+
+ entry = rb_get(funcs, name);
+ if (entry)
+ {
+ func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
+
+ entry = rb_get(&func->overloads, params);
+ if (!entry)
+ {
+ if (!exact_signature)
+ FIXME("No exact match, search for a compatible overloaded function (if any).\n");
+ return NULL;
+ }
+ return RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
+ }
+ return NULL;
+}
+
+static struct hlsl_ir_function_decl *get_func_entry(const char *name)
+{
+ struct hlsl_ir_function_decl *decl;
+ struct hlsl_ir_function *func;
+ struct rb_entry *entry;
+
+ if ((entry = rb_get(&hlsl_ctx.functions, name)))
+ {
+ func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
+ RB_FOR_EACH_ENTRY(decl, &func->overloads, struct hlsl_ir_function_decl, entry)
+ return decl;
+ }
+
+ return NULL;
+}
+
+static struct list *make_list(struct hlsl_ir_node *node)
+{
+ struct list *list;
+
+ if (!(list = vkd3d_malloc(sizeof(*list))))
+ {
+ free_instr(node);
+ return NULL;
+ }
+ list_init(list);
+ list_add_tail(list, &node->entry);
+ return list;
+}
+
+static unsigned int evaluate_array_dimension(struct hlsl_ir_node *node)
+{
+ if (node->data_type->type != HLSL_CLASS_SCALAR)
+ return 0;
+
+ switch (node->type)
+ {
+ case HLSL_IR_CONSTANT:
+ {
+ struct hlsl_ir_constant *constant = constant_from_node(node);
+
+ switch (constant->node.data_type->base_type)
+ {
+ case HLSL_TYPE_UINT:
+ return constant->value.u[0];
+ case HLSL_TYPE_INT:
+ return constant->value.i[0];
+ case HLSL_TYPE_FLOAT:
+ return constant->value.f[0];
+ case HLSL_TYPE_DOUBLE:
+ return constant->value.d[0];
+ case HLSL_TYPE_BOOL:
+ return constant->value.b[0];
+ default:
+ WARN("Invalid type %s.\n", debug_base_type(constant->node.data_type));
+ return 0;
+ }
+ }
+
+ case HLSL_IR_EXPR:
+ case HLSL_IR_LOAD:
+ case HLSL_IR_SWIZZLE:
+ FIXME("Unhandled type %s.\n", debug_node_type(node->type));
+ return 0;
+
+ case HLSL_IR_ASSIGNMENT:
+ default:
+ WARN("Invalid node type %s.\n", debug_node_type(node->type));
+ return 0;
+ }
+}
+
+static struct list *append_unop(struct list *list, struct hlsl_ir_node *node)
+{
+ list_add_tail(list, &node->entry);
+ return list;
+}
+
+static struct list *add_binary_expr(struct list *list1, struct list *list2,
+ enum hlsl_ir_expr_op op, struct source_location loc)
+{
+ struct hlsl_ir_node *args[3] = {node_from_list(list1), node_from_list(list2)};
+
+ list_move_tail(list1, list2);
+ vkd3d_free(list2);
+ add_expr(list1, op, args, &loc);
+ return list1;
+}
+
+static void struct_var_initializer(struct list *list, struct hlsl_ir_var *var,
+ struct parse_initializer *initializer)
+{
+ struct hlsl_type *type = var->data_type;
+ struct hlsl_struct_field *field;
+ unsigned int i = 0;
+
+ if (initializer_size(initializer) != components_count_type(type))
+ {
+ hlsl_report_message(var->loc, HLSL_LEVEL_ERROR, "structure initializer mismatch");
+ free_parse_initializer(initializer);
+ return;
+ }
+
+ list_move_tail(list, initializer->instrs);
+ vkd3d_free(initializer->instrs);
+
+ LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry)
+ {
+ struct hlsl_ir_node *node = initializer->args[i];
+ struct hlsl_ir_assignment *assign;
+ struct hlsl_ir_constant *c;
+
+ if (i++ >= initializer->args_count)
+ break;
+
+ if (components_count_type(field->type) == components_count_type(node->data_type))
+ {
+ if (!(c = new_uint_constant(field->reg_offset * 4, node->loc)))
+ break;
+ list_add_tail(list, &c->node.entry);
+
+ if (!(assign = new_assignment(var, &c->node, node, 0, node->loc)))
+ break;
+ list_add_tail(list, &assign->node.entry);
+ }
+ else
+ FIXME("Initializing with \"mismatched\" fields is not supported yet.\n");
+ }
+
+ vkd3d_free(initializer->args);
+}
+
+static void free_parse_variable_def(struct parse_variable_def *v)
+{
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v->name);
+ vkd3d_free((void *)v->semantic);
+ vkd3d_free(v->reg_reservation);
+ vkd3d_free(v);
+}
+
+static struct list *declare_vars(struct hlsl_type *basic_type, DWORD modifiers, struct list *var_list)
+{
+ struct parse_variable_def *v, *v_next;
+ struct list *statements_list;
+ struct hlsl_ir_var *var;
+ struct hlsl_type *type;
+ BOOL ret, local = TRUE;
+
+ if (basic_type->type == HLSL_CLASS_MATRIX)
+ assert(basic_type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK);
+
+ if (!(statements_list = vkd3d_malloc(sizeof(*statements_list))))
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(v, v_next, var_list, struct parse_variable_def, entry)
+ free_parse_variable_def(v);
+ vkd3d_free(var_list);
+ return NULL;
+ }
+ list_init(statements_list);
+
+ if (!var_list)
+ return statements_list;
+
+ LIST_FOR_EACH_ENTRY_SAFE(v, v_next, var_list, struct parse_variable_def, entry)
+ {
+ if (v->array_size)
+ type = new_array_type(basic_type, v->array_size);
+ else
+ type = basic_type;
+
+ if (!(var = new_var(v->name, type, v->loc, v->semantic, modifiers, v->reg_reservation)))
+ {
+ free_parse_variable_def(v);
+ continue;
+ }
+ debug_dump_decl(type, modifiers, v->name, v->loc.line);
+
+ if (hlsl_ctx.cur_scope == hlsl_ctx.globals)
+ {
+ var->modifiers |= HLSL_STORAGE_UNIFORM;
+ local = FALSE;
+ }
+
+ if (type->modifiers & HLSL_MODIFIER_CONST && !(var->modifiers & HLSL_STORAGE_UNIFORM) && !v->initializer.args_count)
+ {
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR, "const variable without initializer");
+ free_declaration(var);
+ vkd3d_free(v);
+ continue;
+ }
+
+ ret = declare_variable(var, local);
+ if (!ret)
+ {
+ free_declaration(var);
+ vkd3d_free(v);
+ continue;
+ }
+ TRACE("Declared variable %s.\n", var->name);
+
+ if (v->initializer.args_count)
+ {
+ unsigned int size = initializer_size(&v->initializer);
+ struct hlsl_ir_load *load;
+
+ TRACE("Variable with initializer.\n");
+ if (type->type <= HLSL_CLASS_LAST_NUMERIC
+ && type->dimx * type->dimy != size && size != 1)
+ {
+ if (size < type->dimx * type->dimy)
+ {
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR,
+ "'%s' initializer does not match", v->name);
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+ }
+ if ((type->type == HLSL_CLASS_STRUCT || type->type == HLSL_CLASS_ARRAY)
+ && components_count_type(type) != size)
+ {
+ hlsl_report_message(v->loc, HLSL_LEVEL_ERROR,
+ "'%s' initializer does not match", v->name);
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+
+ if (type->type == HLSL_CLASS_STRUCT)
+ {
+ struct_var_initializer(statements_list, var, &v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+ if (type->type > HLSL_CLASS_LAST_NUMERIC)
+ {
+ FIXME("Initializers for non scalar/struct variables not supported yet.\n");
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+ if (v->array_size > 0)
+ {
+ FIXME("Initializing arrays is not supported yet.\n");
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+ if (v->initializer.args_count > 1)
+ {
+ FIXME("Complex initializers are not supported yet.\n");
+ free_parse_initializer(&v->initializer);
+ vkd3d_free(v);
+ continue;
+ }
+
+ load = new_var_load(var, var->loc);
+ list_add_tail(v->initializer.instrs, &load->node.entry);
+ add_assignment(v->initializer.instrs, &load->node, ASSIGN_OP_ASSIGN, v->initializer.args[0]);
+ vkd3d_free(v->initializer.args);
+
+ if (modifiers & HLSL_STORAGE_STATIC)
+ list_move_tail(&hlsl_ctx.static_initializers, v->initializer.instrs);
+ else
+ list_move_tail(statements_list, v->initializer.instrs);
+ vkd3d_free(v->initializer.instrs);
+ }
+ vkd3d_free(v);
+ }
+ vkd3d_free(var_list);
+ return statements_list;
+}
+
+static struct hlsl_ir_function_decl *new_func_decl(struct hlsl_type *return_type,
+ struct list *parameters, const char *semantic, struct source_location loc)
+{
+ struct hlsl_ir_function_decl *decl;
+
+ if (!(decl = vkd3d_calloc(1, sizeof(*decl))))
+ return NULL;
+ decl->return_type = return_type;
+ decl->parameters = parameters;
+ decl->semantic = semantic;
+ decl->loc = loc;
+
+ if (!type_is_void(return_type))
+ {
+ struct hlsl_ir_var *return_var;
+ char name[28];
+
+ sprintf(name, "<retval-%p>", decl);
+ if (!(return_var = new_synthetic_var(name, return_type, loc)))
+ {
+ vkd3d_free(decl);
+ return NULL;
+ }
+ decl->return_var = return_var;
+ }
+
+ return decl;
+}
+
+%}
+
+%locations
+%define parse.error verbose
+%define api.prefix {hlsl_}
+%expect 1
+
+%union
+{
+ struct hlsl_type *type;
+ INT intval;
+ FLOAT floatval;
+ BOOL boolval;
+ char *name;
+ DWORD modifiers;
+ struct hlsl_ir_node *instr;
+ struct list *list;
+ struct parse_function function;
+ struct parse_parameter parameter;
+ struct parse_initializer initializer;
+ struct parse_variable_def *variable_def;
+ struct parse_if_body if_body;
+ enum parse_unary_op unary_op;
+ enum parse_assign_op assign_op;
+ struct reg_reservation *reg_reservation;
+ struct parse_colon_attribute colon_attribute;
+}
+
+%token KW_BLENDSTATE
+%token KW_BREAK
+%token KW_BUFFER
+%token KW_CBUFFER
+%token KW_COLUMN_MAJOR
+%token KW_COMPILE
+%token KW_CONST
+%token KW_CONTINUE
+%token KW_DEPTHSTENCILSTATE
+%token KW_DEPTHSTENCILVIEW
+%token KW_DISCARD
+%token KW_DO
+%token KW_DOUBLE
+%token KW_ELSE
+%token KW_EXTERN
+%token KW_FALSE
+%token KW_FOR
+%token KW_GEOMETRYSHADER
+%token KW_GROUPSHARED
+%token KW_IF
+%token KW_IN
+%token KW_INLINE
+%token KW_INOUT
+%token KW_MATRIX
+%token KW_NAMESPACE
+%token KW_NOINTERPOLATION
+%token KW_OUT
+%token KW_PASS
+%token KW_PIXELSHADER
+%token KW_PRECISE
+%token KW_RASTERIZERSTATE
+%token KW_RENDERTARGETVIEW
+%token KW_RETURN
+%token KW_REGISTER
+%token KW_ROW_MAJOR
+%token KW_SAMPLER
+%token KW_SAMPLER1D
+%token KW_SAMPLER2D
+%token KW_SAMPLER3D
+%token KW_SAMPLERCUBE
+%token KW_SAMPLER_STATE
+%token KW_SAMPLERCOMPARISONSTATE
+%token KW_SHARED
+%token KW_STATEBLOCK
+%token KW_STATEBLOCK_STATE
+%token KW_STATIC
+%token KW_STRING
+%token KW_STRUCT
+%token KW_SWITCH
+%token KW_TBUFFER
+%token KW_TECHNIQUE
+%token KW_TECHNIQUE10
+%token KW_TEXTURE
+%token KW_TEXTURE1D
+%token KW_TEXTURE1DARRAY
+%token KW_TEXTURE2D
+%token KW_TEXTURE2DARRAY
+%token KW_TEXTURE2DMS
+%token KW_TEXTURE2DMSARRAY
+%token KW_TEXTURE3D
+%token KW_TEXTURE3DARRAY
+%token KW_TEXTURECUBE
+%token KW_TRUE
+%token KW_TYPEDEF
+%token KW_UNIFORM
+%token KW_VECTOR
+%token KW_VERTEXSHADER
+%token KW_VOID
+%token KW_VOLATILE
+%token KW_WHILE
+
+%token OP_INC
+%token OP_DEC
+%token OP_AND
+%token OP_OR
+%token OP_EQ
+%token OP_LEFTSHIFT
+%token OP_LEFTSHIFTASSIGN
+%token OP_RIGHTSHIFT
+%token OP_RIGHTSHIFTASSIGN
+%token OP_ELLIPSIS
+%token OP_LE
+%token OP_GE
+%token OP_NE
+%token OP_ADDASSIGN
+%token OP_SUBASSIGN
+%token OP_MULASSIGN
+%token OP_DIVASSIGN
+%token OP_MODASSIGN
+%token OP_ANDASSIGN
+%token OP_ORASSIGN
+%token OP_XORASSIGN
+%token OP_UNKNOWN1
+%token OP_UNKNOWN2
+%token OP_UNKNOWN3
+%token OP_UNKNOWN4
+
+%token <floatval> C_FLOAT
+
+%token <intval> C_INTEGER
+%token <intval> PRE_LINE
+
+%type <list> add_expr
+%type <list> assignment_expr
+%type <list> bitand_expr
+%type <list> bitor_expr
+%type <list> bitxor_expr
+%type <list> compound_statement
+%type <list> conditional_expr
+%type <list> declaration
+%type <list> declaration_statement
+%type <list> equality_expr
+%type <list> expr
+%type <list> expr_statement
+%type <list> field
+%type <list> fields_list
+%type <list> initializer_expr
+%type <list> jump_statement
+%type <list> logicand_expr
+%type <list> logicor_expr
+%type <list> loop_statement
+%type <list> mul_expr
+%type <list> param_list
+%type <list> parameters
+%type <list> postfix_expr
+%type <list> primary_expr
+%type <list> relational_expr
+%type <list> selection_statement
+%type <list> shift_expr
+%type <list> statement
+%type <list> statement_list
+%type <list> struct_declaration
+%type <list> type_specs
+%type <list> unary_expr
+%type <list> variables_def
+%type <list> variables_def_optional
+
+%token <name> VAR_IDENTIFIER
+%token <name> NEW_IDENTIFIER
+%token <name> STRING
+%token <name> TYPE_IDENTIFIER
+
+%type <assign_op> assign_op
+
+%type <boolval> boolean
+
+%type <colon_attribute> colon_attribute
+
+%type <function> func_declaration
+%type <function> func_prototype
+
+%type <initializer> complex_initializer
+%type <initializer> initializer_expr_list
+
+%type <if_body> if_body
+
+%type <intval> array
+
+%type <modifiers> input_mod
+%type <modifiers> input_mods
+%type <modifiers> var_modifiers
+
+%type <name> any_identifier
+%type <name> semantic
+%type <name> var_identifier
+
+%type <parameter> parameter
+
+%type <reg_reservation> register_opt
+
+%type <type> base_type
+%type <type> field_type
+%type <type> named_struct_spec
+%type <type> unnamed_struct_spec
+%type <type> struct_spec
+%type <type> type
+%type <type> typedef_type
+
+%type <unary_op> unary_op
+
+%type <variable_def> type_spec
+%type <variable_def> variable_def
+
+%%
+
+hlsl_prog:
+ /* empty */
+ | hlsl_prog func_declaration
+ {
+ const struct hlsl_ir_function_decl *decl;
+
+ decl = get_overloaded_func(&hlsl_ctx.functions, $2.name, $2.decl->parameters, TRUE);
+ if (decl && !decl->func->intrinsic)
+ {
+ if (decl->body && $2.decl->body)
+ {
+ hlsl_report_message($2.decl->loc, HLSL_LEVEL_ERROR,
+ "redefinition of function %s", debugstr_a($2.name));
+ YYABORT;
+ }
+ else if (!compare_hlsl_types(decl->return_type, $2.decl->return_type))
+ {
+ hlsl_report_message($2.decl->loc, HLSL_LEVEL_ERROR,
+ "redefining function %s with a different return type",
+ debugstr_a($2.name));
+ hlsl_report_message(decl->loc, HLSL_LEVEL_NOTE,
+ "%s previously declared here",
+ debugstr_a($2.name));
+ YYABORT;
+ }
+ }
+
+ if (type_is_void($2.decl->return_type) && $2.decl->semantic)
+ {
+ hlsl_report_message($2.decl->loc, HLSL_LEVEL_ERROR,
+ "void function with a semantic");
+ }
+
+ TRACE("Adding function '%s' to the function list.\n", $2.name);
+ add_function_decl(&hlsl_ctx.functions, $2.name, $2.decl, FALSE);
+ }
+ | hlsl_prog declaration_statement
+ {
+ TRACE("Declaration statement parsed.\n");
+
+ if (!list_empty($2))
+ FIXME("Uniform initializer.\n");
+ free_instr_list($2);
+ }
+ | hlsl_prog preproc_directive
+ | hlsl_prog ';'
+ {
+ TRACE("Skipping stray semicolon.\n");
+ }
+
+preproc_directive:
+ PRE_LINE STRING
+ {
+ const char **new_array = NULL;
+
+ TRACE("Updating line information to file %s, line %u.\n", debugstr_a($2), $1);
+ hlsl_ctx.line_no = $1;
+ if (strcmp($2, hlsl_ctx.source_file))
+ new_array = vkd3d_realloc(hlsl_ctx.source_files,
+ sizeof(*hlsl_ctx.source_files) * (hlsl_ctx.source_files_count + 1));
+
+ if (new_array)
+ {
+ hlsl_ctx.source_files = new_array;
+ hlsl_ctx.source_files[hlsl_ctx.source_files_count++] = $2;
+ hlsl_ctx.source_file = $2;
+ }
+ else
+ {
+ vkd3d_free($2);
+ }
+ }
+
+struct_declaration:
+ var_modifiers struct_spec variables_def_optional ';'
+ {
+ struct hlsl_type *type;
+ DWORD modifiers = $1;
+
+ if (!$3)
+ {
+ if (!$2->name)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR,
+ "anonymous struct declaration with no variables");
+ }
+ if (modifiers)
+ {
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR,
+ "modifier not allowed on struct type declaration");
+ }
+ }
+
+ if (!(type = apply_type_modifiers($2, &modifiers, get_location(&@1))))
+ YYABORT;
+ $$ = declare_vars(type, modifiers, $3);
+ }
+
+struct_spec:
+ named_struct_spec
+ | unnamed_struct_spec
+
+named_struct_spec:
+ KW_STRUCT any_identifier '{' fields_list '}'
+ {
+ BOOL ret;
+
+ TRACE("Structure %s declaration.\n", debugstr_a($2));
+ $$ = new_struct_type($2, $4);
+
+ if (get_variable(hlsl_ctx.cur_scope, $2))
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR, "redefinition of '%s'", $2);
+ YYABORT;
+ }
+
+ ret = add_type_to_scope(hlsl_ctx.cur_scope, $$);
+ if (!ret)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR, "redefinition of struct '%s'", $2);
+ YYABORT;
+ }
+ }
+
+unnamed_struct_spec:
+ KW_STRUCT '{' fields_list '}'
+ {
+ TRACE("Anonymous structure declaration.\n");
+ $$ = new_struct_type(NULL, $3);
+ }
+
+any_identifier:
+ VAR_IDENTIFIER
+ | TYPE_IDENTIFIER
+ | NEW_IDENTIFIER
+
+fields_list:
+ /* empty */
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ }
+ | fields_list field
+ {
+ BOOL ret;
+ struct hlsl_struct_field *field, *next;
+
+ $$ = $1;
+ LIST_FOR_EACH_ENTRY_SAFE(field, next, $2, struct hlsl_struct_field, entry)
+ {
+ ret = add_struct_field($$, field);
+ if (ret == FALSE)
+ {
+ hlsl_report_message(get_location(&@2),
+ HLSL_LEVEL_ERROR, "redefinition of '%s'", field->name);
+ vkd3d_free(field);
+ }
+ }
+ vkd3d_free($2);
+ }
+
+field_type:
+ type
+ | unnamed_struct_spec
+
+field:
+ var_modifiers field_type variables_def ';'
+ {
+ struct hlsl_type *type;
+ DWORD modifiers = $1;
+
+ if (!(type = apply_type_modifiers($2, &modifiers, get_location(&@1))))
+ YYABORT;
+ $$ = gen_struct_fields(type, modifiers, $3);
+ }
+
+func_declaration:
+ func_prototype compound_statement
+ {
+ TRACE("Function %s parsed.\n", $1.name);
+ $$ = $1;
+ $$.decl->body = $2;
+ pop_scope(&hlsl_ctx);
+ }
+ | func_prototype ';'
+ {
+ TRACE("Function prototype for %s.\n", $1.name);
+ $$ = $1;
+ pop_scope(&hlsl_ctx);
+ }
+
+func_prototype:
+ /* var_modifiers is necessary to avoid shift/reduce conflicts. */
+ var_modifiers type var_identifier '(' parameters ')' colon_attribute
+ {
+ if ($1)
+ {
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR,
+ "unexpected modifiers on a function");
+ YYABORT;
+ }
+ if (get_variable(hlsl_ctx.globals, $3))
+ {
+ hlsl_report_message(get_location(&@3), HLSL_LEVEL_ERROR, "redefinition of '%s'\n", $3);
+ YYABORT;
+ }
+ if (type_is_void($2) && $7.semantic)
+ {
+ hlsl_report_message(get_location(&@7), HLSL_LEVEL_ERROR, "void function with a semantic");
+ }
+
+ if ($7.reg_reservation)
+ {
+ FIXME("Unexpected register reservation for a function.\n");
+ vkd3d_free($7.reg_reservation);
+ }
+ if (!($$.decl = new_func_decl($2, $5, $7.semantic, get_location(&@3))))
+ YYABORT;
+ $$.name = $3;
+ hlsl_ctx.cur_function = $$.decl;
+ }
+
+compound_statement:
+ '{' '}'
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ }
+ | '{' scope_start statement_list '}'
+ {
+ pop_scope(&hlsl_ctx);
+ $$ = $3;
+ }
+
+scope_start:
+ /* empty */
+ {
+ push_scope(&hlsl_ctx);
+ }
+
+var_identifier:
+ VAR_IDENTIFIER
+ | NEW_IDENTIFIER
+
+colon_attribute:
+ /* empty */
+ {
+ $$.semantic = NULL;
+ $$.reg_reservation = NULL;
+ }
+ | semantic
+ {
+ $$.semantic = $1;
+ $$.reg_reservation = NULL;
+ }
+ | register_opt
+ {
+ $$.semantic = NULL;
+ $$.reg_reservation = $1;
+ }
+
+semantic:
+ ':' any_identifier
+ {
+ $$ = $2;
+ }
+
+/* FIXME: Writemasks */
+register_opt:
+ ':' KW_REGISTER '(' any_identifier ')'
+ {
+ $$ = parse_reg_reservation($4);
+ vkd3d_free($4);
+ }
+ | ':' KW_REGISTER '(' any_identifier ',' any_identifier ')'
+ {
+ FIXME("Ignoring shader target %s in a register reservation.\n", debugstr_a($4));
+ vkd3d_free($4);
+
+ $$ = parse_reg_reservation($6);
+ vkd3d_free($6);
+ }
+
+parameters:
+ scope_start
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ }
+ | scope_start param_list
+ {
+ $$ = $2;
+ }
+
+param_list:
+ parameter
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ if (!add_func_parameter($$, &$1, get_location(&@1)))
+ {
+ ERR("Error adding function parameter %s.\n", $1.name);
+ set_parse_status(&hlsl_ctx.status, PARSE_ERR);
+ YYABORT;
+ }
+ }
+ | param_list ',' parameter
+ {
+ $$ = $1;
+ if (!add_func_parameter($$, &$3, get_location(&@3)))
+ {
+ hlsl_report_message(get_location(&@3), HLSL_LEVEL_ERROR, "duplicate parameter %s", $3.name);
+ YYABORT;
+ }
+ }
+
+parameter:
+ input_mods var_modifiers type any_identifier colon_attribute
+ {
+ struct hlsl_type *type;
+ DWORD modifiers = $2;
+
+ if (!(type = apply_type_modifiers($3, &modifiers, get_location(&@2))))
+ YYABORT;
+
+ $$.modifiers = $1 ? $1 : HLSL_STORAGE_IN;
+ $$.modifiers |= modifiers;
+ $$.type = type;
+ $$.name = $4;
+ $$.semantic = $5.semantic;
+ $$.reg_reservation = $5.reg_reservation;
+ }
+
+input_mods:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | input_mods input_mod
+ {
+ if ($1 & $2)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR,
+ "duplicate input-output modifiers");
+ YYABORT;
+ }
+ $$ = $1 | $2;
+ }
+
+input_mod:
+ KW_IN
+ {
+ $$ = HLSL_STORAGE_IN;
+ }
+ | KW_OUT
+ {
+ $$ = HLSL_STORAGE_OUT;
+ }
+ | KW_INOUT
+ {
+ $$ = HLSL_STORAGE_IN | HLSL_STORAGE_OUT;
+ }
+
+type:
+ base_type
+ {
+ $$ = $1;
+ }
+ | KW_VECTOR '<' base_type ',' C_INTEGER '>'
+ {
+ if ($3->type != HLSL_CLASS_SCALAR)
+ {
+ hlsl_report_message(get_location(&@3), HLSL_LEVEL_ERROR,
+ "vectors of non-scalar types are not allowed\n");
+ YYABORT;
+ }
+ if ($5 < 1 || $5 > 4)
+ {
+ hlsl_report_message(get_location(&@5), HLSL_LEVEL_ERROR,
+ "vector size must be between 1 and 4\n");
+ YYABORT;
+ }
+
+ $$ = new_hlsl_type(NULL, HLSL_CLASS_VECTOR, $3->base_type, $5, 1);
+ }
+ | KW_MATRIX '<' base_type ',' C_INTEGER ',' C_INTEGER '>'
+ {
+ if ($3->type != HLSL_CLASS_SCALAR)
+ {
+ hlsl_report_message(get_location(&@3), HLSL_LEVEL_ERROR,
+ "matrices of non-scalar types are not allowed\n");
+ YYABORT;
+ }
+ if ($5 < 1 || $5 > 4)
+ {
+ hlsl_report_message(get_location(&@5), HLSL_LEVEL_ERROR,
+ "matrix row count must be between 1 and 4\n");
+ YYABORT;
+ }
+ if ($7 < 1 || $7 > 4)
+ {
+ hlsl_report_message(get_location(&@7), HLSL_LEVEL_ERROR,
+ "matrix column count must be between 1 and 4\n");
+ YYABORT;
+ }
+
+ $$ = new_hlsl_type(NULL, HLSL_CLASS_MATRIX, $3->base_type, $7, $5);
+ }
+
+base_type:
+ KW_VOID
+ {
+ $$ = hlsl_ctx.builtin_types.Void;
+ }
+ | KW_SAMPLER
+ {
+ $$ = hlsl_ctx.builtin_types.sampler[HLSL_SAMPLER_DIM_GENERIC];
+ }
+ | KW_SAMPLER1D
+ {
+ $$ = hlsl_ctx.builtin_types.sampler[HLSL_SAMPLER_DIM_1D];
+ }
+ | KW_SAMPLER2D
+ {
+ $$ = hlsl_ctx.builtin_types.sampler[HLSL_SAMPLER_DIM_2D];
+ }
+ | KW_SAMPLER3D
+ {
+ $$ = hlsl_ctx.builtin_types.sampler[HLSL_SAMPLER_DIM_3D];
+ }
+ | KW_SAMPLERCUBE
+ {
+ $$ = hlsl_ctx.builtin_types.sampler[HLSL_SAMPLER_DIM_3D];
+ }
+ | TYPE_IDENTIFIER
+ {
+ $$ = get_type(hlsl_ctx.cur_scope, $1, TRUE);
+ vkd3d_free($1);
+ }
+ | KW_STRUCT TYPE_IDENTIFIER
+ {
+ $$ = get_type(hlsl_ctx.cur_scope, $2, TRUE);
+ if ($$->type != HLSL_CLASS_STRUCT)
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR, "'%s' redefined as a structure\n", $2);
+ vkd3d_free($2);
+ }
+
+declaration_statement:
+ declaration
+ | struct_declaration
+ | typedef
+ {
+ if (!($$ = vkd3d_malloc(sizeof(*$$))))
+ YYABORT;
+ list_init($$);
+ }
+
+typedef_type:
+ type
+ | struct_spec
+
+typedef:
+ KW_TYPEDEF var_modifiers typedef_type type_specs ';'
+ {
+ if ($2 & ~HLSL_TYPE_MODIFIERS_MASK)
+ {
+ struct parse_variable_def *v, *v_next;
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR, "modifier not allowed on typedefs");
+ LIST_FOR_EACH_ENTRY_SAFE(v, v_next, $4, struct parse_variable_def, entry)
+ vkd3d_free(v);
+ vkd3d_free($4);
+ YYABORT;
+ }
+ if (!add_typedef($2, $3, $4))
+ YYABORT;
+ }
+
+type_specs:
+ type_spec
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ list_add_head($$, &$1->entry);
+ }
+ | type_specs ',' type_spec
+ {
+ $$ = $1;
+ list_add_tail($$, &$3->entry);
+ }
+
+type_spec:
+ any_identifier array
+ {
+ $$ = vkd3d_calloc(1, sizeof(*$$));
+ $$->loc = get_location(&@1);
+ $$->name = $1;
+ $$->array_size = $2;
+ }
+
+declaration:
+ var_modifiers type variables_def ';'
+ {
+ struct hlsl_type *type;
+ DWORD modifiers = $1;
+
+ if (!(type = apply_type_modifiers($2, &modifiers, get_location(&@1))))
+ YYABORT;
+ $$ = declare_vars(type, modifiers, $3);
+ }
+
+variables_def_optional:
+ /* empty */
+ {
+ $$ = NULL;
+ }
+ | variables_def
+
+variables_def:
+ variable_def
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ list_add_head($$, &$1->entry);
+ }
+ | variables_def ',' variable_def
+ {
+ $$ = $1;
+ list_add_tail($$, &$3->entry);
+ }
+
+variable_def:
+ any_identifier array colon_attribute
+ {
+ $$ = vkd3d_calloc(1, sizeof(*$$));
+ $$->loc = get_location(&@1);
+ $$->name = $1;
+ $$->array_size = $2;
+ $$->semantic = $3.semantic;
+ $$->reg_reservation = $3.reg_reservation;
+ }
+ | any_identifier array colon_attribute '=' complex_initializer
+ {
+ TRACE("Declaration with initializer.\n");
+ $$ = vkd3d_calloc(1, sizeof(*$$));
+ $$->loc = get_location(&@1);
+ $$->name = $1;
+ $$->array_size = $2;
+ $$->semantic = $3.semantic;
+ $$->reg_reservation = $3.reg_reservation;
+ $$->initializer = $5;
+ }
+
+array:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | '[' expr ']'
+ {
+ unsigned int size = evaluate_array_dimension(node_from_list($2));
+
+ free_instr_list($2);
+
+ if (!size)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR,
+ "array size is not a positive integer constant\n");
+ YYABORT;
+ }
+ TRACE("Array size %u.\n", size);
+
+ if (size > 65536)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR,
+ "array size must be between 1 and 65536");
+ YYABORT;
+ }
+ $$ = size;
+ }
+
+var_modifiers:
+ /* empty */
+ {
+ $$ = 0;
+ }
+ | KW_EXTERN var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_EXTERN, get_location(&@1));
+ }
+ | KW_NOINTERPOLATION var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_NOINTERPOLATION, get_location(&@1));
+ }
+ | KW_PRECISE var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_MODIFIER_PRECISE, get_location(&@1));
+ }
+ | KW_SHARED var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_SHARED, get_location(&@1));
+ }
+ | KW_GROUPSHARED var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_GROUPSHARED, get_location(&@1));
+ }
+ | KW_STATIC var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_STATIC, get_location(&@1));
+ }
+ | KW_UNIFORM var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_UNIFORM, get_location(&@1));
+ }
+ | KW_VOLATILE var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_STORAGE_VOLATILE, get_location(&@1));
+ }
+ | KW_CONST var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_MODIFIER_CONST, get_location(&@1));
+ }
+ | KW_ROW_MAJOR var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_MODIFIER_ROW_MAJOR, get_location(&@1));
+ }
+ | KW_COLUMN_MAJOR var_modifiers
+ {
+ $$ = add_modifiers($2, HLSL_MODIFIER_COLUMN_MAJOR, get_location(&@1));
+ }
+
+complex_initializer:
+ initializer_expr
+ {
+ $$.args_count = 1;
+ if (!($$.args = vkd3d_malloc(sizeof(*$$.args))))
+ YYABORT;
+ $$.args[0] = node_from_list($1);
+ $$.instrs = $1;
+ }
+ | '{' initializer_expr_list '}'
+ {
+ $$ = $2;
+ }
+ | '{' initializer_expr_list ',' '}'
+ {
+ $$ = $2;
+ }
+
+initializer_expr:
+ assignment_expr
+
+initializer_expr_list:
+ initializer_expr
+ {
+ $$.args_count = 1;
+ if (!($$.args = vkd3d_malloc(sizeof(*$$.args))))
+ YYABORT;
+ $$.args[0] = node_from_list($1);
+ $$.instrs = $1;
+ }
+ | initializer_expr_list ',' initializer_expr
+ {
+ $$ = $1;
+ if (!($$.args = vkd3d_realloc($$.args, ($$.args_count + 1) * sizeof(*$$.args))))
+ YYABORT;
+ $$.args[$$.args_count++] = node_from_list($3);
+ list_move_tail($$.instrs, $3);
+ vkd3d_free($3);
+ }
+
+boolean:
+ KW_TRUE
+ {
+ $$ = TRUE;
+ }
+ | KW_FALSE
+ {
+ $$ = FALSE;
+ }
+
+statement_list:
+ statement
+ | statement_list statement
+ {
+ $$ = $1;
+ list_move_tail($$, $2);
+ vkd3d_free($2);
+ }
+
+statement:
+ declaration_statement
+ | expr_statement
+ | compound_statement
+ | jump_statement
+ | selection_statement
+ | loop_statement
+
+jump_statement:
+ KW_RETURN expr ';'
+ {
+ if (!add_return($2, node_from_list($2), get_location(&@1)))
+ YYABORT;
+ $$ = $2;
+ }
+ | KW_RETURN ';'
+ {
+ if (!($$ = vkd3d_malloc(sizeof(*$$))))
+ YYABORT;
+ list_init($$);
+ if (!add_return($$, NULL, get_location(&@1)))
+ YYABORT;
+ }
+
+selection_statement:
+ KW_IF '(' expr ')' if_body
+ {
+ struct hlsl_ir_node *condition = node_from_list($3);
+ struct hlsl_ir_if *instr;
+
+ if (!(instr = new_if(condition, get_location(&@1))))
+ YYABORT;
+ list_move_tail(&instr->then_instrs, $5.then_instrs);
+ list_move_tail(&instr->else_instrs, $5.else_instrs);
+ vkd3d_free($5.then_instrs);
+ vkd3d_free($5.else_instrs);
+ if (condition->data_type->dimx > 1 || condition->data_type->dimy > 1)
+ hlsl_report_message(instr->node.loc, HLSL_LEVEL_ERROR,
+ "if condition requires a scalar");
+ $$ = $3;
+ list_add_tail($$, &instr->node.entry);
+ }
+
+if_body:
+ statement
+ {
+ $$.then_instrs = $1;
+ $$.else_instrs = NULL;
+ }
+ | statement KW_ELSE statement
+ {
+ $$.then_instrs = $1;
+ $$.else_instrs = $3;
+ }
+
+loop_statement:
+ KW_WHILE '(' expr ')' statement
+ {
+ $$ = create_loop(LOOP_WHILE, NULL, $3, NULL, $5, get_location(&@1));
+ }
+ | KW_DO statement KW_WHILE '(' expr ')' ';'
+ {
+ $$ = create_loop(LOOP_DO_WHILE, NULL, $5, NULL, $2, get_location(&@1));
+ }
+ | KW_FOR '(' scope_start expr_statement expr_statement expr ')' statement
+ {
+ $$ = create_loop(LOOP_FOR, $4, $5, $6, $8, get_location(&@1));
+ pop_scope(&hlsl_ctx);
+ }
+ | KW_FOR '(' scope_start declaration expr_statement expr ')' statement
+ {
+ if (!$4)
+ hlsl_report_message(get_location(&@4), HLSL_LEVEL_WARNING,
+ "no expressions in for loop initializer");
+ $$ = create_loop(LOOP_FOR, $4, $5, $6, $8, get_location(&@1));
+ pop_scope(&hlsl_ctx);
+ }
+
+expr_statement:
+ ';'
+ {
+ $$ = vkd3d_malloc(sizeof(*$$));
+ list_init($$);
+ }
+ | expr ';'
+ {
+ $$ = $1;
+ }
+
+primary_expr:
+ C_FLOAT
+ {
+ struct hlsl_ir_constant *c;
+
+ if (!(c = vkd3d_malloc(sizeof(*c))))
+ YYABORT;
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_ctx.builtin_types.scalar[HLSL_TYPE_FLOAT], get_location(&@1));
+ c->value.f[0] = $1;
+ if (!($$ = make_list(&c->node)))
+ YYABORT;
+ }
+ | C_INTEGER
+ {
+ struct hlsl_ir_constant *c;
+
+ if (!(c = vkd3d_malloc(sizeof(*c))))
+ YYABORT;
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_ctx.builtin_types.scalar[HLSL_TYPE_INT], get_location(&@1));
+ c->value.i[0] = $1;
+ if (!($$ = make_list(&c->node)))
+ YYABORT;
+ }
+ | boolean
+ {
+ struct hlsl_ir_constant *c;
+
+ if (!(c = vkd3d_malloc(sizeof(*c))))
+ YYABORT;
+ init_node(&c->node, HLSL_IR_CONSTANT, hlsl_ctx.builtin_types.scalar[HLSL_TYPE_BOOL], get_location(&@1));
+ c->value.b[0] = $1;
+ if (!($$ = make_list(&c->node)))
+ YYABORT;
+ }
+ | VAR_IDENTIFIER
+ {
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+
+ if (!(var = get_variable(hlsl_ctx.cur_scope, $1)))
+ {
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR, "variable '%s' is not declared\n", $1);
+ YYABORT;
+ }
+ if ((load = new_var_load(var, get_location(&@1))))
+ {
+ if (!($$ = make_list(&load->node)))
+ YYABORT;
+ }
+ else
+ $$ = NULL;
+ }
+ | '(' expr ')'
+ {
+ $$ = $2;
+ }
+
+postfix_expr:
+ primary_expr
+ | postfix_expr OP_INC
+ {
+ struct source_location loc;
+ struct hlsl_ir_node *inc;
+
+ loc = get_location(&@2);
+ if (node_from_list($1)->data_type->modifiers & HLSL_MODIFIER_CONST)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "modifying a const expression");
+ YYABORT;
+ }
+ inc = new_unary_expr(HLSL_IR_UNOP_POSTINC, node_from_list($1), loc);
+ /* Post increment/decrement expressions are considered const */
+ inc->data_type = clone_hlsl_type(inc->data_type, 0);
+ inc->data_type->modifiers |= HLSL_MODIFIER_CONST;
+ $$ = append_unop($1, inc);
+ }
+ | postfix_expr OP_DEC
+ {
+ struct source_location loc;
+ struct hlsl_ir_node *inc;
+
+ loc = get_location(&@2);
+ if (node_from_list($1)->data_type->modifiers & HLSL_MODIFIER_CONST)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "modifying a const expression");
+ YYABORT;
+ }
+ inc = new_unary_expr(HLSL_IR_UNOP_POSTDEC, node_from_list($1), loc);
+ /* Post increment/decrement expressions are considered const */
+ inc->data_type = clone_hlsl_type(inc->data_type, 0);
+ inc->data_type->modifiers |= HLSL_MODIFIER_CONST;
+ $$ = append_unop($1, inc);
+ }
+ | postfix_expr '.' any_identifier
+ {
+ struct hlsl_ir_node *node = node_from_list($1);
+ struct source_location loc;
+
+ loc = get_location(&@2);
+ if (node->data_type->type == HLSL_CLASS_STRUCT)
+ {
+ struct hlsl_type *type = node->data_type;
+ struct hlsl_struct_field *field;
+
+ $$ = NULL;
+ LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry)
+ {
+ if (!strcmp($3, field->name))
+ {
+ if (!add_record_load($1, node, field, loc))
+ YYABORT;
+ $$ = $1;
+ break;
+ }
+ }
+ if (!$$)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "invalid subscript %s", debugstr_a($3));
+ YYABORT;
+ }
+ }
+ else if (node->data_type->type <= HLSL_CLASS_LAST_NUMERIC)
+ {
+ struct hlsl_ir_swizzle *swizzle;
+
+ swizzle = get_swizzle(node, $3, &loc);
+ if (!swizzle)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "invalid swizzle %s", debugstr_a($3));
+ YYABORT;
+ }
+ $$ = append_unop($1, &swizzle->node);
+ }
+ else
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "invalid subscript %s", debugstr_a($3));
+ YYABORT;
+ }
+ }
+ | postfix_expr '[' expr ']'
+ {
+ struct hlsl_ir_node *array = node_from_list($1), *index = node_from_list($3);
+
+ list_move_tail($1, $3);
+ vkd3d_free($3);
+
+ if (index->data_type->type != HLSL_CLASS_SCALAR)
+ {
+ hlsl_report_message(get_location(&@3), HLSL_LEVEL_ERROR, "array index is not scalar");
+ free_instr_list($1);
+ YYABORT;
+ }
+
+ if (!add_array_load($1, array, index, get_location(&@2)))
+ {
+ free_instr_list($1);
+ YYABORT;
+ }
+ $$ = $1;
+ }
+
+ /* var_modifiers is necessary to avoid shift/reduce conflicts. */
+ | var_modifiers type '(' initializer_expr_list ')'
+ {
+ struct hlsl_ir_assignment *assignment;
+ unsigned int i, writemask_offset = 0;
+ static unsigned int counter;
+ struct hlsl_ir_load *load;
+ struct hlsl_ir_var *var;
+ char name[23];
+
+ if ($1)
+ {
+ hlsl_report_message(get_location(&@1), HLSL_LEVEL_ERROR,
+ "unexpected modifier on a constructor\n");
+ YYABORT;
+ }
+ if ($2->type > HLSL_CLASS_LAST_NUMERIC)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR,
+ "constructors may only be used with numeric data types\n");
+ YYABORT;
+ }
+ if ($2->dimx * $2->dimy != initializer_size(&$4))
+ {
+ hlsl_report_message(get_location(&@4), HLSL_LEVEL_ERROR,
+ "expected %u components in constructor, but got %u\n",
+ $2->dimx * $2->dimy, initializer_size(&$4));
+ YYABORT;
+ }
+
+ if ($2->type == HLSL_CLASS_MATRIX)
+ FIXME("Matrix constructors are not supported yet.\n");
+
+ sprintf(name, "<constructor-%x>", counter++);
+ if (!(var = new_synthetic_var(name, $2, get_location(&@2))))
+ YYABORT;
+ for (i = 0; i < $4.args_count; ++i)
+ {
+ struct hlsl_ir_node *arg = $4.args[i];
+ unsigned int width;
+
+ if (arg->data_type->type == HLSL_CLASS_OBJECT)
+ {
+ hlsl_report_message(arg->loc, HLSL_LEVEL_ERROR, "invalid constructor argument");
+ continue;
+ }
+ width = components_count_type(arg->data_type);
+
+ if (width > 4)
+ {
+ FIXME("Constructor argument with %u components.\n", width);
+ continue;
+ }
+
+ if (!(arg = add_implicit_conversion($4.instrs, arg,
+ hlsl_ctx.builtin_types.vector[$2->base_type][width - 1], &arg->loc)))
+ continue;
+
+ if (!(assignment = new_assignment(var, NULL, arg,
+ ((1 << width) - 1) << writemask_offset, arg->loc)))
+ YYABORT;
+ writemask_offset += width;
+ list_add_tail($4.instrs, &assignment->node.entry);
+ }
+ vkd3d_free($4.args);
+ if (!(load = new_var_load(var, get_location(&@2))))
+ YYABORT;
+ $$ = append_unop($4.instrs, &load->node);
+ }
+
+unary_expr:
+ postfix_expr
+ | OP_INC unary_expr
+ {
+ struct source_location loc;
+
+ loc = get_location(&@1);
+ if (node_from_list($2)->data_type->modifiers & HLSL_MODIFIER_CONST)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "modifying a const expression");
+ YYABORT;
+ }
+ $$ = append_unop($2, new_unary_expr(HLSL_IR_UNOP_PREINC, node_from_list($2), loc));
+ }
+ | OP_DEC unary_expr
+ {
+ struct source_location loc;
+
+ loc = get_location(&@1);
+ if (node_from_list($2)->data_type->modifiers & HLSL_MODIFIER_CONST)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "modifying a const expression");
+ YYABORT;
+ }
+ $$ = append_unop($2, new_unary_expr(HLSL_IR_UNOP_PREDEC, node_from_list($2), loc));
+ }
+ | unary_op unary_expr
+ {
+ enum hlsl_ir_expr_op ops[] = {0, HLSL_IR_UNOP_NEG,
+ HLSL_IR_UNOP_LOGIC_NOT, HLSL_IR_UNOP_BIT_NOT};
+
+ if ($1 == UNARY_OP_PLUS)
+ $$ = $2;
+ else
+ $$ = append_unop($2, new_unary_expr(ops[$1], node_from_list($2), get_location(&@1)));
+ }
+
+ /* var_modifiers is necessary to avoid shift/reduce conflicts. */
+ | '(' var_modifiers type array ')' unary_expr
+ {
+ struct hlsl_type *src_type = node_from_list($6)->data_type;
+ struct hlsl_type *dst_type;
+ struct source_location loc;
+
+ loc = get_location(&@3);
+ if ($2)
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "unexpected modifier in a cast");
+ YYABORT;
+ }
+
+ if ($4)
+ dst_type = new_array_type($3, $4);
+ else
+ dst_type = $3;
+
+ if (!compatible_data_types(src_type, dst_type))
+ {
+ hlsl_report_message(loc, HLSL_LEVEL_ERROR, "can't cast from %s to %s",
+ debug_hlsl_type(src_type), debug_hlsl_type(dst_type));
+ YYABORT;
+ }
+
+ $$ = append_unop($6, &new_cast(node_from_list($6), dst_type, &loc)->node);
+ }
+
+unary_op:
+ '+'
+ {
+ $$ = UNARY_OP_PLUS;
+ }
+ | '-'
+ {
+ $$ = UNARY_OP_MINUS;
+ }
+ | '!'
+ {
+ $$ = UNARY_OP_LOGICNOT;
+ }
+ | '~'
+ {
+ $$ = UNARY_OP_BITNOT;
+ }
+
+mul_expr:
+ unary_expr
+ | mul_expr '*' unary_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_MUL, get_location(&@2));
+ }
+ | mul_expr '/' unary_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_DIV, get_location(&@2));
+ }
+ | mul_expr '%' unary_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_MOD, get_location(&@2));
+ }
+
+add_expr:
+ mul_expr
+ | add_expr '+' mul_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_ADD, get_location(&@2));
+ }
+ | add_expr '-' mul_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_SUB, get_location(&@2));
+ }
+
+shift_expr:
+ add_expr
+ | shift_expr OP_LEFTSHIFT add_expr
+ {
+ FIXME("Left shift.\n");
+ }
+ | shift_expr OP_RIGHTSHIFT add_expr
+ {
+ FIXME("Right shift.\n");
+ }
+
+relational_expr:
+ shift_expr
+ | relational_expr '<' shift_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_LESS, get_location(&@2));
+ }
+ | relational_expr '>' shift_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_GREATER, get_location(&@2));
+ }
+ | relational_expr OP_LE shift_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_LEQUAL, get_location(&@2));
+ }
+ | relational_expr OP_GE shift_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_GEQUAL, get_location(&@2));
+ }
+
+equality_expr:
+ relational_expr
+ | equality_expr OP_EQ relational_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_EQUAL, get_location(&@2));
+ }
+ | equality_expr OP_NE relational_expr
+ {
+ $$ = add_binary_expr($1, $3, HLSL_IR_BINOP_NEQUAL, get_location(&@2));
+ }
+
+bitand_expr:
+ equality_expr
+ | bitand_expr '&' equality_expr
+ {
+ FIXME("Bitwise AND.\n");
+ }
+
+bitxor_expr:
+ bitand_expr
+ | bitxor_expr '^' bitand_expr
+ {
+ FIXME("Bitwise XOR.\n");
+ }
+
+bitor_expr:
+ bitxor_expr
+ | bitor_expr '|' bitxor_expr
+ {
+ FIXME("Bitwise OR.\n");
+ }
+
+logicand_expr:
+ bitor_expr
+ | logicand_expr OP_AND bitor_expr
+ {
+ FIXME("Logical AND.\n");
+ }
+
+logicor_expr:
+ logicand_expr
+ | logicor_expr OP_OR logicand_expr
+ {
+ FIXME("Logical OR.\n");
+ }
+
+conditional_expr:
+ logicor_expr
+ | logicor_expr '?' expr ':' assignment_expr
+ {
+ FIXME("Ternary operator.\n");
+ }
+
+assignment_expr:
+
+ conditional_expr
+ | unary_expr assign_op assignment_expr
+ {
+ struct hlsl_ir_node *lhs = node_from_list($1), *rhs = node_from_list($3);
+
+ if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST)
+ {
+ hlsl_report_message(get_location(&@2), HLSL_LEVEL_ERROR, "l-value is const");
+ YYABORT;
+ }
+ list_move_tail($3, $1);
+ vkd3d_free($1);
+ if (!add_assignment($3, lhs, $2, rhs))
+ YYABORT;
+ $$ = $3;
+ }
+
+assign_op:
+ '='
+ {
+ $$ = ASSIGN_OP_ASSIGN;
+ }
+ | OP_ADDASSIGN
+ {
+ $$ = ASSIGN_OP_ADD;
+ }
+ | OP_SUBASSIGN
+ {
+ $$ = ASSIGN_OP_SUB;
+ }
+ | OP_MULASSIGN
+ {
+ $$ = ASSIGN_OP_MUL;
+ }
+ | OP_DIVASSIGN
+ {
+ $$ = ASSIGN_OP_DIV;
+ }
+ | OP_MODASSIGN
+ {
+ $$ = ASSIGN_OP_MOD;
+ }
+ | OP_LEFTSHIFTASSIGN
+ {
+ $$ = ASSIGN_OP_LSHIFT;
+ }
+ | OP_RIGHTSHIFTASSIGN
+ {
+ $$ = ASSIGN_OP_RSHIFT;
+ }
+ | OP_ANDASSIGN
+ {
+ $$ = ASSIGN_OP_AND;
+ }
+ | OP_ORASSIGN
+ {
+ $$ = ASSIGN_OP_OR;
+ }
+ | OP_XORASSIGN
+ {
+ $$ = ASSIGN_OP_XOR;
+ }
+
+expr:
+ assignment_expr
+ | expr ',' assignment_expr
+ {
+ $$ = $1;
+ list_move_tail($$, $3);
+ vkd3d_free($3);
+ }
+
+%%
+
+static struct source_location get_location(const struct YYLTYPE *l)
+{
+ const struct source_location loc =
+ {
+ .file = hlsl_ctx.source_file,
+ .line = l->first_line,
+ .col = l->first_column,
+ };
+ return loc;
+}
+
+static void dump_function_decl(struct rb_entry *entry, void *context)
+{
+ struct hlsl_ir_function_decl *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function_decl, entry);
+
+ if (func->body)
+ debug_dump_ir_function_decl(func);
+}
+
+static void dump_function(struct rb_entry *entry, void *context)
+{
+ struct hlsl_ir_function *func = RB_ENTRY_VALUE(entry, struct hlsl_ir_function, entry);
+ rb_for_each_entry(&func->overloads, dump_function_decl, NULL);
+}
+
+/* Allocate a unique, ordered index to each instruction, which will be used for
+ * computing liveness ranges. */
+static unsigned int index_instructions(struct list *instrs, unsigned int index)
+{
+ struct hlsl_ir_node *instr;
+
+ LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry)
+ {
+ instr->index = index++;
+
+ if (instr->type == HLSL_IR_IF)
+ {
+ struct hlsl_ir_if *iff = if_from_node(instr);
+ index = index_instructions(&iff->then_instrs, index);
+ index = index_instructions(&iff->else_instrs, index);
+ }
+ else if (instr->type == HLSL_IR_LOOP)
+ {
+ index = index_instructions(&loop_from_node(instr)->body, index);
+ loop_from_node(instr)->next_index = index;
+ }
+ }
+
+ return index;
+}
+
+/* Compute the earliest and latest liveness for each variable. In the case that
+ * a variable is accessed inside of a loop, we promote its liveness to extend
+ * to at least the range of the entire loop. Note that we don't need to do this
+ * for anonymous nodes, since there's currently no way to use a node which was
+ * calculated in an earlier iteration of the loop. */
+static void compute_liveness_recurse(struct list *instrs, unsigned int loop_first, unsigned int loop_last)
+{
+ struct hlsl_ir_node *instr;
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(instr, instrs, struct hlsl_ir_node, entry)
+ {
+ switch (instr->type)
+ {
+ case HLSL_IR_ASSIGNMENT:
+ {
+ struct hlsl_ir_assignment *assignment = assignment_from_node(instr);
+
+ var = assignment->lhs.var;
+ if (!var->first_write)
+ var->first_write = loop_first ? min(instr->index, loop_first) : instr->index;
+ assignment->rhs.node->last_read = instr->index;
+ if (assignment->lhs.offset.node)
+ assignment->lhs.offset.node->last_read = instr->index;
+ break;
+ }
+ case HLSL_IR_EXPR:
+ {
+ struct hlsl_ir_expr *expr = expr_from_node(instr);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(expr->operands) && expr->operands[i].node; ++i)
+ expr->operands[i].node->last_read = instr->index;
+ break;
+ }
+ case HLSL_IR_IF:
+ {
+ struct hlsl_ir_if *iff = if_from_node(instr);
+
+ compute_liveness_recurse(&iff->then_instrs, loop_first, loop_last);
+ compute_liveness_recurse(&iff->else_instrs, loop_first, loop_last);
+ iff->condition.node->last_read = instr->index;
+ break;
+ }
+ case HLSL_IR_LOAD:
+ {
+ struct hlsl_ir_load *load = load_from_node(instr);
+
+ var = load->src.var;
+ var->last_read = loop_last ? max(instr->index, loop_last) : instr->index;
+ if (load->src.offset.node)
+ load->src.offset.node->last_read = instr->index;
+ break;
+ }
+ case HLSL_IR_LOOP:
+ {
+ struct hlsl_ir_loop *loop = loop_from_node(instr);
+
+ compute_liveness_recurse(&loop->body, loop_first ? loop_first : instr->index,
+ loop_last ? loop_last : loop->next_index);
+ break;
+ }
+ case HLSL_IR_SWIZZLE:
+ {
+ struct hlsl_ir_swizzle *swizzle = swizzle_from_node(instr);
+
+ swizzle->val.node->last_read = instr->index;
+ break;
+ }
+ case HLSL_IR_CONSTANT:
+ case HLSL_IR_JUMP:
+ break;
+ }
+ }
+}
+
+static void compute_liveness(struct hlsl_ir_function_decl *entry_func)
+{
+ struct hlsl_ir_var *var;
+
+ LIST_FOR_EACH_ENTRY(var, &hlsl_ctx.globals->vars, struct hlsl_ir_var, scope_entry)
+ {
+ var->first_write = 1;
+ }
+
+ LIST_FOR_EACH_ENTRY(var, entry_func->parameters, struct hlsl_ir_var, param_entry)
+ {
+ if (var->modifiers & HLSL_STORAGE_IN)
+ var->first_write = 1;
+ if (var->modifiers & HLSL_STORAGE_OUT)
+ var->last_read = UINT_MAX;
+ }
+
+ if (entry_func->return_var)
+ entry_func->return_var->last_read = UINT_MAX;
+
+ compute_liveness_recurse(entry_func->body, 0, 0);
+}
+
+int hlsl_parser_compile(enum vkd3d_shader_type type, DWORD major, DWORD minor, const char *entrypoint,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context)
+{
+ struct hlsl_ir_function_decl *entry_func;
+ struct hlsl_scope *scope, *next_scope;
+ struct hlsl_type *hlsl_type, *next_type;
+ struct hlsl_ir_var *var, *next_var;
+ int ret = VKD3D_ERROR;
+ unsigned int i;
+
+ hlsl_ctx.status = PARSE_SUCCESS;
+ hlsl_ctx.message_context = message_context;
+ hlsl_ctx.line_no = hlsl_ctx.column = 1;
+ hlsl_ctx.source_file = vkd3d_strdup("");
+ hlsl_ctx.source_files = vkd3d_malloc(sizeof(*hlsl_ctx.source_files));
+ if (hlsl_ctx.source_files)
+ hlsl_ctx.source_files[0] = hlsl_ctx.source_file;
+ hlsl_ctx.source_files_count = 1;
+ hlsl_ctx.cur_scope = NULL;
+ hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR;
+ list_init(&hlsl_ctx.scopes);
+ list_init(&hlsl_ctx.types);
+ init_functions_tree(&hlsl_ctx.functions);
+ list_init(&hlsl_ctx.static_initializers);
+
+ push_scope(&hlsl_ctx);
+ hlsl_ctx.globals = hlsl_ctx.cur_scope;
+ declare_predefined_types(hlsl_ctx.globals);
+
+ hlsl_parse();
+
+ if (hlsl_ctx.status == PARSE_ERR)
+ goto out;
+
+ if (!(entry_func = get_func_entry(entrypoint)))
+ {
+ hlsl_message("error: entry point %s is not defined\n", debugstr_a(entrypoint));
+ goto out;
+ }
+
+ if (!type_is_void(entry_func->return_type)
+ && entry_func->return_type->type != HLSL_CLASS_STRUCT && !entry_func->semantic)
+ {
+ hlsl_report_message(entry_func->loc, HLSL_LEVEL_ERROR,
+ "entry point \"%s\" is missing a return value semantic", entry_func->func->name);
+ }
+
+ list_move_head(entry_func->body, &hlsl_ctx.static_initializers);
+
+ /* Index 0 means unused; index 1 means function entry, so start at 2. */
+ index_instructions(entry_func->body, 2);
+
+ if (TRACE_ON())
+ {
+ TRACE("IR dump.\n");
+ rb_for_each_entry(&hlsl_ctx.functions, dump_function, NULL);
+ }
+
+ compute_liveness(entry_func);
+
+ if (hlsl_ctx.status != PARSE_ERR)
+ ret = VKD3D_ERROR_NOT_IMPLEMENTED;
+
+out:
+ for (i = 0; i < hlsl_ctx.source_files_count; ++i)
+ vkd3d_free((void *)hlsl_ctx.source_files[i]);
+ vkd3d_free(hlsl_ctx.source_files);
+
+ TRACE("Freeing functions IR.\n");
+ rb_destroy(&hlsl_ctx.functions, free_function_rb, NULL);
+
+ TRACE("Freeing variables.\n");
+ LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &hlsl_ctx.scopes, struct hlsl_scope, entry)
+ {
+ LIST_FOR_EACH_ENTRY_SAFE(var, next_var, &scope->vars, struct hlsl_ir_var, scope_entry)
+ free_declaration(var);
+ rb_destroy(&scope->types, NULL, NULL);
+ vkd3d_free(scope);
+ }
+
+ TRACE("Freeing types.\n");
+ LIST_FOR_EACH_ENTRY_SAFE(hlsl_type, next_type, &hlsl_ctx.types, struct hlsl_type, entry)
+ free_hlsl_type(hlsl_type);
+
+ return ret;
+}
diff --git a/libs/vkd3d-shader/trace.c b/libs/vkd3d-shader/trace.c
index e9c462e5..cab5b80d 100644
--- a/libs/vkd3d-shader/trace.c
+++ b/libs/vkd3d-shader/trace.c
@@ -1220,6 +1220,15 @@ const char *shader_get_type_prefix(enum vkd3d_shader_type type)
case VKD3D_SHADER_TYPE_COMPUTE:
return "cs";
+ case VKD3D_SHADER_TYPE_EFFECT:
+ return "fx";
+
+ case VKD3D_SHADER_TYPE_TEXTURE:
+ return "tx";
+
+ case VKD3D_SHADER_TYPE_LIBRARY:
+ return "lib";
+
default:
FIXME("Unhandled shader type %#x.\n", type);
return "unknown";
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c
index df3b1a57..ff917dbf 100644
--- a/libs/vkd3d-shader/vkd3d_shader_main.c
+++ b/libs/vkd3d-shader/vkd3d_shader_main.c
@@ -225,7 +225,7 @@ static void vkd3d_shader_dump_blob(const char *path, const char *prefix, const v
}
}
-static void vkd3d_shader_dump_shader(enum vkd3d_shader_type type, const struct vkd3d_shader_code *shader)
+void vkd3d_shader_dump_shader(enum vkd3d_shader_type type, const struct vkd3d_shader_code *shader)
{
static bool enabled = true;
const char *path;
@@ -961,7 +961,16 @@ static int compile_dxbc_tpf(const struct vkd3d_shader_compile_info *compile_info
static int compile_hlsl(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context)
{
- return VKD3D_ERROR_NOT_IMPLEMENTED;
+ struct vkd3d_shader_code preprocessed;
+ int ret;
+
+ if ((ret = preproc_lexer_parse(compile_info, &preprocessed, message_context)))
+ return ret;
+
+ ret = hlsl_compile_shader(preprocessed.code, compile_info, out, message_context);
+
+ vkd3d_shader_free_shader_code(&preprocessed);
+ return ret;
}
int vkd3d_shader_compile(const struct vkd3d_shader_compile_info *compile_info,
diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h
index 12edfae1..52196caf 100644
--- a/libs/vkd3d-shader/vkd3d_shader_private.h
+++ b/libs/vkd3d-shader/vkd3d_shader_private.h
@@ -548,6 +548,10 @@ enum vkd3d_shader_type
VKD3D_SHADER_TYPE_GRAPHICS_COUNT,
VKD3D_SHADER_TYPE_COMPUTE = VKD3D_SHADER_TYPE_GRAPHICS_COUNT,
+
+ VKD3D_SHADER_TYPE_EFFECT,
+ VKD3D_SHADER_TYPE_TEXTURE,
+ VKD3D_SHADER_TYPE_LIBRARY,
VKD3D_SHADER_TYPE_COUNT,
};
@@ -884,6 +888,8 @@ void vkd3d_shader_verror(struct vkd3d_shader_message_context *context, const str
void vkd3d_shader_vwarning(struct vkd3d_shader_message_context *context, const struct vkd3d_shader_location *location,
enum vkd3d_shader_error error, const char *format, va_list args) DECLSPEC_HIDDEN;
+void vkd3d_shader_dump_shader(enum vkd3d_shader_type type, const struct vkd3d_shader_code *shader) DECLSPEC_HIDDEN;
+
int shader_extract_from_dxbc(const void *dxbc, size_t dxbc_length,
struct vkd3d_shader_message_context *message_context, const char *source_name,
struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
@@ -909,6 +915,9 @@ void vkd3d_compute_dxbc_checksum(const void *dxbc, size_t size, uint32_t checksu
int preproc_lexer_parse(const struct vkd3d_shader_compile_info *compile_info,
struct vkd3d_shader_code *out, struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+int hlsl_compile_shader(const char *text, const struct vkd3d_shader_compile_info *compile_info,
+ struct vkd3d_shader_code *dxbc, struct vkd3d_shader_message_context *message_context) DECLSPEC_HIDDEN;
+
static inline enum vkd3d_shader_component_type vkd3d_component_type_from_data_type(
enum vkd3d_data_type data_type)
{
--
2.30.0
3
2
[PATCH v2 1/3] dxgi/tests: Test removing WS_EX_TOPMOST on a swapchain's fullscreen state output window.
by Gabriel Ivăncescu Jan. 29, 2021
by Gabriel Ivăncescu Jan. 29, 2021
Jan. 29, 2021
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
v2:
- Check for WS_EX_TOPMOST before removing it.
- Get rid of broken() on recent Windows 10 builds by using ResizeBuffers.
- Test Present with the DXGI_PRESENT_TEST flag.
- Test on hidden window as well. (it seems reliable enough, perhaps I messed
up by clicking on stuff by mistake while it was running)
dlls/dxgi/tests/dxgi.c | 86 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 2d8826f..6c9f293 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -2826,10 +2826,94 @@ static void test_set_fullscreen(IUnknown *device, BOOL is_d3d12)
refcount = IDXGISwapChain_Release(swapchain);
ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
- swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", WS_VISIBLE, 0, 0, 400, 200, 0, 0, 0, 0);
check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST), "Got unexpected WS_EX_TOPMOST.\n");
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ ok(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST, "Did not get WS_EX_TOPMOST.\n");
+
+ /* Removing topmost style makes the swapchain lose fullscreen state on next Present */
+ SetWindowPos(swapchain_desc.OutputWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST), "Got unexpected WS_EX_TOPMOST.\n");
+ flush_events();
+
+ hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ hr = IDXGISwapChain_Present(swapchain, 0, DXGI_PRESENT_TEST);
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* But not if the window is hidden */
+ ShowWindow(swapchain_desc.OutputWindow, SW_HIDE);
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE) & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST), "Got unexpected WS_EX_TOPMOST.\n");
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ ok(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST, "Did not get WS_EX_TOPMOST.\n");
+
+ SetWindowPos(swapchain_desc.OutputWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_HIDEWINDOW);
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_STYLE) & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST), "Got unexpected WS_EX_TOPMOST.\n");
+ flush_events();
+
+ hr = IDXGISwapChain_ResizeBuffers(swapchain, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+ todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+
+ DestroyWindow(swapchain_desc.OutputWindow);
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
check_swapchain_fullscreen_state(swapchain, &initial_state);
test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
--
2.29.2
2
3
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/ieframe/ieframe.h | 9 +++++++
dlls/ieframe/ieframe.spec | 1 +
dlls/ieframe/ieframe_main.c | 22 ++++++++++++++++
dlls/ieframe/oleobject.c | 1 +
dlls/ieframe/tests/webbrowser.c | 45 +++++++++++++++++++++++++++++++++
5 files changed, 78 insertions(+)
2
1
[PATCH 1/3] dxgi/tests: Test removing WS_EX_TOPMOST on a swapchain's fullscreen state output window.
by Gabriel Ivăncescu Jan. 29, 2021
by Gabriel Ivăncescu Jan. 29, 2021
Jan. 29, 2021
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/dxgi/tests/dxgi.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 2d8826f..14cb555 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -2826,10 +2826,47 @@ static void test_set_fullscreen(IUnknown *device, BOOL is_d3d12)
refcount = IDXGISwapChain_Release(swapchain);
ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
- swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", WS_VISIBLE, 0, 0, 400, 200, 0, 0, 0, 0);
check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, TRUE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+
+ /* Removing topmost style makes the swapchain lose fullscreen state on next Present */
+ SetWindowPos(swapchain_desc.OutputWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ ok(!(GetWindowLongA(swapchain_desc.OutputWindow, GWL_EXSTYLE) & WS_EX_TOPMOST), "Got unexpected WS_EX_TOPMOST.\n");
+ flush_events();
+
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ ok(!!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ todo_wine ok(hr == DXGI_STATUS_OCCLUDED || broken(hr == DXGI_ERROR_INVALID_CALL) /* Win10 1809 */, "Got unexpected hr %#x.\n", hr);
+ if (hr != DXGI_ERROR_INVALID_CALL)
+ {
+ hr = IDXGISwapChain_GetFullscreenState(swapchain, &fullscreen, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ todo_wine ok(!fullscreen, "Got unexpected fullscreen %#x.\n", fullscreen);
+ hr = IDXGISwapChain_Present(swapchain, 0, 0);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ }
+ hr = IDXGISwapChain_SetFullscreenState(swapchain, FALSE, NULL);
+ ok(hr == S_OK, "Got unexpected hr %#x.\n", hr);
+ refcount = IDXGISwapChain_Release(swapchain);
+ ok(!refcount, "IDXGISwapChain has %u references left.\n", refcount);
+
+ DestroyWindow(swapchain_desc.OutputWindow);
+ swapchain_desc.OutputWindow = CreateWindowA("static", "dxgi_test", 0, 0, 0, 400, 200, 0, 0, 0, 0);
+ check_window_fullscreen_state(swapchain_desc.OutputWindow, &initial_state.fullscreen_state);
+ hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &swapchain);
ok(SUCCEEDED(hr), "CreateSwapChain failed, hr %#x.\n", hr);
check_swapchain_fullscreen_state(swapchain, &initial_state);
test_swapchain_fullscreen_state(swapchain, adapter, &initial_state);
--
2.29.2
3
6
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mf/tests/mf.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 8272064466f..34090d0a9d4 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -1154,7 +1154,6 @@ static void test_session_events(IMFMediaSession *session)
static void test_media_session(void)
{
IMFRateControl *rate_control, *rate_control2;
- IMFLocalMFTRegistration *local_reg;
MFCLOCK_PROPERTIES clock_props;
IMFRateSupport *rate_support;
IMFAttributes *attributes;
@@ -1163,7 +1162,6 @@ static void test_media_session(void)
IMFShutdown *shutdown;
PROPVARIANT propvar;
DWORD status, caps;
- IMFGetService *gs;
IMFClock *clock;
IUnknown *unk;
HRESULT hr;
@@ -1176,23 +1174,19 @@ static void test_media_session(void)
hr = MFCreateMediaSession(NULL, &session);
ok(hr == S_OK, "Failed to create media session, hr %#x.\n", hr);
- hr = IMFMediaSession_QueryInterface(session, &IID_IMFAttributes, (void **)&unk);
- ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+ check_interface(session, &IID_IMFGetService, TRUE);
+ check_interface(session, &IID_IMFAttributes, FALSE);
- hr = IMFMediaSession_QueryInterface(session, &IID_IMFGetService, (void **)&gs);
- ok(hr == S_OK, "Failed to get interface, hr %#x.\n", hr);
-
- hr = IMFGetService_GetService(gs, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support);
+ hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateSupport, (void **)&rate_support);
ok(hr == S_OK, "Failed to get rate support interface, hr %#x.\n", hr);
- hr = IMFGetService_GetService(gs, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control);
+ hr = MFGetService((IUnknown *)session, &MF_RATE_CONTROL_SERVICE, &IID_IMFRateControl, (void **)&rate_control);
ok(hr == S_OK, "Failed to get rate control interface, hr %#x.\n", hr);
- hr = IMFGetService_GetService(gs, &MF_LOCAL_MFT_REGISTRATION_SERVICE, &IID_IMFLocalMFTRegistration,
- (void **)&local_reg);
+ hr = MFGetService((IUnknown *)session, &MF_LOCAL_MFT_REGISTRATION_SERVICE, &IID_IMFLocalMFTRegistration, (void **)&unk);
ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Vista */, "Failed to get registration service, hr %#x.\n", hr);
if (SUCCEEDED(hr))
- IMFLocalMFTRegistration_Release(local_reg);
+ IUnknown_Release(unk);
hr = IMFRateSupport_QueryInterface(rate_support, &IID_IMFMediaSession, (void **)&unk);
ok(hr == S_OK, "Failed to get session interface, hr %#x.\n", hr);
@@ -1220,6 +1214,8 @@ static void test_media_session(void)
hr = IMFMediaSession_GetClock(session, &clock);
ok(hr == S_OK, "Failed to get clock, hr %#x.\n", hr);
+ check_interface(clock, &IID_IMFPresentationClock, TRUE);
+
hr = IMFClock_QueryInterface(clock, &IID_IMFRateControl, (void **)&rate_control2);
ok(hr == S_OK, "Failed to get rate control, hr %#x.\n", hr);
@@ -1241,8 +1237,6 @@ todo_wine
IMFRateControl_Release(rate_control);
IMFRateSupport_Release(rate_support);
- IMFGetService_Release(gs);
-
IMFMediaSession_Release(session);
hr = MFCreateMediaSession(NULL, &session);
--
2.29.2
2
8
[PATCH] wldap32: log in with the authentication name instead of the authorization name
by Damjan Jovanovic Jan. 29, 2021
by Damjan Jovanovic Jan. 29, 2021
Jan. 29, 2021
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50572
Signed-off-by: Damjan Jovanovic <damjan.jov(a)gmail.com>
---
dlls/wldap32/bind.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
3
5
[PATCH v2 2/2] gdi32: Create a bitmap of the size of the virtual screen for display DCs.
by Zhiyi Zhang Jan. 29, 2021
by Zhiyi Zhang Jan. 29, 2021
Jan. 29, 2021
Fix a bug that WeChat screenshot is black when there is only one monitor.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/dc.c | 11 ++++++-
dlls/gdi32/driver.c | 2 +-
dlls/gdi32/gdi_private.h | 5 +++
dlls/gdi32/gdiobj.c | 61 +++++++++++++++++++++++++++++++++++--
dlls/gdi32/tests/bitmap.c | 1 -
dlls/user32/tests/monitor.c | 3 --
6 files changed, 74 insertions(+), 9 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 830fabf6e78..16aea2933aa 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -649,7 +649,16 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
if (!(dc = alloc_dc_ptr( OBJ_DC ))) return 0;
hdc = dc->hSelf;
- dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
+ if (!lstrcmpiW( driver, L"DISPLAY" ) || is_display_device( driver ) || is_display_device( device ))
+ {
+ dc->display_dc = 1;
+ dc->hBitmap = GDI_inc_ref_count( GetStockObject( DISPLAY_BITMAP ));
+ }
+ else
+ {
+ dc->display_dc = 0;
+ dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
+ }
TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index e146a3a4f85..d59061066a3 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -85,7 +85,7 @@ static BOOL (WINAPI *pEnumDisplayMonitors)(HDC, LPRECT, MONITORENUMPROC, LPARAM)
static BOOL (WINAPI *pEnumDisplaySettingsW)(LPCWSTR, DWORD, LPDEVMODEW);
static HWND (WINAPI *pGetDesktopWindow)(void);
static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR, LPMONITORINFO);
-static INT (WINAPI *pGetSystemMetrics)(INT);
+INT (WINAPI *pGetSystemMetrics)(INT) = NULL;
static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
/**********************************************************************
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 2bf16e8eaf8..13865f37ecc 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -47,6 +47,8 @@ typedef struct {
/* extra stock object: default 1x1 bitmap for memory DCs */
#define DEFAULT_BITMAP (STOCK_LAST+1)
+/* extra stock object: the bitmap for display DCs */
+#define DISPLAY_BITMAP (STOCK_LAST+2)
struct gdi_obj_funcs
{
@@ -72,6 +74,7 @@ typedef struct tagDC
DCHOOKPROC hookProc; /* DC hook */
BOOL bounds_enabled:1; /* bounds tracking is enabled */
BOOL path_open:1; /* path is currently open (only for saved DCs) */
+ BOOL display_dc:1; /* Whether this DC is a display DC */
POINT wnd_org; /* Window origin */
SIZE wnd_ext; /* Window extent */
@@ -761,4 +764,6 @@ extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN;
extern HMODULE gdi32_module DECLSPEC_HIDDEN;
+extern INT (WINAPI *pGetSystemMetrics)( INT ) DECLSPEC_HIDDEN;
+
#endif /* __WINE_GDI_PRIVATE_H */
diff --git a/dlls/gdi32/gdiobj.c b/dlls/gdi32/gdiobj.c
index 2309fdac582..bda1cf387be 100644
--- a/dlls/gdi32/gdiobj.c
+++ b/dlls/gdi32/gdiobj.c
@@ -26,6 +26,7 @@
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
+#include "winuser.h"
#include "winreg.h"
#include "winnls.h"
#include "winerror.h"
@@ -101,12 +102,13 @@ static const LOGPEN NullPen = { PS_NULL, { 0, 0 }, 0 };
static const LOGBRUSH DCBrush = { BS_SOLID, RGB(255,255,255), 0 };
static const LOGPEN DCPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
-/* reserve one extra entry for the stock default bitmap */
+/* reserve extra entries for the stock default bitmap and a bitmap for display DCs */
/* this is what Windows does too */
-#define NB_STOCK_OBJECTS (STOCK_LAST+2)
+#define NB_STOCK_OBJECTS (STOCK_LAST+3)
static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
static HGDIOBJ scaled_stock_objects[NB_STOCK_OBJECTS];
+static SIZE display_bitmap_size = { 1, 1 };
static CRITICAL_SECTION gdi_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -642,6 +644,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
stock_objects[DEFAULT_BITMAP] = CreateBitmap( 1, 1, 1, 1, NULL );
+ stock_objects[DISPLAY_BITMAP] = CreateBitmap( 1, 1, 1, 1, NULL );
/* language-independent stock fonts */
stock_objects[OEM_FIXED_FONT] = CreateFontIndirectW( &OEMFixedFont );
@@ -1007,6 +1010,9 @@ void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc)
*/
HGDIOBJ WINAPI GetStockObject( INT obj )
{
+ HBITMAP bitmap;
+ SIZE size;
+
if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
switch (obj)
{
@@ -1016,6 +1022,32 @@ HGDIOBJ WINAPI GetStockObject( INT obj )
case DEFAULT_GUI_FONT:
if (get_system_dpi() != 96) return scaled_stock_objects[obj];
break;
+ case DISPLAY_BITMAP:
+ {
+ EnterCriticalSection( &gdi_section );
+
+ if (pGetSystemMetrics)
+ {
+ size.cx = pGetSystemMetrics( SM_CXVIRTUALSCREEN );
+ size.cy = pGetSystemMetrics( SM_CYVIRTUALSCREEN );
+ if (size.cx != display_bitmap_size.cx || size.cy != display_bitmap_size.cy)
+ {
+ if ((bitmap = CreateBitmap( size.cx, size.cy, 1, 32, NULL )))
+ {
+ __wine_make_gdi_object_system( stock_objects[DISPLAY_BITMAP], FALSE );
+ if (!GDI_get_ref_count( stock_objects[DISPLAY_BITMAP] ))
+ DeleteObject( stock_objects[DISPLAY_BITMAP] );
+ stock_objects[DISPLAY_BITMAP] = bitmap;
+ display_bitmap_size = size;
+ __wine_make_gdi_object_system( stock_objects[DISPLAY_BITMAP], TRUE );
+ }
+ }
+ }
+
+ bitmap = stock_objects[DISPLAY_BITMAP];
+ LeaveCriticalSection( &gdi_section );
+ return bitmap;
+ }
}
return stock_objects[obj];
}
@@ -1125,6 +1157,7 @@ HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type)
{
HGDIOBJ ret = 0;
DC * dc = get_dc_ptr( hdc );
+ HBITMAP display_bitmap;
if (!dc) return 0;
@@ -1134,7 +1167,29 @@ HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type)
case OBJ_BRUSH: ret = dc->hBrush; break;
case OBJ_PAL: ret = dc->hPalette; break;
case OBJ_FONT: ret = dc->hFont; break;
- case OBJ_BITMAP: ret = dc->hBitmap; break;
+ case OBJ_BITMAP:
+ {
+ if (dc->display_dc)
+ {
+ EnterCriticalSection( &gdi_section );
+
+ display_bitmap = GetStockObject( DISPLAY_BITMAP );
+ if (dc->hBitmap != display_bitmap)
+ {
+ GDI_dec_ref_count( dc->hBitmap );
+ dc->hBitmap = GDI_inc_ref_count( display_bitmap );
+ }
+
+ ret = dc->hBitmap;
+ LeaveCriticalSection( &gdi_section );
+ }
+ else
+ {
+ ret = dc->hBitmap;
+ }
+
+ break;
+ }
/* tests show that OBJ_REGION is explicitly ignored */
case OBJ_REGION: break;
diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c
index fe3482671b2..b8071dc2155 100644
--- a/dlls/gdi32/tests/bitmap.c
+++ b/dlls/gdi32/tests/bitmap.c
@@ -2783,7 +2783,6 @@ static void test_CreateBitmap(void)
"0: %p, 1: %p, 4: %p, 5: %p, curObj1 %p, old1 %p\n",
bm, bm1, bm4, bm5, curObj1, old1);
ok(bm != bm2 && bm != bm3, "0: %p, 2: %p, 3: %p\n", bm, bm2, bm3);
-todo_wine
ok(bm != curObj2, "0: %p, curObj2 %p\n", bm, curObj2);
ok(old2 == 0, "old2 %p\n", old2);
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 926b288da11..adea730f65f 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -2039,13 +2039,10 @@ static void _check_display_dc(INT line, HDC hdc, const DEVMODEA *dm, BOOL allow_
if (ret)
{
ok_(__FILE__, line)(bitmap.bmType == 0, "Expected bmType %d, got %d.\n", 0, bitmap.bmType);
- todo_wine
ok_(__FILE__, line)(bitmap.bmWidth == GetSystemMetrics(SM_CXVIRTUALSCREEN),
"Expected bmWidth %d, got %d.\n", GetSystemMetrics(SM_CXVIRTUALSCREEN), bitmap.bmWidth);
- todo_wine
ok_(__FILE__, line)(bitmap.bmHeight == GetSystemMetrics(SM_CYVIRTUALSCREEN),
"Expected bmHeight %d, got %d.\n", GetSystemMetrics(SM_CYVIRTUALSCREEN), bitmap.bmHeight);
- todo_wine
ok_(__FILE__, line)(bitmap.bmBitsPixel == GetDeviceCaps(hdc, BITSPIXEL),
"Expected bmBitsPixel %d, got %d.\n", GetDeviceCaps(hdc, BITSPIXEL), bitmap.bmBitsPixel);
ok_(__FILE__, line)(bitmap.bmWidthBytes == get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel),
--
2.27.0
1
0
Jan. 29, 2021
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
v2: Supersede 198913~198914. Remove a todo_wine for a test that succeeds now.
dlls/user32/tests/monitor.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 58b3f0d5e0c..926b288da11 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -68,6 +68,11 @@ static void flush_events(void)
}
}
+static int get_bitmap_stride(int width, int bpp)
+{
+ return ((width * bpp + 15) >> 3) & ~1;
+}
+
static BOOL CALLBACK monitor_enum_proc(HMONITOR hmon, HDC hdc, LPRECT lprc,
LPARAM lparam)
{
@@ -1995,7 +2000,10 @@ static void test_handles(void)
#define check_display_dc(a, b, c) _check_display_dc(__LINE__, a, b, c)
static void _check_display_dc(INT line, HDC hdc, const DEVMODEA *dm, BOOL allow_todo)
{
+ BITMAP bitmap;
+ HBITMAP hbmp;
INT value;
+ BOOL ret;
value = GetDeviceCaps(hdc, HORZRES);
todo_wine_if(allow_todo && dm->dmPelsWidth != GetSystemMetrics(SM_CXSCREEN))
@@ -2023,6 +2031,29 @@ static void _check_display_dc(INT line, HDC hdc, const DEVMODEA *dm, BOOL allow_
todo_wine_if(allow_todo)
ok_(__FILE__, line)(value == dm->dmDisplayFrequency, "Expected VREFRESH %d, got %d.\n",
dm->dmDisplayFrequency, value);
+
+ hbmp = GetCurrentObject(hdc, OBJ_BITMAP);
+ ok_(__FILE__, line)(!!hbmp, "GetCurrentObject failed, error %#x.\n", GetLastError());
+ ret = GetObjectA(hbmp, sizeof(bitmap), &bitmap);
+ ok_(__FILE__, line)(ret || broken(!ret), /* <= Win7 */ "GetObjectA failed, error %#x.\n", GetLastError());
+ if (ret)
+ {
+ ok_(__FILE__, line)(bitmap.bmType == 0, "Expected bmType %d, got %d.\n", 0, bitmap.bmType);
+ todo_wine
+ ok_(__FILE__, line)(bitmap.bmWidth == GetSystemMetrics(SM_CXVIRTUALSCREEN),
+ "Expected bmWidth %d, got %d.\n", GetSystemMetrics(SM_CXVIRTUALSCREEN), bitmap.bmWidth);
+ todo_wine
+ ok_(__FILE__, line)(bitmap.bmHeight == GetSystemMetrics(SM_CYVIRTUALSCREEN),
+ "Expected bmHeight %d, got %d.\n", GetSystemMetrics(SM_CYVIRTUALSCREEN), bitmap.bmHeight);
+ todo_wine
+ ok_(__FILE__, line)(bitmap.bmBitsPixel == GetDeviceCaps(hdc, BITSPIXEL),
+ "Expected bmBitsPixel %d, got %d.\n", GetDeviceCaps(hdc, BITSPIXEL), bitmap.bmBitsPixel);
+ ok_(__FILE__, line)(bitmap.bmWidthBytes == get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel),
+ "Expected bmWidthBytes %d, got %d.\n", get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel),
+ bitmap.bmWidthBytes);
+ ok_(__FILE__, line)(bitmap.bmPlanes == 1, "Expected bmPlanes %d, got %d.\n", 1, bitmap.bmPlanes);
+ ok_(__FILE__, line)(bitmap.bmBits == NULL, "Expected bmBits %p, got %p.\n", NULL, bitmap.bmBits);
+ }
}
static void test_display_dc(void)
--
2.27.0
1
0
[PATCH] user32/clipboard: Set bitmap and palette handles as system object.
by Jactry Zeng Jan. 29, 2021
by Jactry Zeng Jan. 29, 2021
Jan. 29, 2021
This fixes an issue of WeChat's screenshot function that bitmap
isn't available to be copied to the input box.
Inspired by a PoC from Zhiyi.
Signed-off-by: Jactry Zeng <jzeng(a)codeweavers.com>
---
dlls/user32/clipboard.c | 9 +++-
dlls/user32/tests/clipboard.c | 79 ++++++++++++++++++++++++++++++++++-
2 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c
index 3d17b658e45..3e39a2d9ded 100644
--- a/dlls/user32/clipboard.c
+++ b/dlls/user32/clipboard.c
@@ -41,6 +41,7 @@
#include "user_private.h"
#include "win.h"
+#include "wine/gdi_driver.h"
#include "wine/list.h"
#include "wine/server.h"
#include "wine/debug.h"
@@ -302,8 +303,9 @@ static void free_cached_data( struct cached_format *cache )
switch (cache->format)
{
case CF_BITMAP:
- case CF_DSPBITMAP:
case CF_PALETTE:
+ __wine_make_gdi_object_system( cache->handle, FALSE );
+ case CF_DSPBITMAP:
DeleteObject( cache->handle );
break;
case CF_ENHMETAFILE:
@@ -886,6 +888,11 @@ HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
if (!(cache = HeapAlloc( GetProcessHeap(), 0, sizeof(*cache) ))) goto done;
cache->format = format;
cache->handle = data;
+
+ if (format == CF_BITMAP || format == CF_PALETTE)
+ {
+ __wine_make_gdi_object_system( cache->handle , TRUE );
+ }
}
EnterCriticalSection( &clipboard_cs );
diff --git a/dlls/user32/tests/clipboard.c b/dlls/user32/tests/clipboard.c
index 6fc4325e985..e24db5851ca 100644
--- a/dlls/user32/tests/clipboard.c
+++ b/dlls/user32/tests/clipboard.c
@@ -1779,10 +1779,14 @@ static void test_data_handles(void)
{
BOOL r;
char *ptr;
- HANDLE h, text;
+ HANDLE h, text, metafile;
HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL );
BITMAPINFO bmi;
void *bits;
+ PALETTEENTRY entry;
+ BYTE buffer[1024];
+ HENHMETAFILE emf;
+ int result;
ok( hwnd != 0, "window creation failed\n" );
format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" );
@@ -1895,6 +1899,79 @@ static void test_data_handles(void)
r = CloseClipboard();
ok( r, "gle %d\n", GetLastError() );
+ r = OpenClipboard( hwnd );
+ ok( r, "OpenClipboard failed: %#x.\n", GetLastError() );
+ r = EmptyClipboard();
+ ok( r, "EmptyClipboard failed: %#x.\n", GetLastError() );
+
+ bitmap = CreateBitmap( 10, 10, 1, 1, NULL );
+ h = SetClipboardData( CF_BITMAP, bitmap );
+ ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h );
+ ok( !!DeleteObject( bitmap ), "DeleteObject failed.\n" );
+ h = GetClipboardData( CF_BITMAP );
+ ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h );
+ memset( &bmi, 0, sizeof(bmi) );
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ result = GetDIBits( GetDC(0), h, 0, 0, NULL, &bmi, 0 );
+ ok( !!result && result != ERROR_INVALID_PARAMETER, "GetDIBits failed: %#x.\n", GetLastError() );
+
+ bitmap = CreateBitmap( 10, 10, 1, 1, NULL );
+ h = SetClipboardData( CF_DSPBITMAP, bitmap );
+ ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h );
+ ok( !!DeleteObject( bitmap ), "DeleteObject failed.\n" );
+ h = GetClipboardData( CF_DSPBITMAP );
+ ok( h == bitmap, "Expected bitmap %p, got %p.\n", bitmap, h );
+ memset( &bmi, 0, sizeof(bmi) );
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ ok( !GetDIBits( GetDC(0), h, 0, 0, 0, &bmi, 0 ), "GetDIBits returned unexpected value.\n" );
+
+ palette = CreatePalette( &logpalette );
+ h = SetClipboardData( CF_PALETTE, palette );
+ ok( h == palette, "Expected palette %p, got %p.\n", palette, h );
+ ok( !!DeleteObject( palette ), "DeleteObject failed.\n" );
+ h = GetClipboardData( CF_PALETTE );
+ ok( h == palette, "Expected palette %p, got %p.\n", palette, h );
+ ok( !!GetPaletteEntries( h, 0, 1, &entry ), "GetPaletteEntries %p failed.\n", h );
+ ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56,
+ "Got wrong color (%02x, %02x, %02x).\n", entry.peRed, entry.peGreen, entry.peBlue );
+
+ emf = create_emf();
+ h = SetClipboardData( CF_ENHMETAFILE, emf );
+ ok( h == emf, "Expected enhmetafile %p, got %p.\n", palette, h );
+ ok( !!DeleteEnhMetaFile( emf ), "DeleteEnhMetaFile failed.\n" );
+ h = GetClipboardData( CF_ENHMETAFILE );
+ ok( h == emf, "Expected enhmetafile %p, got %p.\n", palette, h );
+ ok( !GetEnhMetaFileBits( h, sizeof(buffer), buffer ), "GetEnhMetaFileBits returned unexpected value.\n" );
+
+ emf = create_emf();
+ h = SetClipboardData( CF_DSPENHMETAFILE, emf );
+ ok( h == emf, "Expected enhmetafile %p, got %p.\n", emf, h );
+ ok( !!DeleteEnhMetaFile( emf ), "DeleteEnhMetaFile failed.\n" );
+ h = GetClipboardData( CF_DSPENHMETAFILE );
+ ok( h == emf, "Expected enhmetafile %p, got %p.\n", emf, h );
+ ok( !GetEnhMetaFileBits( h, sizeof(buffer), buffer ), "GetEnhMetaFileBits returned unexpected value.\n" );
+
+ metafile = create_metafile();
+ h = SetClipboardData( CF_METAFILEPICT, metafile );
+ ok( h == metafile, "Expected metafilepict %p, got %p.\n", metafile, h );
+ ok( !GlobalFree( metafile ), "GlobalFree failed.\n" );
+ h = GetClipboardData( CF_METAFILEPICT );
+ ok( h == metafile, "Expected metafile %p, got %p.\n", metafile, h );
+ ok( is_freed( h ), "Expected freed mem %p.\n", h );
+
+ metafile = create_metafile();
+ h = SetClipboardData( CF_DSPMETAFILEPICT, metafile );
+ ok( h == metafile, "Expected metafilepict %p, got %p.\n", metafile, h );
+ ok( !GlobalFree( metafile ), "GlobalFree failed.\n" );
+ h = GetClipboardData( CF_DSPMETAFILEPICT );
+ ok( h == metafile, "Expected metafile %p, got %p.\n", metafile, h );
+ ok( is_freed( h ), "Expected freed mem %p.\n", h );
+
+ r = EmptyClipboard();
+ ok( r, "EmptyClipboard failed: %#x.\n", GetLastError() );
+ r = CloseClipboard();
+ ok( r, "CloseClipboard failed: %#x.\n", GetLastError() );
+
DestroyWindow( hwnd );
}
--
2.29.2
2
1
[tools] winetest/dissect: Improve the documentation of the missing start line handling.
by Francois Gouget Jan. 29, 2021
by Francois Gouget Jan. 29, 2021
Jan. 29, 2021
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
winetest/dissect | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/winetest/dissect b/winetest/dissect
index e9729dbc8..27bcf1704 100755
--- a/winetest/dissect
+++ b/winetest/dissect
@@ -717,23 +717,28 @@ while ($line = <IN>) {
if ($l_dll ne $dll or $l_unit ne $unit)
{
- # First close the current test unit taking into account
- # it may have been polluted by the new one.
+ # Warn about the missing start line in the current test unit box.
add_test_line("end", "The $l_dll:$l_unit start line is missing (or it is garbled)");
$extra_failures++;
+
+ # And close the current test unit taking into account
+ # it may have been polluted by the new one.
$broken = 1;
close_test_unit(0);
- # Then switch to the new one, warning it's missing a start line,
- # and that its results may be inconsistent.
+ # Then switch to the new test unit, not for the past lines, but for
+ # those before the next 'start' line. This 'new' test unit may have
+ # inconsistent results too.
($dll, $unit, $source, $rev) = ($l_dll, $l_unit, "-", "-");
%units = ($unit => 1);
$units_re = $unit;
+ $broken = 1;
$testbox = create_test_unit_box();
+ # Finally, warn about the missing start line in the new test unit
+ # box.
add_test_line("end", "The $l_dll:$l_unit start line is missing (or it is garbled)");
$extra_failures++;
- $broken = 1;
}
my $class = $l_rc ? "failed" : "";
--
2.20.1
1
0
[tools] testbot/LogUtils: Fix handling of new test units with no start line.
by Francois Gouget Jan. 29, 2021
by Francois Gouget Jan. 29, 2021
Jan. 29, 2021
Create a real new test unit object so $Cur->{LineFailures} is not
counted multiple times.
This matches the winetest parser behavior.
Improve the documentation.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
This fixes the failure count reported in this wtbsuite test:
WTBS A test unit with no start line (browseui:progressdlg).
testbot/lib/WineTestBot/LogUtils.pm | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index 1b4ee7a28..15ec31a42 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -675,11 +675,14 @@ sub ParseWineTestReport($$$)
$Cur->{IsBroken} = 1;
_CloseTestUnit($LogInfo, $Cur, 0);
- # Then switch to the new one, warning it's missing a start line,
- # and that its results may be inconsistent.
- ($Cur->{Dll}, $Cur->{Unit}) = ($Dll, $Unit);
- _AddExtra($LogInfo, "had no start line (or it is garbled)", $Cur);
+ # Then switch to the new test unit, not for the past lines, but for
+ # those before the next 'start' line. This 'new' test unit may have
+ # inconsistent results too so set IsBroken.
+ $Cur = _NewCurrentUnit($Dll, $Unit);
$Cur->{IsBroken} = 1;
+
+ # Finally, warn about the missing start line.
+ _AddExtra($LogInfo, "had no start line (or it is garbled)", $Cur);
}
if ($Rc == 258)
--
2.20.1
1
0
[PATCH 2/2] gdi32: Create a bitmap of the size of the virtual screen for display DCs.
by Zhiyi Zhang Jan. 29, 2021
by Zhiyi Zhang Jan. 29, 2021
Jan. 29, 2021
Fix a bug that WeChat screenshot is black when there is only one monitor.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/gdi32/dc.c | 11 ++++++-
dlls/gdi32/driver.c | 2 +-
dlls/gdi32/gdi_private.h | 5 +++
dlls/gdi32/gdiobj.c | 61 +++++++++++++++++++++++++++++++++++--
dlls/user32/tests/monitor.c | 3 --
5 files changed, 74 insertions(+), 8 deletions(-)
diff --git a/dlls/gdi32/dc.c b/dlls/gdi32/dc.c
index 830fabf6e78..16aea2933aa 100644
--- a/dlls/gdi32/dc.c
+++ b/dlls/gdi32/dc.c
@@ -649,7 +649,16 @@ HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
if (!(dc = alloc_dc_ptr( OBJ_DC ))) return 0;
hdc = dc->hSelf;
- dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
+ if (!lstrcmpiW( driver, L"DISPLAY" ) || is_display_device( driver ) || is_display_device( device ))
+ {
+ dc->display_dc = 1;
+ dc->hBitmap = GDI_inc_ref_count( GetStockObject( DISPLAY_BITMAP ));
+ }
+ else
+ {
+ dc->display_dc = 0;
+ dc->hBitmap = GDI_inc_ref_count( GetStockObject( DEFAULT_BITMAP ));
+ }
TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index e146a3a4f85..d59061066a3 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -85,7 +85,7 @@ static BOOL (WINAPI *pEnumDisplayMonitors)(HDC, LPRECT, MONITORENUMPROC, LPARAM)
static BOOL (WINAPI *pEnumDisplaySettingsW)(LPCWSTR, DWORD, LPDEVMODEW);
static HWND (WINAPI *pGetDesktopWindow)(void);
static BOOL (WINAPI *pGetMonitorInfoW)(HMONITOR, LPMONITORINFO);
-static INT (WINAPI *pGetSystemMetrics)(INT);
+INT (WINAPI *pGetSystemMetrics)(INT) = NULL;
static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
/**********************************************************************
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 2bf16e8eaf8..13865f37ecc 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -47,6 +47,8 @@ typedef struct {
/* extra stock object: default 1x1 bitmap for memory DCs */
#define DEFAULT_BITMAP (STOCK_LAST+1)
+/* extra stock object: the bitmap for display DCs */
+#define DISPLAY_BITMAP (STOCK_LAST+2)
struct gdi_obj_funcs
{
@@ -72,6 +74,7 @@ typedef struct tagDC
DCHOOKPROC hookProc; /* DC hook */
BOOL bounds_enabled:1; /* bounds tracking is enabled */
BOOL path_open:1; /* path is currently open (only for saved DCs) */
+ BOOL display_dc:1; /* Whether this DC is a display DC */
POINT wnd_org; /* Window origin */
SIZE wnd_ext; /* Window extent */
@@ -761,4 +764,6 @@ extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN;
extern HMODULE gdi32_module DECLSPEC_HIDDEN;
+extern INT (WINAPI *pGetSystemMetrics)( INT ) DECLSPEC_HIDDEN;
+
#endif /* __WINE_GDI_PRIVATE_H */
diff --git a/dlls/gdi32/gdiobj.c b/dlls/gdi32/gdiobj.c
index 2309fdac582..bda1cf387be 100644
--- a/dlls/gdi32/gdiobj.c
+++ b/dlls/gdi32/gdiobj.c
@@ -26,6 +26,7 @@
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
+#include "winuser.h"
#include "winreg.h"
#include "winnls.h"
#include "winerror.h"
@@ -101,12 +102,13 @@ static const LOGPEN NullPen = { PS_NULL, { 0, 0 }, 0 };
static const LOGBRUSH DCBrush = { BS_SOLID, RGB(255,255,255), 0 };
static const LOGPEN DCPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
-/* reserve one extra entry for the stock default bitmap */
+/* reserve extra entries for the stock default bitmap and a bitmap for display DCs */
/* this is what Windows does too */
-#define NB_STOCK_OBJECTS (STOCK_LAST+2)
+#define NB_STOCK_OBJECTS (STOCK_LAST+3)
static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
static HGDIOBJ scaled_stock_objects[NB_STOCK_OBJECTS];
+static SIZE display_bitmap_size = { 1, 1 };
static CRITICAL_SECTION gdi_section;
static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -642,6 +644,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
stock_objects[DEFAULT_BITMAP] = CreateBitmap( 1, 1, 1, 1, NULL );
+ stock_objects[DISPLAY_BITMAP] = CreateBitmap( 1, 1, 1, 1, NULL );
/* language-independent stock fonts */
stock_objects[OEM_FIXED_FONT] = CreateFontIndirectW( &OEMFixedFont );
@@ -1007,6 +1010,9 @@ void GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc)
*/
HGDIOBJ WINAPI GetStockObject( INT obj )
{
+ HBITMAP bitmap;
+ SIZE size;
+
if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
switch (obj)
{
@@ -1016,6 +1022,32 @@ HGDIOBJ WINAPI GetStockObject( INT obj )
case DEFAULT_GUI_FONT:
if (get_system_dpi() != 96) return scaled_stock_objects[obj];
break;
+ case DISPLAY_BITMAP:
+ {
+ EnterCriticalSection( &gdi_section );
+
+ if (pGetSystemMetrics)
+ {
+ size.cx = pGetSystemMetrics( SM_CXVIRTUALSCREEN );
+ size.cy = pGetSystemMetrics( SM_CYVIRTUALSCREEN );
+ if (size.cx != display_bitmap_size.cx || size.cy != display_bitmap_size.cy)
+ {
+ if ((bitmap = CreateBitmap( size.cx, size.cy, 1, 32, NULL )))
+ {
+ __wine_make_gdi_object_system( stock_objects[DISPLAY_BITMAP], FALSE );
+ if (!GDI_get_ref_count( stock_objects[DISPLAY_BITMAP] ))
+ DeleteObject( stock_objects[DISPLAY_BITMAP] );
+ stock_objects[DISPLAY_BITMAP] = bitmap;
+ display_bitmap_size = size;
+ __wine_make_gdi_object_system( stock_objects[DISPLAY_BITMAP], TRUE );
+ }
+ }
+ }
+
+ bitmap = stock_objects[DISPLAY_BITMAP];
+ LeaveCriticalSection( &gdi_section );
+ return bitmap;
+ }
}
return stock_objects[obj];
}
@@ -1125,6 +1157,7 @@ HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type)
{
HGDIOBJ ret = 0;
DC * dc = get_dc_ptr( hdc );
+ HBITMAP display_bitmap;
if (!dc) return 0;
@@ -1134,7 +1167,29 @@ HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type)
case OBJ_BRUSH: ret = dc->hBrush; break;
case OBJ_PAL: ret = dc->hPalette; break;
case OBJ_FONT: ret = dc->hFont; break;
- case OBJ_BITMAP: ret = dc->hBitmap; break;
+ case OBJ_BITMAP:
+ {
+ if (dc->display_dc)
+ {
+ EnterCriticalSection( &gdi_section );
+
+ display_bitmap = GetStockObject( DISPLAY_BITMAP );
+ if (dc->hBitmap != display_bitmap)
+ {
+ GDI_dec_ref_count( dc->hBitmap );
+ dc->hBitmap = GDI_inc_ref_count( display_bitmap );
+ }
+
+ ret = dc->hBitmap;
+ LeaveCriticalSection( &gdi_section );
+ }
+ else
+ {
+ ret = dc->hBitmap;
+ }
+
+ break;
+ }
/* tests show that OBJ_REGION is explicitly ignored */
case OBJ_REGION: break;
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 926b288da11..adea730f65f 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -2039,13 +2039,10 @@ static void _check_display_dc(INT line, HDC hdc, const DEVMODEA *dm, BOOL allow_
if (ret)
{
ok_(__FILE__, line)(bitmap.bmType == 0, "Expected bmType %d, got %d.\n", 0, bitmap.bmType);
- todo_wine
ok_(__FILE__, line)(bitmap.bmWidth == GetSystemMetrics(SM_CXVIRTUALSCREEN),
"Expected bmWidth %d, got %d.\n", GetSystemMetrics(SM_CXVIRTUALSCREEN), bitmap.bmWidth);
- todo_wine
ok_(__FILE__, line)(bitmap.bmHeight == GetSystemMetrics(SM_CYVIRTUALSCREEN),
"Expected bmHeight %d, got %d.\n", GetSystemMetrics(SM_CYVIRTUALSCREEN), bitmap.bmHeight);
- todo_wine
ok_(__FILE__, line)(bitmap.bmBitsPixel == GetDeviceCaps(hdc, BITSPIXEL),
"Expected bmBitsPixel %d, got %d.\n", GetDeviceCaps(hdc, BITSPIXEL), bitmap.bmBitsPixel);
ok_(__FILE__, line)(bitmap.bmWidthBytes == get_bitmap_stride(bitmap.bmWidth, bitmap.bmBitsPixel),
--
2.27.0
1
0