Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2021
- 83 participants
- 2620 messages
[PATCH 3/5] winegstreamer: Implement IWMReaderAdvanced::SetReceiveStreamSamples().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 7 +++
dlls/winegstreamer/wm_asyncreader.c | 20 +++++---
dlls/winegstreamer/wm_reader.c | 23 ++++++++--
dlls/wmvcore/tests/wmvcore.c | 71 ++++++++++++++++++++++++-----
4 files changed, 100 insertions(+), 21 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index f1862515ebc..e31405a09ca 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -125,6 +125,11 @@ struct wm_stream
WORD index;
bool eos;
bool allocate_output;
+ /* Note that we only pretend to read compressed samples, and instead output
+ * uncompressed samples regardless of whether we are configured to read
+ * compressed samples. Rather, the behaviour of the reader objects differs
+ * in nontrivial ways depending on this field. */
+ bool read_compressed;
};
struct wm_reader
@@ -180,6 +185,8 @@ void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration);
HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate);
HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
IWMOutputMediaProps *props);
+HRESULT wm_reader_set_read_compressed(struct wm_reader *reader,
+ WORD stream_number, BOOL compressed);
HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections);
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index e0547dfda60..9cf8a73eb53 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -129,7 +129,13 @@ static DWORD WINAPI stream_thread(void *arg)
}
}
- IWMReaderCallback_OnSample(callback, i, pts, duration, flags, sample, reader->context);
+ if (stream->read_compressed)
+ hr = IWMReaderCallbackAdvanced_OnStreamSample(reader->reader.callback_advanced,
+ i + 1, pts, duration, flags, sample, reader->context);
+ else
+ hr = IWMReaderCallback_OnSample(callback, i, pts, duration,
+ flags, sample, reader->context);
+ TRACE("Callback returned %#x.\n", hr);
INSSBuffer_Release(sample);
all_eos = false;
}
@@ -487,12 +493,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetReceiveSelectionCallbacks(IWMReaderAdv
return E_NOTIMPL;
}
-static HRESULT WINAPI WMReaderAdvanced_SetReceiveStreamSamples(IWMReaderAdvanced6 *iface, WORD stream_num,
- BOOL receive_stream_samples)
+static HRESULT WINAPI WMReaderAdvanced_SetReceiveStreamSamples(IWMReaderAdvanced6 *iface,
+ WORD stream_number, BOOL compressed)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%d %x)\n", This, stream_num, receive_stream_samples);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+ TRACE("reader %p, stream_number %u, compressed %d.\n", reader, stream_number, compressed);
+
+ return wm_reader_set_read_compressed(&reader->reader, stream_number, compressed);
}
static HRESULT WINAPI WMReaderAdvanced_GetReceiveStreamSamples(IWMReaderAdvanced6 *iface, WORD stream_num,
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index 09059c3a32b..c53fb8ea8ee 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -1772,9 +1772,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
if (stream->eos)
return NS_E_NO_MORE_SAMPLES;
- if (!stream->allocate_output)
- callback_advanced = NULL;
-
for (;;)
{
if (!wg_parser_stream_get_event(wg_stream, &event))
@@ -1795,7 +1792,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
HRESULT hr;
BYTE *data;
- if (callback_advanced)
+ if (callback_advanced && !stream->read_compressed && stream->allocate_output)
{
if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced,
stream->index, event.u.buffer.size, &sample, NULL)))
@@ -1973,6 +1970,24 @@ HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output
return S_OK;
}
+HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, WORD stream_number, BOOL compressed)
+{
+ struct wm_stream *stream;
+
+ EnterCriticalSection(&reader->cs);
+
+ if (!(stream = wm_reader_get_stream_by_stream_number(reader, stream_number)))
+ {
+ LeaveCriticalSection(&reader->cs);
+ return E_INVALIDARG;
+ }
+
+ stream->read_compressed = compressed;
+
+ LeaveCriticalSection(&reader->cs);
+ return S_OK;
+}
+
void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
{
reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 07a465c7518..eb6e45b30ce 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1348,6 +1348,7 @@ struct callback
unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
bool all_streams_off;
bool allocated_samples;
+ bool read_compressed;
};
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
@@ -1474,20 +1475,12 @@ static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS sta
return S_OK;
}
-static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
- QWORD time, QWORD duration, DWORD flags, INSSBuffer *sample, void *context)
+static void check_async_sample(struct callback *callback, INSSBuffer *sample)
{
- struct callback *callback = impl_from_IWMReaderCallback(iface);
DWORD size, capacity;
BYTE *data, *data2;
HRESULT hr;
- if (winetest_debug > 1)
- trace("%u: %04x: IWMReaderCallback::OnSample(output %u, time %I64u, duration %I64u, flags %#x)\n",
- GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
-
- ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
-
if (callback->allocated_samples)
{
struct buffer *buffer = impl_from_INSSBuffer(sample);
@@ -1521,7 +1514,22 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
ok(data2 == data, "Data pointers didn't match.\n");
ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size);
}
+}
+static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
+ QWORD time, QWORD duration, DWORD flags, INSSBuffer *sample, void *context)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallback::OnSample(output %u, time %I64u, duration %I64u, flags %#x)\n",
+ GetTickCount(), GetCurrentThreadId(), output, time, duration, flags);
+
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+
+ check_async_sample(callback, sample);
+
+ ok(!callback->read_compressed, "OnSample() should not be called when reading compressed samples.\n");
ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started);
ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
++callback->got_sample;
@@ -1564,8 +1572,22 @@ static ULONG WINAPI callback_advanced_Release(IWMReaderCallbackAdvanced *iface)
static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced *iface,
WORD stream_number, QWORD pts, QWORD duration, DWORD flags, INSSBuffer *sample, void *context)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallbackAdvanced::OnStreamSample(stream %u, pts %I64u, duration %I64u, flags %#x)\n",
+ GetTickCount(), GetCurrentThreadId(), stream_number, pts, duration, flags);
+
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+
+ check_async_sample(callback, sample);
+
+ ok(callback->read_compressed, "OnStreamSample() should not be called unless reading compressed samples.\n");
+ ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started);
+ ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ ++callback->got_sample;
+
+ return S_OK;
}
static HRESULT WINAPI callback_advanced_OnTime(IWMReaderCallbackAdvanced *iface, QWORD time, void *context)
@@ -1915,6 +1937,32 @@ static void test_async_reader_selection(IWMReader *reader,
ok(hr == S_OK, "Got hr %#x.\n", hr);
}
+static void test_async_reader_compressed(IWMReader *reader,
+ IWMReaderAdvanced2 *advanced, struct callback *callback)
+{
+ HRESULT hr;
+
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 0, TRUE);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 3, TRUE);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ callback->read_compressed = true;
+ run_async_reader(reader, advanced, callback);
+ callback->read_compressed = false;
+
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 1, FALSE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetReceiveStreamSamples(advanced, 2, FALSE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+}
+
static void test_async_reader_streaming(void)
{
const WCHAR *filename = load_resource(L"test.wmv");
@@ -2007,6 +2055,7 @@ static void test_async_reader_streaming(void)
test_reader_attributes(profile);
test_async_reader_selection(reader, advanced, &callback);
test_async_reader_allocate(reader, advanced, &callback);
+ test_async_reader_compressed(reader, advanced, &callback);
hr = IWMReader_Close(reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
--
2.33.0
Nov. 11, 2021
[PATCH 2/5] wmvcore/tests: Add tests for user-allocated samples.
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/wmvcore/tests/wmvcore.c | 434 +++++++++++++++++++++++++++++++++--
1 file changed, 415 insertions(+), 19 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 76586822c84..07a465c7518 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -273,6 +273,117 @@ static void test_iscontentprotected(void)
ok(drm == FALSE, "got %0dx\n", drm);
}
+static LONG outstanding_buffers;
+
+struct buffer
+{
+ INSSBuffer INSSBuffer_iface;
+ LONG refcount;
+
+ DWORD capacity, size;
+ BYTE data[1];
+};
+
+static inline struct buffer *impl_from_INSSBuffer(INSSBuffer *iface)
+{
+ return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface);
+}
+
+static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out)
+{
+ if (winetest_debug > 1)
+ trace("%04x: INSSBuffer::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid));
+
+ if (!IsEqualGUID(iid, &IID_INSSBuffer3) && !IsEqualGUID(iid, &IID_IMediaBuffer))
+ ok(0, "Unexpected IID %s.\n", debugstr_guid(iid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI buffer_AddRef(INSSBuffer *iface)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+ return InterlockedIncrement(&buffer->refcount);
+}
+
+static ULONG WINAPI buffer_Release(INSSBuffer *iface)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+ ULONG refcount = InterlockedDecrement(&buffer->refcount);
+
+ if (!refcount)
+ {
+ InterlockedDecrement(&outstanding_buffers);
+ free(buffer);
+ }
+ return refcount;
+}
+
+static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+ if (winetest_debug > 1)
+ trace("%04x: INSSBuffer::GetLength()\n", GetCurrentThreadId());
+
+ *size = buffer->size;
+ return S_OK;
+}
+
+static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+ if (winetest_debug > 1)
+ trace("%04x: INSSBuffer::SetLength(%u)\n", GetCurrentThreadId(), size);
+
+ ok(size <= buffer->capacity, "Got size %u, buffer capacity %u.\n", size, buffer->capacity);
+
+ buffer->size = size;
+ return S_OK;
+}
+
+static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+ if (winetest_debug > 1)
+ trace("%04x: INSSBuffer::GetMaxLength()\n", GetCurrentThreadId());
+
+ *size = buffer->capacity;
+ return S_OK;
+}
+
+static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size)
+{
+ struct buffer *buffer = impl_from_INSSBuffer(iface);
+
+ if (winetest_debug > 1)
+ trace("%04x: INSSBuffer::GetBufferAndLength()\n", GetCurrentThreadId());
+
+ *size = buffer->size;
+ *data = buffer->data;
+ return S_OK;
+}
+
+static const INSSBufferVtbl buffer_vtbl =
+{
+ buffer_QueryInterface,
+ buffer_AddRef,
+ buffer_Release,
+ buffer_GetLength,
+ buffer_SetLength,
+ buffer_GetMaxLength,
+ buffer_GetBuffer,
+ buffer_GetBufferAndLength,
+};
+
struct teststream
{
IStream IStream_iface;
@@ -1230,10 +1341,13 @@ static void test_sync_reader_file(void)
struct callback
{
IWMReaderCallback IWMReaderCallback_iface;
+ IWMReaderCallbackAdvanced IWMReaderCallbackAdvanced_iface;
+ IWMReaderAllocatorEx IWMReaderAllocatorEx_iface;
LONG refcount;
HANDLE got_opened, got_stopped, eof_event;
unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
bool all_streams_off;
+ bool allocated_samples;
};
static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
@@ -1243,13 +1357,25 @@ static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
static HRESULT WINAPI callback_QueryInterface(IWMReaderCallback *iface, REFIID iid, void **out)
{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
if (winetest_debug > 1)
trace("%04x: IWMReaderCallback::QueryInterface(%s)\n", GetCurrentThreadId(), debugstr_guid(iid));
- if (!IsEqualGUID(iid, &IID_IWMReaderCallbackAdvanced) && !IsEqualGUID(iid, &IID_IWMCredentialCallback))
- ok(0, "Unexpected IID %s.\n", debugstr_guid(iid));
+ if (IsEqualGUID(iid, &IID_IWMReaderAllocatorEx))
+ *out = &callback->IWMReaderAllocatorEx_iface;
+ else if (IsEqualGUID(iid, &IID_IWMReaderCallbackAdvanced))
+ *out = &callback->IWMReaderCallbackAdvanced_iface;
+ else
+ {
+ if (!IsEqualGUID(iid, &IID_IWMCredentialCallback))
+ ok(0, "Unexpected IID %s.\n", debugstr_guid(iid));
- return E_NOINTERFACE;
+ return E_NOINTERFACE;
+ }
+
+ IWMReaderCallback_AddRef(iface);
+ return S_OK;
}
static ULONG WINAPI callback_AddRef(IWMReaderCallback *iface)
@@ -1362,27 +1488,39 @@ static HRESULT WINAPI callback_OnSample(IWMReaderCallback *iface, DWORD output,
ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
- hr = INSSBuffer_GetBufferAndLength(sample, &data, &size);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (callback->allocated_samples)
+ {
+ struct buffer *buffer = impl_from_INSSBuffer(sample);
- hr = INSSBuffer_GetBuffer(sample, &data2);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ok(data2 == data, "Data pointers didn't match.\n");
+ ok(sample->lpVtbl == &buffer_vtbl, "Buffer vtbl didn't match.\n");
+ ok(buffer->size > 0 && buffer->size <= buffer->capacity, "Got size %d.\n", buffer->size);
+ }
+ else
+ {
+ ok(sample->lpVtbl != &buffer_vtbl, "Buffer vtbl shouldn't match.\n");
- hr = INSSBuffer_GetMaxLength(sample, &capacity);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ok(size <= capacity, "Size %u exceeds capacity %u.\n", size, capacity);
+ hr = INSSBuffer_GetBufferAndLength(sample, &data, &size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
- hr = INSSBuffer_SetLength(sample, capacity + 1);
- ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = INSSBuffer_GetBuffer(sample, &data2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(data2 == data, "Data pointers didn't match.\n");
- hr = INSSBuffer_SetLength(sample, capacity - 1);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = INSSBuffer_GetMaxLength(sample, &capacity);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(size <= capacity, "Size %u exceeds capacity %u.\n", size, capacity);
- hr = INSSBuffer_GetBufferAndLength(sample, &data2, &size);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ok(data2 == data, "Data pointers didn't match.\n");
- ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size);
+ hr = INSSBuffer_SetLength(sample, capacity + 1);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = INSSBuffer_SetLength(sample, capacity - 1);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = INSSBuffer_GetBufferAndLength(sample, &data2, &size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(data2 == data, "Data pointers didn't match.\n");
+ ok(size == capacity - 1, "Expected size %u, got %u.\n", capacity - 1, size);
+ }
ok(callback->got_started > 0, "Got %u WMT_STARTED callbacks.\n", callback->got_started);
ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
@@ -1400,10 +1538,164 @@ static const IWMReaderCallbackVtbl callback_vtbl =
callback_OnSample,
};
+static struct callback *impl_from_IWMReaderCallbackAdvanced(IWMReaderCallbackAdvanced *iface)
+{
+ return CONTAINING_RECORD(iface, struct callback, IWMReaderCallbackAdvanced_iface);
+}
+
+static HRESULT WINAPI callback_advanced_QueryInterface(IWMReaderCallbackAdvanced *iface, REFIID iid, void **out)
+{
+ struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+ return IWMReaderCallback_QueryInterface(&callback->IWMReaderCallback_iface, iid, out);
+}
+
+static ULONG WINAPI callback_advanced_AddRef(IWMReaderCallbackAdvanced *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+ return IWMReaderCallback_AddRef(&callback->IWMReaderCallback_iface);
+}
+
+static ULONG WINAPI callback_advanced_Release(IWMReaderCallbackAdvanced *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+ return IWMReaderCallback_Release(&callback->IWMReaderCallback_iface);
+}
+
+static HRESULT WINAPI callback_advanced_OnStreamSample(IWMReaderCallbackAdvanced *iface,
+ WORD stream_number, QWORD pts, QWORD duration, DWORD flags, INSSBuffer *sample, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI callback_advanced_OnTime(IWMReaderCallbackAdvanced *iface, QWORD time, void *context)
+{
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallbackAdvanced::OnTime(time %I64u)\n",
+ GetTickCount(), GetCurrentThreadId(), time);
+
+ ok(time == 3000 * 10000, "Got time %I64u.\n", time);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ return S_OK;
+}
+
+static HRESULT WINAPI callback_advanced_OnStreamSelection(IWMReaderCallbackAdvanced *iface,
+ WORD count, WORD *stream_numbers, WMT_STREAM_SELECTION *selections, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI callback_advanced_OnOutputPropsChanged(IWMReaderCallbackAdvanced *iface,
+ DWORD output, WM_MEDIA_TYPE *mt, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI callback_advanced_AllocateForStream(IWMReaderCallbackAdvanced *iface,
+ WORD stream_number, DWORD size, INSSBuffer **sample, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI callback_advanced_AllocateForOutput(IWMReaderCallbackAdvanced *iface,
+ DWORD output, DWORD size, INSSBuffer **sample, void *context)
+{
+ struct callback *callback = impl_from_IWMReaderCallbackAdvanced(iface);
+ struct buffer *object;
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallbackAdvanced::AllocateForOutput(output %u, size %u)\n",
+ GetTickCount(), GetCurrentThreadId(), output, size);
+
+ ok(callback->allocated_samples, "AllocateForOutput() should only be called when using a custom allocator.\n");
+
+ if (!(object = malloc(offsetof(struct buffer, data[size]))))
+ return E_OUTOFMEMORY;
+
+ size = max(size, 65536);
+
+ object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
+ object->refcount = 1;
+ object->capacity = size;
+ object->size = 0;
+ *sample = &object->INSSBuffer_iface;
+
+ InterlockedIncrement(&outstanding_buffers);
+
+ ok(!context, "Got unexpected context %p.\n", context);
+ return S_OK;
+}
+
+static const IWMReaderCallbackAdvancedVtbl callback_advanced_vtbl =
+{
+ callback_advanced_QueryInterface,
+ callback_advanced_AddRef,
+ callback_advanced_Release,
+ callback_advanced_OnStreamSample,
+ callback_advanced_OnTime,
+ callback_advanced_OnStreamSelection,
+ callback_advanced_OnOutputPropsChanged,
+ callback_advanced_AllocateForStream,
+ callback_advanced_AllocateForOutput,
+};
+
+static struct callback *impl_from_IWMReaderAllocatorEx(IWMReaderAllocatorEx *iface)
+{
+ return CONTAINING_RECORD(iface, struct callback, IWMReaderAllocatorEx_iface);
+}
+
+static HRESULT WINAPI callback_allocator_QueryInterface(IWMReaderAllocatorEx *iface, REFIID iid, void **out)
+{
+ struct callback *callback = impl_from_IWMReaderAllocatorEx(iface);
+ return IWMReaderCallback_QueryInterface(&callback->IWMReaderCallback_iface, iid, out);
+}
+
+static ULONG WINAPI callback_allocator_AddRef(IWMReaderAllocatorEx *iface)
+{
+ struct callback *callback = impl_from_IWMReaderAllocatorEx(iface);
+ return IWMReaderCallback_AddRef(&callback->IWMReaderCallback_iface);
+}
+
+static ULONG WINAPI callback_allocator_Release(IWMReaderAllocatorEx *iface)
+{
+ struct callback *callback = impl_from_IWMReaderAllocatorEx(iface);
+ return IWMReaderCallback_Release(&callback->IWMReaderCallback_iface);
+}
+
+static HRESULT WINAPI callback_allocator_AllocateForStreamEx(IWMReaderAllocatorEx *iface,
+ WORD stream_number, DWORD size, INSSBuffer **sample, DWORD flags,
+ QWORD pts, QWORD duration, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI callback_allocator_AllocateForOutputEx(IWMReaderAllocatorEx *iface,
+ DWORD output, DWORD size, INSSBuffer **sample, DWORD flags,
+ QWORD pts, QWORD duration, void *context)
+{
+ ok(0, "Unexpected call.\n");
+ return E_NOTIMPL;
+}
+
+static const IWMReaderAllocatorExVtbl callback_allocator_vtbl =
+{
+ callback_allocator_QueryInterface,
+ callback_allocator_AddRef,
+ callback_allocator_Release,
+ callback_allocator_AllocateForStreamEx,
+ callback_allocator_AllocateForOutputEx,
+};
+
static void callback_init(struct callback *callback)
{
memset(callback, 0, sizeof(*callback));
callback->IWMReaderCallback_iface.lpVtbl = &callback_vtbl;
+ callback->IWMReaderCallbackAdvanced_iface.lpVtbl = &callback_advanced_vtbl;
+ callback->IWMReaderAllocatorEx_iface.lpVtbl = &callback_allocator_vtbl;
callback->refcount = 1;
callback->got_opened = CreateEventW(NULL, FALSE, FALSE, NULL);
callback->got_stopped = CreateEventW(NULL, FALSE, FALSE, NULL);
@@ -1444,6 +1736,109 @@ static void run_async_reader(IWMReader *reader, IWMReaderAdvanced2 *advanced, st
ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = WaitForSingleObject(callback->got_stopped, 1000);
ok(!ret, "Wait timed out.\n");
+
+ ok(!outstanding_buffers, "Got %d outstanding buffers.\n", outstanding_buffers);
+}
+
+static void test_async_reader_allocate(IWMReader *reader,
+ IWMReaderAdvanced2 *advanced, struct callback *callback)
+{
+ BOOL allocate;
+ HRESULT hr;
+
+ callback->allocated_samples = true;
+
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 2, &allocate);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 0, &allocate);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 3, &allocate);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 0, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 1, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 2, TRUE);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(allocate == TRUE, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(allocate == TRUE, "Got allocate %d.\n", allocate);
+
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+
+ run_async_reader(reader, advanced, callback);
+
+ callback->allocated_samples = false;
+
+ hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 0, FALSE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForOutput(advanced, 1, FALSE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 0, TRUE);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, TRUE);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, TRUE);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 3, TRUE);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 0, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForOutput(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(!allocate, "Got allocate %d.\n", allocate);
+
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 1, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(allocate == TRUE, "Got allocate %d.\n", allocate);
+ hr = IWMReaderAdvanced2_GetAllocateForStream(advanced, 2, &allocate);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr == S_OK)
+ ok(allocate == TRUE, "Got allocate %d.\n", allocate);
+
+ run_async_reader(reader, advanced, callback);
+
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 1, FALSE);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetAllocateForStream(advanced, 2, FALSE);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
}
static void test_async_reader_selection(IWMReader *reader,
@@ -1611,6 +2006,7 @@ static void test_async_reader_streaming(void)
test_reader_attributes(profile);
test_async_reader_selection(reader, advanced, &callback);
+ test_async_reader_allocate(reader, advanced, &callback);
hr = IWMReader_Close(reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
--
2.33.0
Nov. 11, 2021
[PATCH 1/5] winegstreamer: Implement IWMReaderAdvanced::SetAllocateForOutput().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 8 ++-
dlls/winegstreamer/wm_asyncreader.c | 17 ++++--
dlls/winegstreamer/wm_reader.c | 84 ++++++++++++++++++++++++-----
3 files changed, 91 insertions(+), 18 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index e1dec7b755c..f1862515ebc 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -120,10 +120,11 @@ struct wm_stream
{
struct wm_reader *reader;
struct wg_parser_stream *wg_stream;
- WORD index;
- bool eos;
struct wg_format format;
WMT_STREAM_SELECTION selection;
+ WORD index;
+ bool eos;
+ bool allocate_output;
};
struct wm_reader
@@ -148,6 +149,8 @@ struct wm_reader
struct wm_stream *streams;
WORD stream_count;
+ IWMReaderCallbackAdvanced *callback_advanced;
+
const struct wm_reader_ops *ops;
};
@@ -174,6 +177,7 @@ void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops);
HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename);
HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration);
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate);
HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
IWMOutputMediaProps *props);
HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 35ed8221aa0..e0547dfda60 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -57,10 +57,16 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader)
static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
{
static const DWORD zero;
+ HRESULT hr;
IWMReaderCallback_AddRef(reader->callback = callback);
reader->context = context;
IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+
+ if (FAILED(hr = IWMReaderCallback_QueryInterface(callback,
+ &IID_IWMReaderCallbackAdvanced, (void **)&reader->reader.callback_advanced)))
+ reader->reader.callback_advanced = NULL;
+ TRACE("Querying for IWMReaderCallbackAdvanced returned %#x.\n", hr);
}
static DWORD WINAPI stream_thread(void *arg)
@@ -497,11 +503,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetReceiveStreamSamples(IWMReaderAdvanced
return E_NOTIMPL;
}
-static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL allocate)
+static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface,
+ DWORD output, BOOL allocate)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%d %x)\n", This, output_num, allocate);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+ TRACE("reader %p, output %u, allocate %d.\n", reader, output, allocate);
+
+ return wm_reader_set_allocate_for_output(&reader->reader, output, allocate);
}
static HRESULT WINAPI WMReaderAdvanced_GetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL *allocate)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index 3ca43fb127e..09059c3a32b 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -1554,6 +1554,10 @@ HRESULT wm_reader_close(struct wm_reader *reader)
CloseHandle(reader->read_thread);
reader->read_thread = NULL;
+ if (reader->callback_advanced)
+ IWMReaderCallbackAdvanced_Release(reader->callback_advanced);
+ reader->callback_advanced = NULL;
+
wg_parser_destroy(reader->wg_parser);
reader->wg_parser = NULL;
@@ -1758,9 +1762,9 @@ static const char *get_major_type_string(enum wg_major_type type)
HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags)
{
+ IWMReaderCallbackAdvanced *callback_advanced = stream->reader->callback_advanced;
struct wg_parser_stream *wg_stream = stream->wg_stream;
struct wg_parser_event event;
- struct buffer *object;
if (stream->selection == WMT_OFF)
return NS_E_INVALID_REQUEST;
@@ -1768,6 +1772,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
if (stream->eos)
return NS_E_NO_MORE_SAMPLES;
+ if (!stream->allocate_output)
+ callback_advanced = NULL;
+
for (;;)
{
if (!wg_parser_stream_get_event(wg_stream, &event))
@@ -1782,24 +1789,59 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
switch (event.type)
{
case WG_PARSER_EVENT_BUFFER:
- /* FIXME: Should these be pooled? */
- if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size]))))
+ {
+ DWORD size, capacity;
+ INSSBuffer *sample;
+ HRESULT hr;
+ BYTE *data;
+
+ if (callback_advanced)
{
- wg_parser_stream_release_buffer(wg_stream);
- return E_OUTOFMEMORY;
+ if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced,
+ stream->index, event.u.buffer.size, &sample, NULL)))
+ {
+ ERR("Failed to allocate sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr);
+ wg_parser_stream_release_buffer(wg_stream);
+ return hr;
+ }
+ }
+ else
+ {
+ struct buffer *object;
+
+ /* FIXME: Should these be pooled? */
+ if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size]))))
+ {
+ wg_parser_stream_release_buffer(wg_stream);
+ return E_OUTOFMEMORY;
+ }
+
+ object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
+ object->refcount = 1;
+ object->capacity = event.u.buffer.size;
+
+ TRACE("Created buffer %p.\n", object);
+ sample = &object->INSSBuffer_iface;
}
- object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
- object->refcount = 1;
- object->capacity = object->size = event.u.buffer.size;
+ if (FAILED(hr = INSSBuffer_GetBufferAndLength(sample, &data, &size)))
+ ERR("Failed to get data pointer, hr %#x.\n", hr);
+ if (FAILED(hr = INSSBuffer_GetMaxLength(sample, &capacity)))
+ ERR("Failed to get capacity, hr %#x.\n", hr);
+ if (event.u.buffer.size > capacity)
+ ERR("Returned capacity %u is less than requested capacity %u.\n",
+ capacity, event.u.buffer.size);
- if (!wg_parser_stream_copy_buffer(wg_stream, object->data, 0, object->size))
+ if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, event.u.buffer.size))
{
/* The GStreamer pin has been flushed. */
- free(object);
+ INSSBuffer_Release(sample);
break;
}
+ if (FAILED(hr = INSSBuffer_SetLength(sample, event.u.buffer.size)))
+ ERR("Failed to set size %u, hr %#x.\n", event.u.buffer.size, hr);
+
wg_parser_stream_release_buffer(wg_stream);
if (!event.u.buffer.has_pts)
@@ -1815,9 +1857,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
if (!event.u.buffer.delta)
*flags |= WM_SF_CLEANPOINT;
- TRACE("Created buffer %p.\n", object);
- *ret_sample = &object->INSSBuffer_iface;
+ *ret_sample = sample;
return S_OK;
+ }
case WG_PARSER_EVENT_EOS:
stream->eos = true;
@@ -1913,6 +1955,24 @@ HRESULT wm_reader_get_stream_selection(struct wm_reader *reader,
return S_OK;
}
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate)
+{
+ struct wm_stream *stream;
+
+ EnterCriticalSection(&reader->cs);
+
+ if (!(stream = get_stream_by_output_number(reader, output)))
+ {
+ LeaveCriticalSection(&reader->cs);
+ return E_INVALIDARG;
+ }
+
+ stream->allocate_output = !!allocate;
+
+ LeaveCriticalSection(&reader->cs);
+ return S_OK;
+}
+
void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
{
reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
--
2.33.0
Nov. 11, 2021
[PATCH v6 2/2] ntdll: Prevent loading Wine system dependencies in place of identically named application DLLs.
by Zebediah Figura
That is, load Wine system dependencies only when they are imported from Wine
builtins or other system dependencies, and do not match a Wine system dependency
by its base name when looking for already-loaded modules.
The reasoning is that it is possible for an application to ship, and expect to
use, a newer version of a MinGW-compiled library, or one with custom patches, or
possibly an unrelated library with the same name. We don't want to offer Wine's
system dependencies in place of the application's, or vice versa.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v6: remove a leftover trace.
dlls/ntdll/loader.c | 54 ++++++++++++++++++++++++++++-----------------
1 file changed, 34 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index a9578ae86bf..df337de85a4 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -135,6 +135,7 @@ typedef struct _wine_modref
LDR_DATA_TABLE_ENTRY ldr;
struct file_id id;
ULONG CheckSum;
+ BOOL system;
} WINE_MODREF;
static UINT tls_module_count; /* number of modules with TLS directory */
@@ -186,7 +187,7 @@ static WINE_MODREF *last_failed_modref;
static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
- DWORD flags, WINE_MODREF** pwm );
+ DWORD flags, WINE_MODREF **pwm, BOOL system );
static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
@@ -505,21 +506,22 @@ static WINE_MODREF *get_modref( HMODULE hmod )
* Find a module from its base name.
* The loader_section must be locked while calling this function
*/
-static WINE_MODREF *find_basename_module( LPCWSTR name )
+static WINE_MODREF *find_basename_module( const WCHAR *name, BOOL system )
{
PLIST_ENTRY mark, entry;
UNICODE_STRING name_str;
RtlInitUnicodeString( &name_str, name );
- if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
+ if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE )
+ && system == cached_modref->system)
return cached_modref;
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
- LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
- if (RtlEqualUnicodeString( &name_str, &mod->BaseDllName, TRUE ))
+ WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
+ if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && system == mod->system)
{
cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
return cached_modref;
@@ -714,6 +716,8 @@ static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
*/
static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
{
+ WINE_MODREF *imp = get_modref( module );
+ BOOL system = imp->system || (imp->ldr.Flags & LDR_WINE_INTERNAL);
const IMAGE_EXPORT_DIRECTORY *exports;
DWORD exp_size;
WINE_MODREF *wm;
@@ -733,10 +737,10 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWS
if (!wcschr( mod_name, '.' ))
memcpy( mod_name + (end - forward), L".dll", sizeof(L".dll") );
- if (!(wm = find_basename_module( mod_name )))
+ if (!(wm = find_basename_module( mod_name, system )))
{
TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
- if (load_dll( load_path, mod_name, L".dll", 0, &wm ) == STATUS_SUCCESS &&
+ if (load_dll( load_path, mod_name, L".dll", 0, &wm, system ) == STATUS_SUCCESS &&
!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
{
if (!imports_fixup_done && current_modref)
@@ -903,6 +907,7 @@ void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
*/
static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
{
+ BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
NTSTATUS status;
WINE_MODREF *wmImp;
HMODULE imp_mod;
@@ -936,7 +941,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
{
ascii_to_unicode( buffer, name, len );
buffer[len] = 0;
- status = load_dll( load_path, buffer, L".dll", 0, &wmImp );
+ status = load_dll( load_path, buffer, L".dll", 0, &wmImp, system );
}
else /* need to allocate a larger buffer */
{
@@ -944,7 +949,7 @@ static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LP
if (!ptr) return FALSE;
ascii_to_unicode( ptr, name, len );
ptr[len] = 0;
- status = load_dll( load_path, ptr, L".dll", 0, &wmImp );
+ status = load_dll( load_path, ptr, L".dll", 0, &wmImp, system );
RtlFreeHeap( GetProcessHeap(), 0, ptr );
}
@@ -1216,7 +1221,7 @@ static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void *
prev = current_modref;
current_modref = wm;
assert( !wm->ldr.DdagNode->Dependencies.Tail );
- if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp ))
+ if (!(status = load_dll( load_path, L"mscoree.dll", NULL, 0, &imp, FALSE ))
&& !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
status = STATUS_NO_MEMORY;
current_modref = prev;
@@ -2902,7 +2907,7 @@ done:
*/
static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
- SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
+ SECTION_IMAGE_INFORMATION *image_info, struct file_id *id, BOOL system )
{
WCHAR *ext, *dllname;
NTSTATUS status;
@@ -2943,7 +2948,7 @@ static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, con
else
{
if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
- if ((*pwm = find_basename_module( libname )) != NULL)
+ if ((*pwm = find_basename_module( libname, system )) != NULL)
{
status = STATUS_SUCCESS;
goto done;
@@ -2976,7 +2981,7 @@ done:
* The loader_section must be locked while calling this function.
*/
static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WCHAR *default_ext,
- DWORD flags, WINE_MODREF** pwm )
+ DWORD flags, WINE_MODREF **pwm, BOOL system )
{
UNICODE_STRING nt_name;
struct file_id id;
@@ -2987,10 +2992,13 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- if (system_dll_path.Buffer)
- nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (system && system_dll_path.Buffer)
+ nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, TRUE );
if (nts)
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ {
+ nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id, FALSE );
+ system = FALSE;
+ }
if (*pwm) /* found already loaded module */
{
@@ -3027,6 +3035,12 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
break;
}
+ /* mark the DLL as system only if it was loaded from a system path and is
+ * not builtin. note that builtins can appear to be loaded from a system
+ * path during prefix bootstrap */
+ if (!((*pwm)->ldr.Flags & LDR_WINE_INTERNAL))
+ (*pwm)->system = system;
+
if (NtCurrentTeb64())
NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
else
@@ -3084,7 +3098,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
RtlEnterCriticalSection( &loader_section );
- nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm );
+ nts = load_dll( path_name, libname->Buffer, L".dll", flags, &wm, FALSE );
if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
{
@@ -3159,7 +3173,7 @@ NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_ch
RtlEnterCriticalSection( &loader_section );
- status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id );
+ status = find_dll_file( load_path, name->Buffer, L".dll", &nt_name, &wm, &mapping, &image_info, &id, FALSE );
if (wm) *base = wm->ldr.DllBase;
else
@@ -3860,7 +3874,7 @@ static void init_wow64( CONTEXT *context )
NTSTATUS status;
static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";
- if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm )))
+ if ((status = load_dll( NULL, wow64_path, NULL, 0, &wm, FALSE )))
{
ERR( "could not load %s, status %x\n", debugstr_w(wow64_path), status );
NtTerminateProcess( GetCurrentProcess(), status );
@@ -4010,7 +4024,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
- if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS)
+ if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32, FALSE )) != STATUS_SUCCESS)
{
MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
NtTerminateProcess( GetCurrentProcess(), status );
--
2.33.0
Nov. 11, 2021
[PATCH v6 1/2] ntdll: Allow loading system DLLs from a path specified at configure time.
by Zebediah Figura
Many distributions provide MinGW-compiled system DLLs which are currently
bundled with Wine. Unfortunately, while MinGW pkg-config can be used to detect
the linking path, there is no standardized runtime path, and many distributions
in fact use different paths.
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v6: rebase on top of current git.
configure.ac | 3 +++
dlls/ntdll/Makefile.in | 1 +
dlls/ntdll/loader.c | 10 ++++++++--
dlls/ntdll/unix/env.c | 1 +
dlls/ntdll/unix/loader.c | 3 +++
dlls/ntdll/unix/unix_private.h | 1 +
6 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index f86a5decb07..d4c16e2c3d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,6 +99,7 @@ AC_ARG_WITH(xshm, AS_HELP_STRING([--without-xshm],[do not use XShm (shared
AC_ARG_WITH(xxf86vm, AS_HELP_STRING([--without-xxf86vm],[do not use XFree video mode extension]),
[if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_xf86vmode_h=no; ac_cv_header_X11_extensions_xf86vmproto_h=no; fi])
+AC_ARG_WITH(system-dlldir, AS_HELP_STRING([--with-system-dlldir=DIR],[load external PE dependencies from directory DIR]))
AC_ARG_WITH(wine-tools,AS_HELP_STRING([--with-wine-tools=DIR],[use Wine tools from directory DIR]))
AC_ARG_WITH(wine64, AS_HELP_STRING([--with-wine64=DIR],[use the 64-bit Wine in DIR for a Wow64 build]))
@@ -266,6 +267,8 @@ then
TARGETFLAGS="-b $host_alias $TARGETFLAGS"
fi
+AC_SUBST(system_dlldir,"$with_system_dlldir")
+
dnl Check for flex
AC_CHECK_PROGS(FLEX,flex,none)
if test "$FLEX" = "none"
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index d3be1fad0bc..bce141bc14b 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -72,5 +72,6 @@ EXTRA_OBJS = unix/version.o
unix_loader_EXTRADEFS = \
-DBINDIR=\"${bindir}\" \
+ -DSYSTEMDLLDIR=\"${system_dlldir}\" \
-DDLL_TO_BINDIR=\"`${MAKEDEP} -R ${dlldir} ${bindir}`\" \
-DBIN_TO_DATADIR=\"`${MAKEDEP} -R ${bindir} ${datadir}/wine`\"
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 255d5afef79..a9578ae86bf 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -95,6 +95,7 @@ static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
static ULONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
static ULONG dll_safe_mode = 1; /* dll search mode */
static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
+static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
static WCHAR *default_load_path; /* default dll search path */
@@ -2981,12 +2982,15 @@ static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, const WC
struct file_id id;
HANDLE mapping = 0;
SECTION_IMAGE_INFORMATION image_info;
- NTSTATUS nts;
+ NTSTATUS nts = STATUS_DLL_NOT_FOUND;
ULONG64 prev;
TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
- nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (system_dll_path.Buffer)
+ nts = find_dll_file( system_dll_path.Buffer, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
+ if (nts)
+ nts = find_dll_file( load_path, libname, default_ext, &nt_name, pwm, &mapping, &image_info, &id );
if (*pwm) /* found already loaded module */
{
@@ -3997,6 +4001,8 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR
load_global_options();
version_init();
+ get_env_var( L"WINESYSTEMDLLDIR", 0, &system_dll_path );
+
wm = build_main_module();
wm->ldr.LoadCount = -1;
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c
index 24f4fa5a588..f9e6e625cbb 100644
--- a/dlls/ntdll/unix/env.c
+++ b/dlls/ntdll/unix/env.c
@@ -1296,6 +1296,7 @@ static void add_dynamic_environment( WCHAR **env, SIZE_T *pos, SIZE_T *size )
add_path_var( env, pos, size, "WINEHOMEDIR", home_dir );
add_path_var( env, pos, size, "WINEBUILDDIR", build_dir );
add_path_var( env, pos, size, "WINECONFIGDIR", config_dir );
+ add_path_var( env, pos, size, "WINESYSTEMDLLDIR", system_dll_path );
for (i = 0; dll_paths[i]; i++)
{
sprintf( str, "WINEDLLDIR%u", i );
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 99226d472da..8464637e7e3 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -386,6 +386,7 @@ const char *data_dir = NULL;
const char *build_dir = NULL;
const char *config_dir = NULL;
const char **dll_paths = NULL;
+const char *system_dll_path = NULL;
const char *user_name = NULL;
SECTION_IMAGE_INFORMATION main_image_info = { NULL };
static HMODULE ntdll_module;
@@ -617,6 +618,8 @@ static void init_paths( char *argv[] )
data_dir = build_path( bin_dir, BIN_TO_DATADIR );
}
+ if (strlen(SYSTEMDLLDIR)) system_dll_path = SYSTEMDLLDIR;
+
set_dll_path();
set_home_dir();
set_config_dir();
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 641de0c465f..de7b66123c1 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -126,6 +126,7 @@ extern const char *build_dir DECLSPEC_HIDDEN;
extern const char *config_dir DECLSPEC_HIDDEN;
extern const char *user_name DECLSPEC_HIDDEN;
extern const char **dll_paths DECLSPEC_HIDDEN;
+extern const char *system_dll_path DECLSPEC_HIDDEN;
extern PEB *peb DECLSPEC_HIDDEN;
extern USHORT *uctable DECLSPEC_HIDDEN;
extern USHORT *lctable DECLSPEC_HIDDEN;
--
2.33.0
Nov. 11, 2021
[PATCH] shell32: Fix getting file attributes from the file system in SHELL32_GetItemAttributes.
by Torge Matthies
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52017
Signed-off-by: Torge Matthies <openglfreak(a)googlemail.com>
---
dlls/shell32/shlfolder.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/shell32/shlfolder.c b/dlls/shell32/shlfolder.c
index ce7fc072fa3..10aafc160c0 100644
--- a/dlls/shell32/shlfolder.c
+++ b/dlls/shell32/shlfolder.c
@@ -417,7 +417,7 @@ HRESULT SHELL32_GetItemAttributes (IShellFolder2 *psf, LPCITEMIDLIST pidl, LPDWO
} else if (_ILGetDataPointer (pidl)) {
DWORD file_attr = _ILGetFileAttributes (pidl, NULL, 0);
- if (!file_attr && has_guid) {
+ if (!file_attr) {
WCHAR path[MAX_PATH];
STRRET strret;
--
2.33.1
Nov. 10, 2021
Re: [PATCH vkd3d] vkd3d-shader/hlsl: swizzle types of srcs can now be specified on sm4_instruction
by Zebediah Figura
On 11/10/21 2:11 PM, Francisco Casas wrote:
> Some dxbc instructions require swizzle types that differ from what is
> usual for the register type.
>
> e.g.
> gather4 requires a register with register type VKD3D_SM4_RT_SAMPLER but
> a swizzle type VKD3D_SM4_SWIZZLE_VEC4 instead of the usual
> VKD3D_SM4_SWIZZLE_NONE.
You could look at it that way, but I would rather say that "some
register types do not use a consistent swizzle type." I.e. there's not
really a "usual" case.
This is particularly true upon noticing that gather4 isn't the only
"exception". For instance, I believe that single-element writemasks
should in general result in SCALAR rather than VEC4 for normal temps.
Along those lines, I'd rather see sm4_swizzle_type() just go away, and
the swizzle type explicitly specified everywhere. Introducing helpers
like sm4_source_from_node() and sm4_source_from_deref() would make this
easier.
As an aside, patch subjects should generally be phrased in the
imperative. E.g. in this case I'd say something like "Allow using a
custom swizzle type for sm4 source registers", or, if you end up
following my suggestion, "Explicitly specify the swizzle type for sm4
source registers".
>
> The new fields of sm4_instruction can be used to handle these
> exceptions.
>
> Also, they shouldn't change the current behaviour of the rest of
> the code since they are currently initalized with zeroes everywhere a
> sm4_instruction is initialized.
I think these paragraphs are obvious enough that they don't need to be
in a patch description.
Nov. 10, 2021
Re: [PATCH] mscoree: Update Wine Mono to 7.0.0.
by Marvin
Hi,
While running your changed tests, I think I found new failures.
Being a bot and all I'm not very good at pattern recognition, so I might be
wrong, but could you please double-check?
Full results can be found at:
https://testbot.winehq.org/JobDetails.pl?Key=101679
Your paranoid android.
=== debiant2 (build log) ===
WineRunWineTest.pl:error: The task timed out
=== debiant2 (build log) ===
Task: Could not create the wow32 wineprefix: Failed to disable the crash dialogs:
Task: WineTest did not produce the wow32 report
Nov. 10, 2021
[PATCH] mscoree: Update Wine Mono to 7.0.0.
by Esme Povirk
Signed-off-by: Esme Povirk <esme(a)codeweavers.com>
---
dlls/appwiz.cpl/addons.c | 4 ++--
dlls/mscoree/mscoree_private.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c
index 7ef7ca312ae..b4da6137d72 100644
--- a/dlls/appwiz.cpl/addons.c
+++ b/dlls/appwiz.cpl/addons.c
@@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
#define GECKO_SHA "???"
#endif
-#define MONO_VERSION "6.4.0"
+#define MONO_VERSION "7.0.0"
#if defined(__i386__) || defined(__x86_64__)
#define MONO_ARCH "x86"
-#define MONO_SHA "db8b85f3b910590f61adbfa0005a995d613e299a1cc73d00553d70dc81010e36"
+#define MONO_SHA "b37e6fc9e590e582243dc25d72a5fcc330c3a7970dfdc98a7a81d23845ba8900"
#else
#define MONO_ARCH ""
#define MONO_SHA "???"
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index 04844c8da69..1ef5ac200f3 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN;
extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN;
-#define WINE_MONO_VERSION "6.4.0"
+#define WINE_MONO_VERSION "7.0.0"
/* Mono embedding */
typedef struct _MonoDomain MonoDomain;
--
2.30.2
Nov. 10, 2021
[PATCH vkd3d] vkd3d-shader/hlsl: swizzle types of srcs can now be specified on sm4_instruction
by Francisco Casas
Some dxbc instructions require swizzle types that differ from what is
usual for the register type.
e.g.
gather4 requires a register with register type VKD3D_SM4_RT_SAMPLER but
a swizzle type VKD3D_SM4_SWIZZLE_VEC4 instead of the usual
VKD3D_SM4_SWIZZLE_NONE.
The new fields of sm4_instruction can be used to handle these
exceptions.
Also, they shouldn't change the current behaviour of the rest of
the code since they are currently initalized with zeroes everywhere a
sm4_instruction is initialized.
Signed-off-by: Francisco Casas <fcasas(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl_sm4.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index 9d45e163..e148c821 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -747,6 +747,10 @@ struct sm4_instruction
{
struct sm4_register reg;
unsigned int swizzle;
+ /* If use_custom_swizzle_type is true, then custom_swizzle_type will be used in the
+ * instruction, instead of the default swizzle type obtained from the register type. */
+ bool use_custom_swizzle_type;
+ enum vkd3d_sm4_swizzle_type custom_swizzle_type;
} srcs[2];
unsigned int src_count;
@@ -754,7 +758,7 @@ struct sm4_instruction
unsigned int idx_count;
};
-static unsigned int sm4_swizzle_type(enum vkd3d_sm4_register_type type)
+static unsigned int sm4_default_swizzle_type(enum vkd3d_sm4_register_type type)
{
switch (type)
{
@@ -913,8 +917,10 @@ static void write_sm4_instruction(struct vkd3d_bytecode_buffer *buffer, const st
for (i = 0; i < instr->src_count; ++i)
{
+ unsigned int swizzle_type = instr->srcs[i].use_custom_swizzle_type ?
+ instr->srcs[i].custom_swizzle_type : sm4_default_swizzle_type(instr->srcs[i].reg.type);
token = sm4_encode_register(&instr->srcs[i].reg);
- token |= sm4_swizzle_type(instr->srcs[i].reg.type) << VKD3D_SM4_SWIZZLE_TYPE_SHIFT;
+ token |= swizzle_type << VKD3D_SM4_SWIZZLE_TYPE_SHIFT;
token |= instr->srcs[i].swizzle << VKD3D_SM4_SWIZZLE_SHIFT;
if (instr->srcs[i].reg.mod)
token |= VKD3D_SM4_EXTENDED_OPERAND;
--
2.25.1
Nov. 10, 2021