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 vkd3d 4/6] vkd3d-shader/hlsl: Align conditionals and loops in the IR dump.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
index da4f10a9f..c71eac3f1 100644
--- a/libs/vkd3d-shader/hlsl.c
+++ b/libs/vkd3d-shader/hlsl.c
@@ -1208,11 +1208,11 @@ static void dump_ir_if(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer,
{
vkd3d_string_buffer_printf(buffer, "if (");
dump_src(buffer, &if_node->condition);
- vkd3d_string_buffer_printf(buffer, ")\n{\n");
+ vkd3d_string_buffer_printf(buffer, ") {\n");
dump_instr_list(ctx, buffer, &if_node->then_instrs.instrs);
- vkd3d_string_buffer_printf(buffer, "}\nelse\n{\n");
+ vkd3d_string_buffer_printf(buffer, " %10s } else {\n", "");
dump_instr_list(ctx, buffer, &if_node->else_instrs.instrs);
- vkd3d_string_buffer_printf(buffer, "}\n");
+ vkd3d_string_buffer_printf(buffer, " %10s }", "");
}
static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_jump *jump)
@@ -1239,9 +1239,9 @@ static void dump_ir_jump(struct vkd3d_string_buffer *buffer, const struct hlsl_i
static void dump_ir_loop(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer, const struct hlsl_ir_loop *loop)
{
- vkd3d_string_buffer_printf(buffer, "for (;;)\n{\n");
+ vkd3d_string_buffer_printf(buffer, "for (;;) {\n");
dump_instr_list(ctx, buffer, &loop->body.instrs);
- vkd3d_string_buffer_printf(buffer, "}\n");
+ vkd3d_string_buffer_printf(buffer, " %10s }", "");
}
static void dump_ir_resource_load(struct vkd3d_string_buffer *buffer, const struct hlsl_ir_resource_load *load)
--
2.33.1
Nov. 3, 2021
[PATCH vkd3d 3/6] vkd3d-shader/hlsl: Write SM4 conditionals.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl_sm4.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index 9d4319b6f..d48a41d11 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -1415,6 +1415,33 @@ static void write_sm4_expr(struct hlsl_ctx *ctx,
}
}
+static void write_sm4_if(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_if *iff)
+{
+ struct sm4_instruction instr =
+ {
+ .opcode = VKD3D_SM4_OP_IF | VKD3D_SM4_CONDITIONAL_NZ,
+ .src_count = 1,
+ };
+ unsigned int writemask;
+
+ assert(iff->condition.node->data_type->dimx == 1);
+
+ sm4_register_from_node(&instr.srcs[0].reg, &writemask, iff->condition.node);
+ instr.srcs[0].swizzle = hlsl_swizzle_from_writemask(writemask);
+ write_sm4_instruction(buffer, &instr);
+
+ write_sm4_block(ctx, buffer, &iff->then_instrs);
+
+ instr.opcode = VKD3D_SM4_OP_ELSE;
+ instr.src_count = 0;
+ write_sm4_instruction(buffer, &instr);
+
+ write_sm4_block(ctx, buffer, &iff->else_instrs);
+
+ instr.opcode = VKD3D_SM4_OP_ENDIF;
+ write_sm4_instruction(buffer, &instr);
+}
+
static void write_sm4_load(struct hlsl_ctx *ctx,
struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_load *load)
{
@@ -1554,6 +1581,10 @@ static void write_sm4_block(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *
write_sm4_expr(ctx, buffer, hlsl_ir_expr(instr));
break;
+ case HLSL_IR_IF:
+ write_sm4_if(ctx, buffer, hlsl_ir_if(instr));
+ break;
+
case HLSL_IR_LOAD:
write_sm4_load(ctx, buffer, hlsl_ir_load(instr));
break;
--
2.33.1
Nov. 3, 2021
[PATCH vkd3d 2/6] vkd3d-shader/hlsl: Write SM4 loops.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
libs/vkd3d-shader/hlsl_sm4.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index b6cb96775..9d4319b6f 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -23,6 +23,8 @@
#include "vkd3d_d3dcommon.h"
#include "sm4.h"
+static void write_sm4_block(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_block *block);
+
bool hlsl_sm4_register_from_semantic(struct hlsl_ctx *ctx, const struct hlsl_semantic *semantic,
bool output, enum vkd3d_sm4_register_type *type, bool *has_idx)
{
@@ -1432,6 +1434,22 @@ static void write_sm4_load(struct hlsl_ctx *ctx,
write_sm4_instruction(buffer, &instr);
}
+static void write_sm4_loop(struct hlsl_ctx *ctx,
+ struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_loop *loop)
+{
+ struct sm4_instruction instr =
+ {
+ .opcode = VKD3D_SM4_OP_LOOP,
+ };
+
+ write_sm4_instruction(buffer, &instr);
+
+ write_sm4_block(ctx, buffer, &loop->body);
+
+ instr.opcode = VKD3D_SM4_OP_ENDLOOP;
+ write_sm4_instruction(buffer, &instr);
+}
+
static void write_sm4_resource_load(struct hlsl_ctx *ctx,
struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_load *load)
{
@@ -1544,6 +1562,10 @@ static void write_sm4_block(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *
write_sm4_resource_load(ctx, buffer, hlsl_ir_resource_load(instr));
break;
+ case HLSL_IR_LOOP:
+ write_sm4_loop(ctx, buffer, hlsl_ir_loop(instr));
+ break;
+
case HLSL_IR_STORE:
write_sm4_store(ctx, buffer, hlsl_ir_store(instr));
break;
--
2.33.1
Nov. 3, 2021
[PATCH vkd3d 1/6] vkd3d-shader/hlsl: Introduce a helper to write SM4 code blocks.
by Zebediah Figura
From: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Giovanni Mascellani <gmascellani(a)codeweavers.com>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
Rebased onto the series beginning with 218669, with which some of these patches
conflicted, but not otherwise modified.
libs/vkd3d-shader/hlsl_sm4.c | 105 +++++++++++++++++++----------------
1 file changed, 56 insertions(+), 49 deletions(-)
diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c
index cef7d6b0f..b6cb96775 100644
--- a/libs/vkd3d-shader/hlsl_sm4.c
+++ b/libs/vkd3d-shader/hlsl_sm4.c
@@ -1503,13 +1503,67 @@ static void write_sm4_swizzle(struct hlsl_ctx *ctx,
write_sm4_instruction(buffer, &instr);
}
+static void write_sm4_block(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer,
+ const struct hlsl_block *block)
+{
+ const struct hlsl_ir_node *instr;
+
+ LIST_FOR_EACH_ENTRY(instr, &block->instrs, struct hlsl_ir_node, entry)
+ {
+ if (instr->data_type)
+ {
+ if (instr->data_type->type == HLSL_CLASS_MATRIX)
+ {
+ FIXME("Matrix operations need to be lowered.\n");
+ break;
+ }
+ else if (instr->data_type->type == HLSL_CLASS_OBJECT)
+ {
+ hlsl_fixme(ctx, instr->loc, "Object copy.\n");
+ break;
+ }
+
+ assert(instr->data_type->type == HLSL_CLASS_SCALAR || instr->data_type->type == HLSL_CLASS_VECTOR);
+ }
+
+ switch (instr->type)
+ {
+ case HLSL_IR_CONSTANT:
+ write_sm4_constant(ctx, buffer, hlsl_ir_constant(instr));
+ break;
+
+ case HLSL_IR_EXPR:
+ write_sm4_expr(ctx, buffer, hlsl_ir_expr(instr));
+ break;
+
+ case HLSL_IR_LOAD:
+ write_sm4_load(ctx, buffer, hlsl_ir_load(instr));
+ break;
+
+ case HLSL_IR_RESOURCE_LOAD:
+ write_sm4_resource_load(ctx, buffer, hlsl_ir_resource_load(instr));
+ break;
+
+ case HLSL_IR_STORE:
+ write_sm4_store(ctx, buffer, hlsl_ir_store(instr));
+ break;
+
+ case HLSL_IR_SWIZZLE:
+ write_sm4_swizzle(ctx, buffer, hlsl_ir_swizzle(instr));
+ break;
+
+ default:
+ FIXME("Unhandled instruction type %s.\n", hlsl_node_type_to_string(instr->type));
+ }
+ }
+}
+
static void write_sm4_shdr(struct hlsl_ctx *ctx,
const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc)
{
const struct hlsl_profile_info *profile = ctx->profile;
struct vkd3d_bytecode_buffer buffer = {0};
const struct hlsl_buffer *cbuffer;
- const struct hlsl_ir_node *instr;
const struct hlsl_ir_var *var;
size_t token_count_position;
@@ -1553,54 +1607,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx,
if (ctx->temp_count)
write_sm4_dcl_temps(&buffer, ctx->temp_count);
- LIST_FOR_EACH_ENTRY(instr, &entry_func->body.instrs, struct hlsl_ir_node, entry)
- {
- if (instr->data_type)
- {
- if (instr->data_type->type == HLSL_CLASS_MATRIX)
- {
- FIXME("Matrix operations need to be lowered.\n");
- break;
- }
- else if (instr->data_type->type == HLSL_CLASS_OBJECT)
- {
- hlsl_fixme(ctx, instr->loc, "Object copy.\n");
- break;
- }
-
- assert(instr->data_type->type == HLSL_CLASS_SCALAR || instr->data_type->type == HLSL_CLASS_VECTOR);
- }
-
- switch (instr->type)
- {
- case HLSL_IR_CONSTANT:
- write_sm4_constant(ctx, &buffer, hlsl_ir_constant(instr));
- break;
-
- case HLSL_IR_EXPR:
- write_sm4_expr(ctx, &buffer, hlsl_ir_expr(instr));
- break;
-
- case HLSL_IR_LOAD:
- write_sm4_load(ctx, &buffer, hlsl_ir_load(instr));
- break;
-
- case HLSL_IR_RESOURCE_LOAD:
- write_sm4_resource_load(ctx, &buffer, hlsl_ir_resource_load(instr));
- break;
-
- case HLSL_IR_STORE:
- write_sm4_store(ctx, &buffer, hlsl_ir_store(instr));
- break;
-
- case HLSL_IR_SWIZZLE:
- write_sm4_swizzle(ctx, &buffer, hlsl_ir_swizzle(instr));
- break;
-
- default:
- FIXME("Unhandled instruction type %s.\n", hlsl_node_type_to_string(instr->type));
- }
- }
+ write_sm4_block(ctx, &buffer, &entry_func->body);
write_sm4_ret(&buffer);
--
2.33.1
Nov. 3, 2021
[PATCH v2 5/5] winegstreamer: Implement IWMReader::GetOutputProps().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 10 +++++----
dlls/wmvcore/tests/wmvcore.c | 32 +++++++++++------------------
2 files changed, 18 insertions(+), 24 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 8caf21a2de0..6771b590a71 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -114,11 +114,13 @@ static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *count)
return S_OK;
}
-static HRESULT WINAPI WMReader_GetOutputProps(IWMReader *iface, DWORD output_num, IWMOutputMediaProps **output)
+static HRESULT WINAPI WMReader_GetOutputProps(IWMReader *iface, DWORD output, IWMOutputMediaProps **props)
{
- struct async_reader *This = impl_from_IWMReader(iface);
- FIXME("(%p)->(%u %p)\n", This, output_num, output);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReader(iface);
+
+ TRACE("reader %p, output %u, props %p.\n", reader, output, props);
+
+ return wm_reader_get_output_props(&reader->reader, output, props);
}
static HRESULT WINAPI WMReader_SetOutputProps(IWMReader *iface, DWORD output_num, IWMOutputMediaProps *output)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 553f79656d6..148b4f5f373 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1397,12 +1397,7 @@ static void test_async_reader_types(void)
output_number = i;
hr = IWMReader_GetOutputProps(reader, output_number, &output_props);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr != S_OK)
- {
- winetest_pop_context();
- continue;
- }
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
ret_size = sizeof(mt_buffer);
hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size);
@@ -1529,25 +1524,22 @@ static void test_async_reader_types(void)
todo_wine ok(hr == NS_E_INVALID_OUTPUT_FORMAT, "Got hr %#x.\n", hr);
hr = IWMReader_GetOutputProps(reader, output_number, &output_props);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr == S_OK)
- {
- hr = IWMReader_GetOutputProps(reader, output_number, &output_props2);
- ok(hr == S_OK, "Got hr %#x.\n", hr);
- ok(output_props2 != output_props, "Expected different objects.\n");
+ hr = IWMReader_GetOutputProps(reader, output_number, &output_props2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(output_props2 != output_props, "Expected different objects.\n");
- ref = IWMOutputMediaProps_Release(output_props2);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- ref = IWMOutputMediaProps_Release(output_props);
- ok(!ref, "Got outstanding refcount %d.\n", ref);
- }
+ ref = IWMOutputMediaProps_Release(output_props2);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
winetest_pop_context();
}
- todo_wine ok(got_audio, "No audio stream was enumerated.\n");
- todo_wine ok(got_video, "No video stream was enumerated.\n");
+ ok(got_audio, "No audio stream was enumerated.\n");
+ ok(got_video, "No video stream was enumerated.\n");
count = 0xdeadbeef;
hr = IWMReader_GetOutputFormatCount(reader, 2, &count);
@@ -1556,7 +1548,7 @@ static void test_async_reader_types(void)
output_props = (void *)0xdeadbeef;
hr = IWMReader_GetOutputProps(reader, 2, &output_props);
- todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
output_props = (void *)0xdeadbeef;
--
2.33.0
Nov. 3, 2021
[PATCH v2 4/5] winegstreamer: Implement IWMReader::GetOutputCount().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 12 ++++++------
dlls/wmvcore/tests/wmvcore.c | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 3448e156fa0..8caf21a2de0 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -102,15 +102,15 @@ static HRESULT WINAPI WMReader_Close(IWMReader *iface)
return hr;
}
-static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *outputs)
+static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *count)
{
- struct async_reader *This = impl_from_IWMReader(iface);
- FIXME("(%p)->(%p)\n", This, outputs);
+ struct async_reader *reader = impl_from_IWMReader(iface);
- if(!outputs)
- return E_INVALIDARG;
+ TRACE("reader %p, count %p.\n", reader, count);
- *outputs = 0;
+ EnterCriticalSection(&reader->reader.cs);
+ *count = reader->reader.stream_count;
+ LeaveCriticalSection(&reader->reader.cs);
return S_OK;
}
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 9d9c4a571f2..553f79656d6 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1264,7 +1264,7 @@ static void test_async_reader_streaming(void)
count = 0xdeadbeef;
hr = IWMReader_GetOutputCount(reader, &count);
ok(hr == S_OK, "Got hr %#x.\n", hr);
- todo_wine ok(count == 2, "Got count %u.\n", count);
+ ok(count == 2, "Got count %u.\n", count);
for (i = 0; i < 2; ++i)
{
--
2.33.0
Nov. 3, 2021
[PATCH v2 3/5] winegstreamer: Implement IWMReaderAdvanced2::OpenStream().
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/wm_asyncreader.c | 58 +++++++++++++++++++++++++----
dlls/wmvcore/tests/wmvcore.c | 21 +++++------
2 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 4fec89a2100..3448e156fa0 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -31,8 +31,20 @@ struct async_reader
IWMReaderStreamClock IWMReaderStreamClock_iface;
IWMReaderTypeNegotiation IWMReaderTypeNegotiation_iface;
IReferenceClock IReferenceClock_iface;
+
+ IWMReaderCallback *callback;
+ void *context;
};
+static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
+{
+ static const DWORD zero;
+
+ IWMReaderCallback_AddRef(reader->callback = callback);
+ reader->context = context;
+ IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+}
+
static struct async_reader *impl_from_IWMReader(IWMReader *iface)
{
return CONTAINING_RECORD(iface, struct async_reader, IWMReader_iface);
@@ -68,9 +80,26 @@ static HRESULT WINAPI WMReader_Open(IWMReader *iface, const WCHAR *url, IWMReade
static HRESULT WINAPI WMReader_Close(IWMReader *iface)
{
- struct async_reader *This = impl_from_IWMReader(iface);
- FIXME("(%p)\n", This);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReader(iface);
+ static const DWORD zero;
+ HRESULT hr;
+
+ TRACE("reader %p.\n", reader);
+
+ EnterCriticalSection(&reader->reader.cs);
+
+ hr = wm_reader_close(&reader->reader);
+ if (reader->callback)
+ {
+ IWMReaderCallback_OnStatus(reader->callback, WMT_CLOSED, S_OK,
+ WMT_TYPE_DWORD, (BYTE *)&zero, reader->context);
+ IWMReaderCallback_Release(reader->callback);
+ }
+ reader->callback = NULL;
+
+ LeaveCriticalSection(&reader->reader.cs);
+
+ return hr;
}
static HRESULT WINAPI WMReader_GetOutputCount(IWMReader *iface, DWORD *outputs)
@@ -427,12 +456,21 @@ static HRESULT WINAPI WMReaderAdvanced2_StopBuffering(IWMReaderAdvanced6 *iface)
return E_NOTIMPL;
}
-static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface, IStream *stream,
- IWMReaderCallback *callback, void *context)
+static HRESULT WINAPI WMReaderAdvanced2_OpenStream(IWMReaderAdvanced6 *iface,
+ IStream *stream, IWMReaderCallback *callback, void *context)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%p %p %p)\n", This, stream, callback, context);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+ HRESULT hr;
+
+ TRACE("reader %p, stream %p, callback %p, context %p.\n", reader, stream, callback, context);
+
+ EnterCriticalSection(&reader->reader.cs);
+
+ if (SUCCEEDED(hr = wm_reader_open_stream(&reader->reader, stream)))
+ open_stream(reader, callback, context);
+
+ LeaveCriticalSection(&reader->reader.cs);
+ return hr;
}
static HRESULT WINAPI WMReaderAdvanced3_StopNetStreaming(IWMReaderAdvanced6 *iface)
@@ -1256,6 +1294,10 @@ static void async_reader_destroy(struct wm_reader *iface)
TRACE("reader %p.\n", reader);
wm_reader_close(&reader->reader);
+
+ if (reader->callback)
+ IWMReaderCallback_Release(reader->callback);
+
wm_reader_cleanup(&reader->reader);
free(reader);
}
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 8f4cc6eb482..9d9c4a571f2 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -1255,9 +1255,7 @@ static void test_async_reader_streaming(void)
IWMReader_QueryInterface(reader, &IID_IWMReaderAdvanced2, (void **)&advanced);
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr != S_OK)
- goto out;
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
ok(callback.refcount > 1, "Got refcount %d.\n", callback.refcount);
ret = WaitForSingleObject(callback.got_opened, 1000);
@@ -1315,19 +1313,18 @@ static void test_async_reader_streaming(void)
test_reader_attributes(profile);
hr = IWMReader_Close(reader);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
- todo_wine ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed);
ok(callback.refcount == 1, "Got outstanding refcount %d.\n", callback.refcount);
callback_cleanup(&callback);
-out:
ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount);
CloseHandle(stream.file);
ret = DeleteFileW(filename);
ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
hr = IWMReader_Close(reader);
- todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
+ ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
IWMReaderAdvanced2_Release(advanced);
IWMProfile_Release(profile);
@@ -1368,9 +1365,7 @@ static void test_async_reader_types(void)
IWMReader_QueryInterface(reader, &IID_IWMReaderAdvanced2, (void **)&advanced);
hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef);
- todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
- if (hr != S_OK)
- goto out;
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
ok(callback.refcount > 1, "Got refcount %d.\n", callback.refcount);
ret = WaitForSingleObject(callback.got_opened, 1000);
@@ -1403,6 +1398,11 @@ static void test_async_reader_types(void)
hr = IWMReader_GetOutputProps(reader, output_number, &output_props);
todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK)
+ {
+ winetest_pop_context();
+ continue;
+ }
ret_size = sizeof(mt_buffer);
hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size);
@@ -1564,7 +1564,6 @@ static void test_async_reader_types(void)
todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
-out:
IWMReaderAdvanced2_Release(advanced);
IWMProfile_Release(profile);
ref = IWMReader_Release(reader);
--
2.33.0
Nov. 3, 2021
[PATCH v2 2/5] wmvcore/tests: Add tests for asynchronous reader media types.
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/wmvcore/tests/wmvcore.c | 254 ++++++++++++++++++++++++++++++++++-
1 file changed, 253 insertions(+), 1 deletion(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index 2a337648761..8f4cc6eb482 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -34,7 +34,17 @@ HRESULT WINAPI WMCreateWriterPriv(IWMWriter **writer);
static BOOL compare_media_types(const WM_MEDIA_TYPE *a, const WM_MEDIA_TYPE *b)
{
- return !memcmp(a, b, offsetof(WM_MEDIA_TYPE, pbFormat))
+ /* We can't use memcmp(), because WM_MEDIA_TYPE has a hole, which sometimes
+ * contains junk. */
+
+ return IsEqualGUID(&a->majortype, &b->majortype)
+ && IsEqualGUID(&a->subtype, &b->subtype)
+ && a->bFixedSizeSamples == b->bFixedSizeSamples
+ && a->bTemporalCompression == b->bTemporalCompression
+ && a->lSampleSize == b->lSampleSize
+ && IsEqualGUID(&a->formattype, &b->formattype)
+ && a->pUnk == b->pUnk
+ && a->cbFormat == b->cbFormat
&& !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
}
@@ -1325,6 +1335,247 @@ out:
ok(!ref, "Got outstanding refcount %d.\n", ref);
}
+static void test_async_reader_types(void)
+{
+ char mt_buffer[2000], mt2_buffer[2000];
+ const WCHAR *filename = load_resource(L"test.wmv");
+ IWMOutputMediaProps *output_props, *output_props2;
+ WM_MEDIA_TYPE *mt2 = (WM_MEDIA_TYPE *)mt2_buffer;
+ WM_MEDIA_TYPE *mt = (WM_MEDIA_TYPE *)mt_buffer;
+ bool got_video = false, got_audio = false;
+ DWORD size, ret_size, output_number;
+ IWMReaderAdvanced2 *advanced;
+ struct teststream stream;
+ struct callback callback;
+ IWMStreamConfig *config;
+ ULONG count, ref, i, j;
+ IWMProfile *profile;
+ IWMReader *reader;
+ GUID majortype;
+ HANDLE file;
+ HRESULT hr;
+ BOOL ret;
+
+ file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError());
+
+ teststream_init(&stream, file);
+ callback_init(&callback);
+
+ hr = WMCreateReader(NULL, 0, &reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IWMReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile);
+ IWMReader_QueryInterface(reader, &IID_IWMReaderAdvanced2, (void **)&advanced);
+
+ hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK)
+ goto out;
+ ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
+ ok(callback.refcount > 1, "Got refcount %d.\n", callback.refcount);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
+
+ for (i = 0; i < 2; ++i)
+ {
+ winetest_push_context("Stream %u", i);
+
+ hr = IWMProfile_GetStream(profile, i, &config);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IWMStreamConfig_GetStreamType(config, &majortype);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (!i)
+ ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype));
+ else
+ ok(IsEqualGUID(&majortype, &MEDIATYPE_Audio), "Got major type %s.\n", debugstr_guid(&majortype));
+
+ ref = IWMStreamConfig_Release(config);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ winetest_pop_context();
+ }
+
+ for (i = 0; i < 2; ++i)
+ {
+ winetest_push_context("Output %u", i);
+ output_number = i;
+
+ hr = IWMReader_GetOutputProps(reader, output_number, &output_props);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ret_size = sizeof(mt_buffer);
+ hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ majortype = mt->majortype;
+ if (IsEqualGUID(&majortype, &MEDIATYPE_Audio))
+ {
+ got_audio = true;
+ check_audio_type(mt);
+
+ /* R.U.S.E. enumerates all audio formats, picks the first one it
+ * likes, and then sets the wrong stream to that format.
+ * Accordingly we need the first audio format to be the default
+ * format, and we need it to be a format that the game is happy
+ * with. In particular it has to be PCM. */
+
+ hr = IWMReader_GetOutputFormat(reader, output_number, 0, &output_props);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ if (hr == S_OK)
+ {
+ ret_size = sizeof(mt2_buffer);
+ hr = IWMOutputMediaProps_GetMediaType(output_props, mt2, &ret_size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ /* The sample size might differ. */
+ mt2->lSampleSize = mt->lSampleSize;
+ ok(compare_media_types(mt, mt2), "Media types didn't match.\n");
+ }
+ }
+ else
+ {
+ ok(IsEqualGUID(&majortype, &MEDIATYPE_Video), "Got major type %s.\n", debugstr_guid(&majortype));
+ got_video = true;
+ check_video_type(mt);
+ }
+
+ count = 0;
+ hr = IWMReader_GetOutputFormatCount(reader, output_number, &count);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(count > 0, "Got count %u.\n", count);
+
+ for (j = 0; j < count; ++j)
+ {
+ winetest_push_context("Format %u", j);
+
+ hr = IWMReader_GetOutputFormat(reader, output_number, j, &output_props);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IWMReader_GetOutputFormat(reader, output_number, j, &output_props2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(output_props2 != output_props, "Expected different objects.\n");
+ ref = IWMOutputMediaProps_Release(output_props2);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ size = 0xdeadbeef;
+ hr = IWMOutputMediaProps_GetMediaType(output_props, NULL, &size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(size != 0xdeadbeef && size >= sizeof(WM_MEDIA_TYPE), "Got size %u.\n", size);
+
+ ret_size = size - 1;
+ hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size);
+ ok(hr == ASF_E_BUFFERTOOSMALL, "Got hr %#x.\n", hr);
+ ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size);
+
+ ret_size = sizeof(mt_buffer);
+ memset(mt_buffer, 0xcc, sizeof(mt_buffer));
+ hr = IWMOutputMediaProps_GetMediaType(output_props, mt, &ret_size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(ret_size == size, "Expected size %u, got %u.\n", size, ret_size);
+ ok(size == sizeof(WM_MEDIA_TYPE) + mt->cbFormat, "Expected size %u, got %u.\n",
+ sizeof(WM_MEDIA_TYPE) + mt->cbFormat, size);
+
+ ok(IsEqualGUID(&mt->majortype, &majortype), "Got major type %s.\n", debugstr_guid(&mt->majortype));
+
+ if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio))
+ check_audio_type(mt);
+ else
+ check_video_type(mt);
+
+ hr = IWMReader_SetOutputProps(reader, output_number, output_props);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK)
+ {
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ winetest_pop_context();
+ continue;
+ }
+ hr = IWMReader_SetOutputProps(reader, 1 - output_number, output_props);
+ if (!i)
+ ok(hr == NS_E_INCOMPATIBLE_FORMAT /* win < 8, win10 1507-1809 */
+ || hr == ASF_E_BADMEDIATYPE /* win8, win10 1909+ */, "Got hr %#x.\n", hr);
+ else
+ todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
+ hr = IWMReader_SetOutputProps(reader, 2, output_props);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ hr = IWMReader_GetOutputProps(reader, output_number, &output_props2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(output_props2 != output_props, "Expected different objects.\n");
+
+ ret_size = sizeof(mt2_buffer);
+ hr = IWMOutputMediaProps_GetMediaType(output_props2, mt2, &ret_size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(compare_media_types(mt, mt2), "Media types didn't match.\n");
+
+ ref = IWMOutputMediaProps_Release(output_props2);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ winetest_pop_context();
+ }
+
+ hr = IWMReader_GetOutputFormat(reader, output_number, count, &output_props);
+ todo_wine ok(hr == NS_E_INVALID_OUTPUT_FORMAT, "Got hr %#x.\n", hr);
+
+ hr = IWMReader_GetOutputProps(reader, output_number, &output_props);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ if (hr == S_OK)
+ {
+ hr = IWMReader_GetOutputProps(reader, output_number, &output_props2);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(output_props2 != output_props, "Expected different objects.\n");
+
+ ref = IWMOutputMediaProps_Release(output_props2);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IWMOutputMediaProps_Release(output_props);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ }
+
+ winetest_pop_context();
+ }
+
+ todo_wine ok(got_audio, "No audio stream was enumerated.\n");
+ todo_wine ok(got_video, "No video stream was enumerated.\n");
+
+ count = 0xdeadbeef;
+ hr = IWMReader_GetOutputFormatCount(reader, 2, &count);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ ok(count == 0xdeadbeef, "Got count %#x.\n", count);
+
+ output_props = (void *)0xdeadbeef;
+ hr = IWMReader_GetOutputProps(reader, 2, &output_props);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
+
+ output_props = (void *)0xdeadbeef;
+ hr = IWMReader_GetOutputFormat(reader, 2, 0, &output_props);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ ok(output_props == (void *)0xdeadbeef, "Got output props %p.\n", output_props);
+
+out:
+ IWMReaderAdvanced2_Release(advanced);
+ IWMProfile_Release(profile);
+ ref = IWMReader_Release(reader);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount);
+ CloseHandle(stream.file);
+ ret = DeleteFileW(filename);
+ ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
+}
+
START_TEST(wmvcore)
{
HRESULT hr;
@@ -1345,6 +1596,7 @@ START_TEST(wmvcore)
test_sync_reader_types();
test_sync_reader_file();
test_async_reader_streaming();
+ test_async_reader_types();
CoUninitialize();
}
--
2.33.0
Nov. 3, 2021
[PATCH v2 1/5] wmvcore/tests: Add tests for asynchronous reader streaming.
by Zebediah Figura
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/wmvcore/tests/wmvcore.c | 291 ++++++++++++++++++++++++++++++++++-
1 file changed, 283 insertions(+), 8 deletions(-)
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index eae320c4d2e..2a337648761 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -420,6 +420,14 @@ static const IStreamVtbl stream_vtbl =
stream_Clone,
};
+static void teststream_init(struct teststream *stream, HANDLE file)
+{
+ memset(stream, 0, sizeof(*stream));
+ stream->IStream_iface.lpVtbl = &stream_vtbl;
+ stream->refcount = 1;
+ stream->file = file;
+}
+
static void test_reader_attributes(IWMProfile *profile)
{
WORD size, stream_number, ret_stream_number;
@@ -578,7 +586,7 @@ static void test_sync_reader_streaming(void)
WORD stream_numbers[2], stream_number;
IWMStreamConfig *config, *config2;
bool eos[2] = {0}, first = true;
- struct teststream stream = {{0}};
+ struct teststream stream;
ULONG i, j, count, ref;
IWMSyncReader *reader;
IWMProfile *profile;
@@ -592,9 +600,7 @@ static void test_sync_reader_streaming(void)
file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError());
- stream.IStream_iface.lpVtbl = &stream_vtbl;
- stream.refcount = 1;
- stream.file = file;
+ teststream_init(&stream, file);
hr = WMCreateSyncReader(NULL, 0, &reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -816,7 +822,7 @@ static void test_sync_reader_types(void)
bool got_video = false, got_audio = false;
DWORD size, ret_size, output_number;
WORD stream_number, stream_number2;
- struct teststream stream = {{0}};
+ struct teststream stream;
IWMStreamConfig *config;
ULONG count, ref, i, j;
IWMSyncReader *reader;
@@ -829,9 +835,7 @@ static void test_sync_reader_types(void)
file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError());
- stream.IStream_iface.lpVtbl = &stream_vtbl;
- stream.refcount = 1;
- stream.file = file;
+ teststream_init(&stream, file);
hr = WMCreateSyncReader(NULL, 0, &reader);
ok(hr == S_OK, "Got hr %#x.\n", hr);
@@ -1051,6 +1055,276 @@ static void test_sync_reader_file(void)
ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
}
+struct callback
+{
+ IWMReaderCallback IWMReaderCallback_iface;
+ LONG refcount;
+ HANDLE got_opened, got_stopped, eof_event;
+ unsigned int got_closed, got_started, got_sample, got_end_of_streaming, got_eof;
+};
+
+static struct callback *impl_from_IWMReaderCallback(IWMReaderCallback *iface)
+{
+ return CONTAINING_RECORD(iface, struct callback, IWMReaderCallback_iface);
+}
+
+static HRESULT WINAPI callback_QueryInterface(IWMReaderCallback *iface, REFIID iid, void **out)
+{
+ 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));
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI callback_AddRef(IWMReaderCallback *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ return InterlockedIncrement(&callback->refcount);
+}
+
+static ULONG WINAPI callback_Release(IWMReaderCallback *iface)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ return InterlockedDecrement(&callback->refcount);
+}
+
+static HRESULT WINAPI callback_OnStatus(IWMReaderCallback *iface, WMT_STATUS status,
+ HRESULT hr, WMT_ATTR_DATATYPE type, BYTE *value, void *context)
+{
+ struct callback *callback = impl_from_IWMReaderCallback(iface);
+
+ if (winetest_debug > 1)
+ trace("%u: %04x: IWMReaderCallback::OnStatus(status %u, hr %#x, type %#x, value %p)\n",
+ GetTickCount(), GetCurrentThreadId(), status, hr, type, value);
+
+ switch (status)
+ {
+ case WMT_OPENED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context);
+ SetEvent(callback->got_opened);
+ break;
+
+ case WMT_STARTED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ++callback->got_started;
+ break;
+
+ case WMT_STOPPED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ SetEvent(callback->got_stopped);
+ break;
+
+ case WMT_CLOSED:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ todo_wine ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ++callback->got_closed;
+ break;
+
+ case WMT_END_OF_STREAMING:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(!callback->got_eof, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ ++callback->got_end_of_streaming;
+ break;
+
+ case WMT_EOF:
+ ok(type == WMT_TYPE_DWORD, "Got type %#x.\n", type);
+ ok(!*(DWORD *)value, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(callback->got_sample > 0, "Got no samples.\n");
+ ok(callback->got_end_of_streaming == 1, "Got %u WMT_END_OF_STREAMING callbacks.\n",
+ callback->got_end_of_streaming);
+ ++callback->got_eof;
+ SetEvent(callback->eof_event);
+ break;
+
+ /* Not sent when not using IWMReaderAdvanced::DeliverTime(). */
+ case WMT_END_OF_SEGMENT:
+ ok(type == WMT_TYPE_QWORD, "Got type %#x.\n", type);
+ ok(*(QWORD *)value == 3000, "Got value %#x.\n", *(DWORD *)value);
+ ok(context == (void *)0xfacade, "Got unexpected context %p.\n", context);
+ ok(callback->got_sample > 0, "Got no samples.\n");
+ ok(callback->got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback->got_eof);
+ break;
+
+ default:
+ ok(0, "Unexpected status %#x.\n", status);
+ }
+
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ return S_OK;
+}
+
+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);
+ HRESULT hr;
+ DWORD size;
+ BYTE *data;
+
+ 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);
+
+ hr = INSSBuffer_GetBufferAndLength(sample, &data, &size);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ 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 const IWMReaderCallbackVtbl callback_vtbl =
+{
+ callback_QueryInterface,
+ callback_AddRef,
+ callback_Release,
+ callback_OnStatus,
+ callback_OnSample,
+};
+
+static void callback_init(struct callback *callback)
+{
+ memset(callback, 0, sizeof(*callback));
+ callback->IWMReaderCallback_iface.lpVtbl = &callback_vtbl;
+ callback->refcount = 1;
+ callback->got_opened = CreateEventW(NULL, FALSE, FALSE, NULL);
+ callback->got_stopped = CreateEventW(NULL, FALSE, FALSE, NULL);
+ callback->eof_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+}
+
+static void callback_cleanup(struct callback *callback)
+{
+ CloseHandle(callback->got_opened);
+ CloseHandle(callback->got_stopped);
+ CloseHandle(callback->eof_event);
+}
+
+static void test_async_reader_streaming(void)
+{
+ const WCHAR *filename = load_resource(L"test.wmv");
+ IWMReaderAdvanced2 *advanced;
+ struct teststream stream;
+ struct callback callback;
+ IWMStreamConfig *config;
+ WORD stream_numbers[2];
+ IWMProfile *profile;
+ ULONG i, count, ref;
+ IWMReader *reader;
+ HANDLE file;
+ HRESULT hr;
+ BOOL ret;
+
+ file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0);
+ ok(file != INVALID_HANDLE_VALUE, "Failed to open %s, error %u.\n", debugstr_w(file), GetLastError());
+
+ teststream_init(&stream, file);
+ callback_init(&callback);
+
+ hr = WMCreateReader(NULL, 0, &reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IWMReader_QueryInterface(reader, &IID_IWMProfile, (void **)&profile);
+ IWMReader_QueryInterface(reader, &IID_IWMReaderAdvanced2, (void **)&advanced);
+
+ hr = IWMReaderAdvanced2_OpenStream(advanced, &stream.IStream_iface, &callback.IWMReaderCallback_iface, (void **)0xdeadbeef);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ if (hr != S_OK)
+ goto out;
+ ok(stream.refcount > 1, "Got refcount %d.\n", stream.refcount);
+ ok(callback.refcount > 1, "Got refcount %d.\n", callback.refcount);
+ ret = WaitForSingleObject(callback.got_opened, 1000);
+ ok(!ret, "Wait timed out.\n");
+
+ count = 0xdeadbeef;
+ hr = IWMReader_GetOutputCount(reader, &count);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(count == 2, "Got count %u.\n", count);
+
+ for (i = 0; i < 2; ++i)
+ {
+ hr = IWMProfile_GetStream(profile, i, &config);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ stream_numbers[i] = 0xdead;
+ hr = IWMStreamConfig_GetStreamNumber(config, &stream_numbers[i]);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(stream_numbers[i] == i + 1, "Got stream number %u.\n", stream_numbers[i]);
+
+ ref = IWMStreamConfig_Release(config);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ }
+
+ hr = IWMReader_Start(reader, 0, 0, 1.0f, (void *)0xfacade);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ if (hr == S_OK)
+ {
+ /* By default the reader will time itself, and attempt to deliver samples
+ * according to their presentation time. Call DeliverTime with the file
+ * duration in order to request all samples as fast as possible. */
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == E_UNEXPECTED, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_SetUserProvidedClock(advanced, TRUE);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IWMReaderAdvanced2_DeliverTime(advanced, 3000 * 10000);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ ret = WaitForSingleObject(callback.eof_event, 1000);
+ ok(!ret, "Wait timed out.\n");
+ ok(callback.got_eof == 1, "Got %u WMT_EOF callbacks.\n", callback.got_eof);
+
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
+
+ hr = IWMReader_Stop(reader);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ret = WaitForSingleObject(callback.got_stopped, 1000);
+ ok(!ret, "Wait timed out.\n");
+ }
+
+ test_reader_attributes(profile);
+
+ hr = IWMReader_Close(reader);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(callback.got_closed == 1, "Got %u WMT_CLOSED callbacks.\n", callback.got_closed);
+ ok(callback.refcount == 1, "Got outstanding refcount %d.\n", callback.refcount);
+ callback_cleanup(&callback);
+
+out:
+ ok(stream.refcount == 1, "Got outstanding refcount %d.\n", stream.refcount);
+ CloseHandle(stream.file);
+ ret = DeleteFileW(filename);
+ ok(ret, "Failed to delete %s, error %u.\n", debugstr_w(filename), GetLastError());
+
+ hr = IWMReader_Close(reader);
+ todo_wine ok(hr == NS_E_INVALID_REQUEST, "Got hr %#x.\n", hr);
+
+ IWMReaderAdvanced2_Release(advanced);
+ IWMProfile_Release(profile);
+ ref = IWMReader_Release(reader);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+}
+
START_TEST(wmvcore)
{
HRESULT hr;
@@ -1070,6 +1344,7 @@ START_TEST(wmvcore)
test_sync_reader_streaming();
test_sync_reader_types();
test_sync_reader_file();
+ test_async_reader_streaming();
CoUninitialize();
}
--
2.33.0
Nov. 3, 2021
Re: [PATCH v5 3/7] win32u: fix return value of StretchDIBits for EMF DC.
by Jin-oh Kang
On Wed, Nov 3, 2021 at 1:09 AM Jacek Caban <jacek(a)codeweavers.com> wrote:
>
> On 11/2/21 4:46 AM, Jin-oh Kang wrote:
> > On Tue, Nov 2, 2021 at 6:21 AM Jacek Caban <jacek(a)codeweavers.com> wrote:
> >> Hi Jinoh,
> >>
> >> On 11/1/21 6:30 AM, Jinoh Kang wrote:
> >>> Signed-off-by: Jinoh Kang <jinoh.kang.kr(a)gmail.com>
> >>> ---
> >>> dlls/win32u/emfdrv.c | 2 +-
> >>> 1 file changed, 1 insertion(+), 1 deletion(-)
> >>>
> >>> diff --git a/dlls/win32u/emfdrv.c b/dlls/win32u/emfdrv.c
> >>> index e05f11d7b9a..395d51048d8 100644
> >>> --- a/dlls/win32u/emfdrv.c
> >>> +++ b/dlls/win32u/emfdrv.c
> >>> @@ -408,7 +408,7 @@ static INT CDECL EMFDRV_StretchDIBits( PHYSDEV dev, INT x_dst, INT y_dst, INT wi
> >>> UINT wUsage, DWORD dwRop )
> >>> {
> >>> /* FIXME: Update bound rect */
> >>> - return height_src;
> >>> + return abs( info->bmiHeader.biHeight );
> >>> }
> >>>
> >>> static INT CDECL EMFDRV_SetDIBitsToDevice( PHYSDEV dev, INT x_dst, INT y_dst, DWORD width,
> >>
> >> For this and the next patch, you could simply remove
> >> EMFDRV_StretchDIBits and EMFDRV_SetDIBitsToDevice and let the null
> >> driver take care of it.
> > The nulldrv code is still broken w.r.t. BI_RLE[48] case, so I guess
> > that side needs fixing?
>
>
> If it's broken then ideally yes, but not necessarily in this series. A
> quick testing with tests from your patches works fine.
My gdi32 emf tests didn't cover the BI_RLE[48] cases mainly for
brevity reasons--metafile.c was approaching ~10kloc at this point.
Mind if I move all the fixtures to .rc files in the next patch series
where I would (possibly) fix the nulldrv code to match EMF and cover
more pathological cases?
>
>
> >> I originally left it because of bound rect
> >> update (that's supposed to happen in win32u instead of of gdi32), but
> >> that doesn't seem worth keeping it now.
> > I suppose the most ideal way to deal with it is to do normalization
> > early (in either gdi32 or NtGdi* functions) so that the calculation
> > code doesn't have to be duplicated between emfdc.c, EMFDRV and
> > nulldrv. Currently the args are passed as-is to both EMFDC and NtGdi*,
> > and the normalization work is done *twice*.
>
>
> NtGdi* functions generally need to validate input. They are syscalls
> which generally can't trust callers much and we mostly follow what
> Windows does here.
I agree. A thing to note, though, is that in general validation !=
normalisation (although the latter sometimes helps sanitize the
input). It is possible that most normalization is done on the GDI32
side, and win32k.sys accepts whatever it seems as valid. Then again,
this is a pure speculation and I'm not an NT developer.
> It's possible that gdi32.dll should be more involved,
> but we will still need some duplication.
>
>
> EMFDRV is a different story. Most of those functions should probably
> just be removed. They are there because we should move bounding rect
> calculation for EMFs to win32u. However, I later found that there is an
> undocumented generic way to request that for any DC. It's currently not
> implemented, but ideally we'd use that. Once implemented, it should live
> in common DC code, so most of EMFDRV entries will probably not be needed.
>
>
> Thanks,
>
> Jacek
>
Nov. 3, 2021