Wine-devel
Threads by month
- ----- 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
- 756 discussions
15 Nov '21
Signed-off-by: Stefan Dösinger <stefan(a)codeweavers.com>
---
Supersedes 219242.
Version 3: It is color keying, not culling that is randomly applied by old
WARP versions.
---
dlls/ddraw/tests/ddraw1.c | 440 +++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw2.c | 462 +++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw4.c | 467 ++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw7.c | 444 ++++++++++++++++++++++++++++++++++++
4 files changed, 1813 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 0e0a198add2..f9c3634c03e 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -14448,6 +14448,445 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DExecuteBuffer *execute_buffer;
+ D3DEXECUTEBUFFERDESC exec_desc;
+ IDirectDrawSurface *backbuffer;
+ IDirect3DMaterial *background;
+ IDirect3DViewport *viewport;
+ unsigned int inst_length;
+ IDirect3DDevice *device;
+ DWORD colour, expected;
+ unsigned int i, x, y;
+ IDirectDraw *ddraw;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+ void *ptr;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ D3DLVERTEX center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ };
+
+ D3DTLVERTEX center_tris_t[] =
+ {
+ /* left */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD op;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DPROCESSVERTICES_COPY,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DPROCESSVERTICES_COPY,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+ static WORD indices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+
+ window = create_window();
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a 3D device.\n");
+ IDirectDraw_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&backbuffer);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport_set_background(device, viewport, background);
+
+ memset(&exec_desc, 0, sizeof(exec_desc));
+ exec_desc.dwSize = sizeof(exec_desc);
+ exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
+ exec_desc.dwBufferSize = 1024;
+ exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
+
+ hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
+ ok(hr == D3D_OK, "Failed to create execute buffer, hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
+ ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#x.\n", hr);
+
+ /* All test geometry has the same vertex count and vertex size. */
+ memcpy(exec_desc.lpData, tests[i].geometry, sizeof(center_tris));
+ ptr = ((BYTE *)exec_desc.lpData) + sizeof(center_tris);
+ emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
+ /* Old WARP versions (w8, early win10) apply color keying without textures. */
+ emit_set_rs(&ptr, D3DRENDERSTATE_COLORKEYENABLE, FALSE);
+
+ emit_process_vertices(&ptr, tests[i].op, 0, 12);
+ emit_tri_indices(&ptr, indices, 4);
+ emit_end(&ptr);
+ inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
+ inst_length -= sizeof(center_tris);
+
+ hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
+ ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#x.\n", hr);
+
+ set_execute_data(execute_buffer, 12, sizeof(center_tris), inst_length);
+
+ hr = IDirect3DDevice_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(backbuffer, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u.\n",
+ colour, x, y, i);
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface_Release(backbuffer);
+ IDirect3DDevice_Release(device);
+ refcount = IDirectDraw_Release(ddraw);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw1)
{
DDDEVICEIDENTIFIER identifier;
@@ -14565,4 +15004,5 @@ START_TEST(ddraw1)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index a1d4dd942fa..7285c1c3a88 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -15380,6 +15380,467 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ IDirectDrawSurface *rt, *backbuffer, *cur, *ds;
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DMaterial2 *background;
+ IDirect3DViewport2 *viewport;
+ IDirect3DDevice2 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw2 *ddraw;
+ DDSURFACEDESC desc;
+ IDirect3D2 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ D3DLVERTEX center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ };
+
+ D3DTLVERTEX center_tris_t[] =
+ {
+ /* left */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DVT_TLVERTEX,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DVT_TLVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a 3D device.\n");
+ IDirectDraw2_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport_set_background(device, viewport, background);
+ hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw2_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Nvidia on Windows 10 refuses to set the offscreen RT
+ * if it does not have an attached depth stencil. */
+ ds = get_depth_stencil(device);
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ hr = IDirectDrawSurface_GetPixelFormat(ds, &desc.ddpfPixelFormat);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ hr = IDirectDraw2_CreateSurface(ddraw, &desc, &ds, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice2_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice2_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface_Release(backbuffer);
+ IDirectDrawSurface_Release(rt);
+ IDirectDrawSurface_Release(ds);
+ IDirect3D2_Release(d3d);
+ refcount = IDirect3DDevice2_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ refcount = IDirectDraw2_Release(ddraw);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
static void run_for_each_device_type(void (*test_func)(const GUID *))
{
test_func(&IID_IDirect3DHALDevice);
@@ -15509,4 +15970,5 @@ START_TEST(ddraw2)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 4f052256882..07afc44e519 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -18431,6 +18431,472 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ IDirectDrawSurface4 *rt, *backbuffer, *cur, *ds;
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DViewport3 *viewport;
+ IDirect3DDevice3 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw4 *ddraw;
+ DDSURFACEDESC2 desc;
+ IDirect3D3 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_left},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_left},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_top},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_right},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_right},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ };
+
+ struct
+ {
+ struct vec4 position;
+ DWORD diffuse;
+ }
+ center_tris_t[] =
+ {
+ /* left */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_left},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_left},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_right},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_right},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_left},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_left},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_right},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_right},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create 3D device.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw4_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Nvidia on Windows 10 refuses to set the offscreen RT
+ * if it does not have an attached depth stencil. */
+ ds = get_depth_stencil(device);
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ hr = IDirectDrawSurface4_GetPixelFormat(ds, &desc.ddpfPixelFormat);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ hr = IDirectDraw4_CreateSurface(ddraw, &desc, &ds, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface4_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice3_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, colour_clear, 0.0f, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface4_Release(backbuffer);
+ IDirectDrawSurface4_Release(rt);
+ IDirectDrawSurface4_Release(ds);
+ IDirectDraw4_Release(ddraw);
+ IDirect3D3_Release(d3d);
+ refcount = IDirect3DDevice3_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw4)
{
DDDEVICEIDENTIFIER identifier;
@@ -18570,4 +19036,5 @@ START_TEST(ddraw4)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 4402f2d93b5..29fa3434d4b 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -18684,6 +18684,449 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirectDrawSurface7 *rt, *backbuffer, *cur;
+ IDirect3DDevice7 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw7 *ddraw;
+ DDSURFACEDESC2 desc;
+ IDirect3D7 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DVIEWPORT7 vp = { 0, 0, vp_size, vp_size, 0.0, 1.0 };
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_left},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_left},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_top},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_right},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_right},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ };
+
+ struct
+ {
+ struct vec4 position;
+ DWORD diffuse;
+ }
+ center_tris_t[] =
+ {
+ /* left */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_left},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_left},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_right},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_right},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_left},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_left},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_right},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_right},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create 3D device.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw7_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice7_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, colour_clear, 0.0f, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_SetViewport(device, &vp);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ IDirectDrawSurface7_Release(backbuffer);
+ IDirectDrawSurface7_Release(rt);
+ IDirectDraw7_Release(ddraw);
+ IDirect3D7_Release(d3d);
+ refcount = IDirect3DDevice7_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
static void run_for_each_device_type(void (*test_func)(const GUID *))
{
test_func(hw_device_guid);
@@ -18861,4 +19304,5 @@ START_TEST(ddraw7)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
--
2.32.0
3
2
15 Nov '21
Signed-off-by: Stefan Dösinger <stefan(a)codeweavers.com>
---
Version 2: Disable culling to make some Win10 versions happy.
---
dlls/ddraw/tests/ddraw1.c | 439 +++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw2.c | 462 +++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw4.c | 467 ++++++++++++++++++++++++++++++++++++++
dlls/ddraw/tests/ddraw7.c | 444 ++++++++++++++++++++++++++++++++++++
4 files changed, 1812 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 0e0a198add2..a9a10a3b8a0 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -14448,6 +14448,444 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DExecuteBuffer *execute_buffer;
+ D3DEXECUTEBUFFERDESC exec_desc;
+ IDirectDrawSurface *backbuffer;
+ IDirect3DMaterial *background;
+ IDirect3DViewport *viewport;
+ unsigned int inst_length;
+ IDirect3DDevice *device;
+ DWORD colour, expected;
+ unsigned int i, x, y;
+ IDirectDraw *ddraw;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+ void *ptr;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ D3DLVERTEX center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ };
+
+ D3DTLVERTEX center_tris_t[] =
+ {
+ /* left */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD op;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DPROCESSVERTICES_TRANSFORM,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DPROCESSVERTICES_COPY,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DPROCESSVERTICES_COPY,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+ static WORD indices[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+
+ window = create_window();
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a 3D device.\n");
+ IDirectDraw_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice_QueryInterface(device, &IID_IDirectDrawSurface, (void **)&backbuffer);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport_set_background(device, viewport, background);
+
+ memset(&exec_desc, 0, sizeof(exec_desc));
+ exec_desc.dwSize = sizeof(exec_desc);
+ exec_desc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS;
+ exec_desc.dwBufferSize = 1024;
+ exec_desc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY;
+
+ hr = IDirect3DDevice_CreateExecuteBuffer(device, &exec_desc, &execute_buffer, NULL);
+ ok(hr == D3D_OK, "Failed to create execute buffer, hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ hr = IDirect3DViewport_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc);
+ ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#x.\n", hr);
+
+ /* All test geometry has the same vertex count and vertex size. */
+ memcpy(exec_desc.lpData, tests[i].geometry, sizeof(center_tris));
+ ptr = ((BYTE *)exec_desc.lpData) + sizeof(center_tris);
+ emit_set_rs(&ptr, D3DRENDERSTATE_ZENABLE, FALSE);
+ emit_set_rs(&ptr, D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
+
+ emit_process_vertices(&ptr, tests[i].op, 0, 12);
+ emit_tri_indices(&ptr, indices, 4);
+ emit_end(&ptr);
+ inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData;
+ inst_length -= sizeof(center_tris);
+
+ hr = IDirect3DExecuteBuffer_Unlock(execute_buffer);
+ ok(hr == D3D_OK, "Failed to lock execute buffer, hr %#x.\n", hr);
+
+ set_execute_data(execute_buffer, 12, sizeof(center_tris), inst_length);
+
+ hr = IDirect3DDevice_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice_Execute(device, execute_buffer, viewport, D3DEXECUTE_CLIPPED);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(backbuffer, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u.\n",
+ colour, x, y, i);
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface_Release(backbuffer);
+ IDirect3DDevice_Release(device);
+ refcount = IDirectDraw_Release(ddraw);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw1)
{
DDDEVICEIDENTIFIER identifier;
@@ -14565,4 +15003,5 @@ START_TEST(ddraw1)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index a1d4dd942fa..7285c1c3a88 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -15380,6 +15380,467 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ IDirectDrawSurface *rt, *backbuffer, *cur, *ds;
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DMaterial2 *background;
+ IDirect3DViewport2 *viewport;
+ IDirect3DDevice2 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw2 *ddraw;
+ DDSURFACEDESC desc;
+ IDirect3D2 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ D3DLVERTEX center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-0.5f / 4.0f}, { 2.5f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.5f / 4.0f}, { 0.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-0.5f / 4.0f}, {-1.5f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 2.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-eps - 0.0f / 4.0f}, { 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 1.0f / 4.0f}, { 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-eps - 0.0f / 4.0f}, {-1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_left}},
+
+ /* top */
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{-2.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_top}},
+
+ /* right */
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+ {{ 0.0f / 4.0f}, {-eps + 3.0f / 4.0f}, {0.0f}, 0, {colour_right}},
+
+ /* bottom */
+ {{-2.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{-1.0f / 4.0f}, {-eps + 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ {{ 0.0f / 4.0f}, {-eps - 1.0f / 4.0f}, {0.0f}, 0, {colour_bottom}},
+ };
+
+ D3DTLVERTEX center_tris_t[] =
+ {
+ /* left */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_left}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{1.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_top}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{3.5f}, {1.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_right}},
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{2.5f}, {3.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{3.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{1.5f}, {5.5f}, {0.0f}, {1.0f}, {colour_bottom}},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_left}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_left}},
+
+ /* top */
+ {{2.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_top}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_top}},
+
+ /* right */
+ {{4.0f}, {1.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_right}},
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_right}},
+
+ /* bottom */
+ {{3.0f}, {3.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{4.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ {{2.0f}, {5.0f}, {0.0f}, {1.0f}, {colour_bottom}},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DVT_LVERTEX,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DVT_TLVERTEX,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DVT_TLVERTEX,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create a 3D device.\n");
+ IDirectDraw2_Release(ddraw);
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ background = create_diffuse_material(device, 0.0f, 0.0f, 1.0f, 1.0f);
+ viewport_set_background(device, viewport, background);
+ hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw2_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Nvidia on Windows 10 refuses to set the offscreen RT
+ * if it does not have an attached depth stencil. */
+ ds = get_depth_stencil(device);
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ hr = IDirectDrawSurface_GetPixelFormat(ds, &desc.ddpfPixelFormat);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ hr = IDirectDraw2_CreateSurface(ddraw, &desc, &ds, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice2_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice2_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice2_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface_Release(backbuffer);
+ IDirectDrawSurface_Release(rt);
+ IDirectDrawSurface_Release(ds);
+ IDirect3D2_Release(d3d);
+ refcount = IDirect3DDevice2_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ refcount = IDirectDraw2_Release(ddraw);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
static void run_for_each_device_type(void (*test_func)(const GUID *))
{
test_func(&IID_IDirect3DHALDevice);
@@ -15509,4 +15970,5 @@ START_TEST(ddraw2)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 4f052256882..07afc44e519 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -18431,6 +18431,472 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ IDirectDrawSurface4 *rt, *backbuffer, *cur, *ds;
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirect3DViewport3 *viewport;
+ IDirect3DDevice3 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw4 *ddraw;
+ DDSURFACEDESC2 desc;
+ IDirect3D3 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DRECT clear_rect = {{0}, {0}, {vp_size}, {vp_size}};
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_left},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_left},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_top},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_right},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_right},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ };
+
+ struct
+ {
+ struct vec4 position;
+ DWORD diffuse;
+ }
+ center_tris_t[] =
+ {
+ /* left */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_left},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_left},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_right},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_right},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_left},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_left},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_right},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_right},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create 3D device.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice3_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3D3_QueryInterface(d3d, &IID_IDirectDraw4, (void **)&ddraw);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ viewport = create_viewport(device, 0, 0, vp_size, vp_size);
+ hr = IDirect3DDevice3_SetCurrentViewport(device, viewport);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw4_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ /* Nvidia on Windows 10 refuses to set the offscreen RT
+ * if it does not have an attached depth stencil. */
+ ds = get_depth_stencil(device);
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ hr = IDirectDrawSurface4_GetPixelFormat(ds, &desc.ddpfPixelFormat);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ IDirectDrawSurface4_Release(ds);
+
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ hr = IDirectDraw4_CreateSurface(ddraw, &desc, &ds, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface4_AddAttachedSurface(rt, ds);
+ ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice3_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DViewport3_Clear2(viewport, 1, &clear_rect, D3DCLEAR_TARGET, colour_clear, 0.0f, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice3_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice3_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ destroy_viewport(device, viewport);
+ IDirectDrawSurface4_Release(backbuffer);
+ IDirectDrawSurface4_Release(rt);
+ IDirectDrawSurface4_Release(ds);
+ IDirectDraw4_Release(ddraw);
+ IDirect3D3_Release(d3d);
+ refcount = IDirect3DDevice3_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw4)
{
DDDEVICEIDENTIFIER identifier;
@@ -18570,4 +19036,5 @@ START_TEST(ddraw4)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 4402f2d93b5..29fa3434d4b 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -18684,6 +18684,449 @@ static void test_texture_wrong_caps(const GUID *device_guid)
DestroyWindow(window);
}
+static void test_filling_convention(void)
+{
+ static const DWORD colour_bottom = 0x00ffff00;
+ static const DWORD colour_clear = 0x000000ff;
+ static const DWORD colour_right = 0x00000000;
+ static const DWORD colour_left = 0x00ff0000;
+ static const DWORD colour_top = 0x0000ff00;
+ IDirectDrawSurface7 *rt, *backbuffer, *cur;
+ IDirect3DDevice7 *device;
+ unsigned int i, j, x, y;
+ DWORD colour, expected;
+ IDirectDraw7 *ddraw;
+ DDSURFACEDESC2 desc;
+ IDirect3D7 *d3d;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+ BOOL todo;
+
+ static const unsigned int vp_size = 8;
+ D3DVIEWPORT7 vp = { 0, 0, vp_size, vp_size, 0.0, 1.0 };
+
+ /* This test data follows the examples in MSDN's
+ * "Rasterization Rules (Direct3D 9)" article. */
+ static const float eps = 1.0f / 512.0f;
+ struct
+ {
+ struct vec3 position;
+ DWORD diffuse;
+ }
+ center_tris[] =
+ {
+ /* left */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_left},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_left},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_top},
+ {{-2.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_right},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_right},
+ {{-0.5f / 4.0f, 2.5f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.5f / 4.0f, 0.5f / 4.0f, 0.0f}, colour_bottom},
+ {{-0.5f / 4.0f, -1.5f / 4.0f, 0.0f}, colour_bottom},
+
+ },
+ edge_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_right_tris[] =
+ {
+ /* left */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_left_tris[] =
+ {
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 2.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-eps - 0.0f / 4.0f, 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-eps - 2.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 1.0f / 4.0f, 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-eps - 0.0f / 4.0f, -1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_top_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ },
+ nudge_bottom_tris[] =
+ {
+ /* left */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_left},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_left},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_left},
+
+ /* top */
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_top},
+ {{-2.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_top},
+
+ /* right */
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_right},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_right},
+ {{ 0.0f / 4.0f, -eps + 3.0f / 4.0f, 0.0f}, colour_right},
+
+ /* bottom */
+ {{-2.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{-1.0f / 4.0f, -eps + 1.0f / 4.0f, 0.0f}, colour_bottom},
+ {{ 0.0f / 4.0f, -eps - 1.0f / 4.0f, 0.0f}, colour_bottom},
+ };
+
+ struct
+ {
+ struct vec4 position;
+ DWORD diffuse;
+ }
+ center_tris_t[] =
+ {
+ /* left */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_left},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_left},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 1.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_top},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 3.5f, 1.5f, 0.0f, 1.0f}, colour_right},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_right},
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 2.5f, 3.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 3.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ {{ 1.5f, 5.5f, 0.0f, 1.0f}, colour_bottom},
+ },
+ edge_tris_t[] =
+ {
+ /* left */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_left},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_left},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_left},
+
+ /* top */
+ {{ 2.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_top},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_top},
+
+ /* right */
+ {{ 4.0f, 1.0f, 0.0f, 1.0f}, colour_right},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_right},
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_right},
+
+ /* bottom */
+ {{ 3.0f, 3.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 4.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ {{ 2.0f, 5.0f, 0.0f, 1.0f}, colour_bottom},
+ };
+
+ const struct
+ {
+ void *geometry;
+ DWORD fvf;
+ const char *expected[8];
+ }
+ tests[] =
+ {
+ {
+ center_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_right_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " TR ",
+ " LR ",
+ " BR ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_left_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_top_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " LT ",
+ " LT ",
+ " LB ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ {
+ nudge_bottom_tris,
+ D3DFVF_XYZ | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " LT ",
+ " Lt ",
+ " LB ",
+ " lB ",
+ " ",
+ " "
+ }
+ },
+ {
+ center_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " ",
+ " TT ",
+ " LR ",
+ " LR ",
+ " BB ",
+ " ",
+ " "
+ }
+ },
+ {
+ edge_tris_t,
+ D3DFVF_XYZRHW | D3DFVF_DIFFUSE,
+ {
+ " ",
+ " TT ",
+ " LT ",
+ " LR ",
+ " LB ",
+ " ",
+ " ",
+ " "
+ }
+ },
+ };
+
+ window = create_window();
+ if (!(device = create_device(window, DDSCL_NORMAL)))
+ {
+ skip("Failed to create 3D device.\n");
+ DestroyWindow(window);
+ return;
+ }
+
+ hr = IDirect3DDevice7_GetDirect3D(device, &d3d);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3D7_QueryInterface(d3d, &IID_IDirectDraw7, (void **)&ddraw);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_GetRenderTarget(device, &backbuffer);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+ desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+ desc.dwWidth = vp_size;
+ desc.dwHeight = vp_size;
+ desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
+ desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
+ desc.ddpfPixelFormat.dwRGBBitCount = 32;
+ desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
+ desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
+ desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
+ hr = IDirectDraw7_CreateSurface(ddraw, &desc, &rt, NULL);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_LIGHTING, FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i)
+ {
+ for (j = 0; j < 2; ++j)
+ {
+ cur = j ? rt : backbuffer;
+
+ hr = IDirect3DDevice7_SetRenderTarget(device, cur, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_Clear(device, 0, NULL, D3DCLEAR_TARGET, colour_clear, 0.0f, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_SetViewport(device, &vp);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ hr = IDirect3DDevice7_BeginScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_DrawPrimitive(device, D3DPT_TRIANGLELIST,
+ tests[i].fvf, tests[i].geometry, 12, 0);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirect3DDevice7_EndScene(device);
+ ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
+
+ for (y = 0; y < 8; y++)
+ {
+ for (x = 0; x < 8; x++)
+ {
+ todo = FALSE;
+ switch (tests[i].expected[y][x])
+ {
+ case 'l': todo = TRUE;
+ case 'L':
+ expected = colour_left;
+ break;
+ case 't': todo = TRUE;
+ case 'T':
+ expected = colour_top;
+ break;
+ case 'r': todo = TRUE;
+ case 'R':
+ expected = colour_right;
+ break;
+ case 'b': todo = TRUE;
+ case 'B':
+ expected = colour_bottom;
+ break;
+ case ' ':
+ expected = colour_clear;
+ break;
+ default:
+ ok(0, "Unexpected entry in expected test char\n");
+ expected = 0xdeadbeef;
+ }
+ colour = get_surface_color(cur, x, y);
+ /* The nudge-to-bottom test fails on cards that give us a bottom-left
+ * filling convention. The cause isn't the bottom part of the filling
+ * convention, but because wined3d will nudge geometry to the left to
+ * keep diagonals (the 'R' in test case 'edge_tris') intact. */
+ todo_wine_if(todo && !compare_color(colour, expected, 1))
+ ok(compare_color(colour, expected, 1), "Got unexpected colour %08x, %ux%u, case %u, j %u.\n",
+ colour, x, y, i, j);
+ }
+ }
+ }
+ }
+
+ IDirectDrawSurface7_Release(backbuffer);
+ IDirectDrawSurface7_Release(rt);
+ IDirectDraw7_Release(ddraw);
+ IDirect3D7_Release(d3d);
+ refcount = IDirect3DDevice7_Release(device);
+ ok(!refcount, "Device has %u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
static void run_for_each_device_type(void (*test_func)(const GUID *))
{
test_func(hw_device_guid);
@@ -18861,4 +19304,5 @@ START_TEST(ddraw7)
test_window_position();
test_get_display_mode();
run_for_each_device_type(test_texture_wrong_caps);
+ test_filling_convention();
}
--
2.32.0
3
3
[PATCH v2 1/2] kernel32/tests: Add SetCurrentConsoleFontEx tests for the current window size
by Hugh McMaster 15 Nov '21
by Hugh McMaster 15 Nov '21
15 Nov '21
Signed-off-by: Hugh McMaster <hugh.mcmaster(a)outlook.com>
---
Changes in v2:
* Use skip() instead of win_skip() for Unix systems without the test fonts.
dlls/kernel32/tests/console.c | 204 +++++++++++++++++++++++++++++++++-
1 file changed, 202 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/console.c b/dlls/kernel32/tests/console.c
index 8b5abfa2da9..355eb296174 100644
--- a/dlls/kernel32/tests/console.c
+++ b/dlls/kernel32/tests/console.c
@@ -3554,10 +3554,18 @@ static void test_GetCurrentConsoleFontEx(HANDLE std_output)
static void test_SetCurrentConsoleFontEx(HANDLE std_output)
{
- CONSOLE_FONT_INFOEX orig_cfix, cfix;
+ CONSOLE_FONT_INFOEX orig_cfix, cfix, tmp;
BOOL ret;
HANDLE pipe1, pipe2;
HANDLE std_input = GetStdHandle(STD_INPUT_HANDLE);
+ unsigned int i, cp, font_family;
+ const WCHAR *fonts[] = { L"Courier New", L"Liberation Mono" };
+ const WCHAR *face_name;
+
+ font_family = TMPF_VECTOR | TMPF_TRUETYPE | FF_MODERN;
+
+ /* Save current console font information */
+ cp = GetConsoleOutputCP();
orig_cfix.cbSize = sizeof(CONSOLE_FONT_INFOEX);
@@ -3651,17 +3659,209 @@ static void test_SetCurrentConsoleFontEx(HANDLE std_output)
ok(!ret, "got %d, expected 0\n", ret);
todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "got %u, expected 6\n", GetLastError());
+ /* Try setting console font information for the current window size (maxwindow = FALSE) */
+ SetConsoleOutputCP(CP_UTF8);
+
+ cfix.cbSize = sizeof(cfix);
+ cfix.nFont = 0;
+ cfix.dwFontSize.X = 8;
+ cfix.dwFontSize.Y = 16;
+ cfix.FontFamily = font_family;
+ cfix.FontWeight = FW_NORMAL;
+
+ tmp.cbSize = sizeof(tmp);
+
+ /* Courier New is available in the console by default from Windows 10 build 1607 */
+ for (i = 0; i < ARRAY_SIZE(fonts); i++)
+ {
+ face_name = fonts[i];
+ lstrcpyW(cfix.FaceName, face_name);
+
+ SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+
+ if (!lstrcmpW(tmp.FaceName, face_name)) break;
+ }
+
+ if (i == ARRAY_SIZE(fonts))
+ {
+ SetConsoleOutputCP(cp);
+ skip("%s not available. Skipping SetCurrentConsoleFontEx tests.\n", wine_dbgstr_w(face_name));
+ return;
+ }
+
+ /* Test font size 8x16 */
SetLastError(0xdeadbeef);
ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
todo_wine ok(ret, "got %d, expected non-zero\n", ret);
todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == cfix.dwFontSize.X, "got %u, expected font width of %u\n",
+ tmp.dwFontSize.X, cfix.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == cfix.dwFontSize.Y, "got %u, expected font height of %u\n",
+ tmp.dwFontSize.Y, cfix.dwFontSize.Y);
+ todo_wine ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, cfix.FaceName), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(cfix.FaceName));
+
+ /* Test font size 10x20 */
+ cfix.dwFontSize.X = 10;
+ cfix.dwFontSize.Y = 20;
SetLastError(0xdeadbeef);
- ret = SetCurrentConsoleFontEx(std_output, TRUE, &cfix);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == cfix.dwFontSize.X, "got %u, expected font width of %u\n",
+ tmp.dwFontSize.X, cfix.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == cfix.dwFontSize.Y, "got %u, expected font height of %u\n",
+ tmp.dwFontSize.Y, cfix.dwFontSize.Y);
+ todo_wine ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, cfix.FaceName), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(cfix.FaceName));
+
+ /* Test font size 5x12. We pass in 10x12. */
+ cfix.dwFontSize.Y = 12;
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == 5, "got %u, expected font width of 5\n", tmp.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == 12, "got %u, expected font height of 12\n", tmp.dwFontSize.Y);
+ todo_wine ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, cfix.FaceName), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(cfix.FaceName));
+
+ /* Test font size 10x20. Font height is 20. All other metrics are zero. */
+ cfix.dwFontSize.X = 0;
+ cfix.dwFontSize.Y = 20;
+ cfix.FontFamily = 0;
+ cfix.FontWeight = 0;
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == 10, "got %u, expected font width of 10\n", tmp.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == 20, "got %u, expected font height of 20\n", tmp.dwFontSize.Y);
+ todo_wine ok(tmp.FontFamily == font_family, "got %u, expected %u\n", tmp.FontFamily, font_family);
+ ok(tmp.FontWeight == FW_NORMAL, "got %u, expected %u\n", tmp.FontWeight, FW_NORMAL);
+ ok(!lstrcmpW(tmp.FaceName, face_name), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(face_name));
+
+ /* Test font size 7x14. We pass in 7x0. */
+ cfix = tmp;
+ cfix.dwFontSize.X = 7;
+ cfix.dwFontSize.Y = 0;
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
todo_wine ok(ret, "got %d, expected non-zero\n", ret);
todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == 5, "got %u, expected font width of 5\n", tmp.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == 12, "got %u, expected font height of 12\n", tmp.dwFontSize.Y);
+ ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, cfix.FaceName), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(cfix.FaceName));
+
+ /* Test font size with width and height set to 0x0. */
+ cfix.dwFontSize.X = 0;
+ cfix.dwFontSize.Y = 0;
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == 5, "got %u, expected font width of 5\n", tmp.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == 12, "got %u, expected font height of 12\n", tmp.dwFontSize.Y);
+ ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, cfix.FaceName), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(cfix.FaceName));
+
+ /* Test with invalid font face name */
+ cfix.dwFontSize.X = 8;
+ cfix.dwFontSize.Y = 16;
+ lstrcpyW(cfix.FaceName, L"MissingFont");
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == cfix.dwFontSize.X, "got %u, expected font width of %u\n",
+ tmp.dwFontSize.X, cfix.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == cfix.dwFontSize.Y, "got %u, expected font height of %u\n",
+ tmp.dwFontSize.Y, cfix.dwFontSize.Y);
+ ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, face_name), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(face_name));
+
+ /* Test with no font face name */
+ cfix.FaceName[0] = 0;
+ SetLastError(0xdeadbeef);
+ ret = SetCurrentConsoleFontEx(std_output, FALSE, &cfix);
+ todo_wine ok(ret, "got %d, expected non-zero\n", ret);
+ todo_wine ok(GetLastError() == 0xdeadbeef, "got %u, expected 0xdeadbeef\n", GetLastError());
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.cbSize = sizeof(tmp);
+ ret = GetCurrentConsoleFontEx(std_output, FALSE, &tmp);
+ ok(ret, "got %d, expected non-zero\n", ret);
+ ok(tmp.nFont == cfix.nFont, "got %u, expected %u\n", tmp.nFont, cfix.nFont);
+ todo_wine ok(tmp.dwFontSize.X == cfix.dwFontSize.X, "got %u, expected font width of %u\n",
+ tmp.dwFontSize.X, cfix.dwFontSize.X);
+ todo_wine ok(tmp.dwFontSize.Y == cfix.dwFontSize.Y, "got %u, expected font height of %u\n",
+ tmp.dwFontSize.Y, cfix.dwFontSize.Y);
+ ok(tmp.FontFamily == cfix.FontFamily, "got %u, expected %u\n", tmp.FontFamily, cfix.FontFamily);
+ ok(tmp.FontWeight == cfix.FontWeight, "got %u, expected %u\n", tmp.FontWeight, cfix.FontWeight);
+ ok(!lstrcmpW(tmp.FaceName, face_name), "got %s, expected %s\n",
+ wine_dbgstr_w(tmp.FaceName), wine_dbgstr_w(face_name));
+
/* Restore original console font parameters */
+ SetConsoleOutputCP(cp);
+
SetLastError(0xdeadbeef);
ret = SetCurrentConsoleFontEx(std_output, FALSE, &orig_cfix);
todo_wine ok(ret, "got %d, expected non-zero\n", ret);
--
2.33.1
1
1
Signed-off-by: Esme Povirk <esme(a)codeweavers.com>
---
Let's Build a Zoo on Steam creates a temporary file
and expects to be able to delete it while playing it.
dlls/mfplat/main.c | 2 +-
dlls/mfplat/tests/mfplat.c | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 37a66798b2f..c36a2069bd8 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -4407,7 +4407,7 @@ HRESULT WINAPI MFCreateFile(MF_FILE_ACCESSMODE accessmode, MF_FILE_OPENMODE open
{
DWORD capabilities = MFBYTESTREAM_IS_SEEKABLE | MFBYTESTREAM_DOES_NOT_USE_NETWORK;
DWORD filecreation_disposition = 0, fileaccessmode = 0, fileattributes = 0;
- DWORD filesharemode = FILE_SHARE_READ;
+ DWORD filesharemode = FILE_SHARE_READ | FILE_SHARE_DELETE;
struct bytestream *object;
FILETIME writetime;
HANDLE file;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 541459c715b..0f928284534 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -2077,10 +2077,14 @@ static void test_file_stream(void)
hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, pathW, &bytestream);
ok(FAILED(hr), "Unexpected hr %#x.\n", hr);
+ hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &bytestream);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(DeleteFileW(filename), "failed to delete file\n");
+ IMFByteStream_Release(bytestream);
+
hr = MFShutdown();
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
- DeleteFileW(filename);
DeleteFileW(newfilename);
}
--
2.25.1
2
1
15 Nov '21
This was changed from a unsigned int to a pointer in
e5d37832ee66d011ba572a9b571e9fb44a7b2b4d and this use was missed,
causing prefix creation hang if the allocated printers array is not
filled with zeros.
Signed-off-by: Rémi Bernon <rbernon(a)codeweavers.com>
---
I'm also not sure to see why this was changed to a pointer, imho it's
a little more ugly than the integer, which would simply have to be
mapped on output for wow64 too and would have required less changes
overall? But maybe there was a specific reason?
dlls/winspool.drv/info.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 3424c69d196..ac8f0994a1c 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -800,7 +800,7 @@ static BOOL init_unix_printers( void )
if (printer->is_default) default_printer = printer->name;
}
- if (!default_printer && enum_params.num) default_printer = enum_params.printers[0].name;
+ if (!default_printer && num) default_printer = enum_params.printers[0].name;
if (default_printer) SetDefaultPrinterW( default_printer );
if (ppd_dir)
--
2.33.1
3
2
[PATCH 6/6] winecoreaudio: Store the channel count and period_ms directly in the audio client.
by Huw Davies 15 Nov '21
by Huw Davies 15 Nov '21
15 Nov '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winecoreaudio.drv/mmdevdrv.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index ebab18df75b..1e37a2a9026 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -124,6 +124,7 @@ struct ACImpl {
IUnknown *pUnkFTMarshal;
EDataFlow dataflow;
+ UINT32 channel_count, period_ms;
DWORD flags;
HANDLE event;
float *vols;
@@ -1179,7 +1180,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
ACImpl *This = impl_from_IAudioClient3(iface);
HRESULT hr;
OSStatus sc;
- int i;
+ UINT32 i;
TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags,
wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid));
@@ -1342,7 +1343,12 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
This->stream->cap_buffer = HeapAlloc(GetProcessHeap(), 0, This->stream->cap_bufsize_frames * This->stream->fmt->nBlockAlign);
}
- This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
+ This->stream->share = mode;
+ This->flags = flags;
+ This->channel_count = fmt->nChannels;
+ This->period_ms = period / 10000;
+
+ This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float));
if(!This->vols){
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
@@ -1351,12 +1357,9 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
return E_OUTOFMEMORY;
}
- for(i = 0; i < fmt->nChannels; ++i)
+ for(i = 0; i < This->channel_count; ++i)
This->vols[i] = 1.f;
- This->stream->share = mode;
- This->flags = flags;
-
hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
&This->session);
if(FAILED(hr)){
@@ -1906,7 +1909,7 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
if(This->event && !This->timer)
if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb,
- This, 0, This->stream->period_ms, WT_EXECUTEINTIMERTHREAD)){
+ This, 0, This->period_ms, WT_EXECUTEINTIMERTHREAD)){
This->timer = NULL;
OSSpinLockUnlock(&This->stream->lock);
WARN("Unable to create timer: %u\n", GetLastError());
@@ -3173,7 +3176,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
if(!out)
return E_POINTER;
- *out = This->stream->fmt->nChannels;
+ *out = This->channel_count;
return S_OK;
}
@@ -3189,7 +3192,7 @@ static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
- if(index >= This->stream->fmt->nChannels)
+ if(index >= This->channel_count)
return E_INVALIDARG;
EnterCriticalSection(&g_sessions_lock);
@@ -3214,7 +3217,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
if(!level)
return E_POINTER;
- if(index >= This->stream->fmt->nChannels)
+ if(index >= This->channel_count)
return E_INVALIDARG;
*level = This->vols[index];
@@ -3234,7 +3237,7 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->stream->fmt->nChannels)
+ if(count != This->channel_count)
return E_INVALIDARG;
EnterCriticalSection(&g_sessions_lock);
@@ -3260,7 +3263,7 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->stream->fmt->nChannels)
+ if(count != This->channel_count)
return E_INVALIDARG;
EnterCriticalSection(&g_sessions_lock);
--
2.23.0
1
0
[PATCH 5/6] winecoreaudio: Use the global lock to protect the audio client.
by Huw Davies 15 Nov '21
by Huw Davies 15 Nov '21
15 Nov '21
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winecoreaudio.drv/mmdevdrv.c | 115 +++++++++++++++---------------
1 file changed, 59 insertions(+), 56 deletions(-)
diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index e82962db1ba..ebab18df75b 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -1234,16 +1234,19 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
}
}
- OSSpinLockLock(&This->stream->lock);
+ EnterCriticalSection(&g_sessions_lock);
if(This->initted){
- OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return AUDCLNT_E_ALREADY_INITIALIZED;
}
+ OSSpinLockLock(&This->stream->lock);
+
This->stream->fmt = clone_format(fmt);
if(!This->stream->fmt){
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return E_OUTOFMEMORY;
}
@@ -1259,6 +1262,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return hr;
}
@@ -1278,6 +1282,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return osstatus_to_hresult(sc);
}
}else{
@@ -1294,6 +1299,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return osstatus_to_hresult(sc);
}
}
@@ -1308,6 +1314,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return osstatus_to_hresult(sc);
}
@@ -1323,6 +1330,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return osstatus_to_hresult(sc);
}
@@ -1339,6 +1347,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return E_OUTOFMEMORY;
}
@@ -1348,29 +1357,26 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
This->stream->share = mode;
This->flags = flags;
- EnterCriticalSection(&g_sessions_lock);
-
hr = get_audio_session(sessionguid, This->parent, fmt->nChannels,
&This->session);
if(FAILED(hr)){
- LeaveCriticalSection(&g_sessions_lock);
CoTaskMemFree(This->stream->fmt);
This->stream->fmt = NULL;
HeapFree(GetProcessHeap(), 0, This->vols);
This->vols = NULL;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return E_INVALIDARG;
}
list_add_tail(&This->session->clients, &This->entry);
- LeaveCriticalSection(&g_sessions_lock);
-
ca_setvol(This, -1);
This->initted = TRUE;
OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
@@ -1983,41 +1989,35 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
HANDLE event)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ HRESULT hr = S_OK;
TRACE("(%p)->(%p)\n", This, event);
if(!event)
return E_INVALIDARG;
- OSSpinLockLock(&This->stream->lock);
-
- if(!This->initted){
- OSSpinLockUnlock(&This->stream->lock);
- return AUDCLNT_E_NOT_INITIALIZED;
- }
-
- if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
- OSSpinLockUnlock(&This->stream->lock);
- return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
- }
+ EnterCriticalSection(&g_sessions_lock);
- if (This->event){
- OSSpinLockUnlock(&This->stream->lock);
+ if(!This->initted)
+ hr = AUDCLNT_E_NOT_INITIALIZED;
+ else if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))
+ hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
+ else if(This->event){
FIXME("called twice\n");
- return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
- }
-
- This->event = event;
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
+ }else
+ This->event = event;
- OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
- return S_OK;
+ return hr;
}
static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
void **ppv)
{
ACImpl *This = impl_from_IAudioClient3(iface);
+ HRESULT hr;
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
@@ -2025,24 +2025,24 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
return E_POINTER;
*ppv = NULL;
- OSSpinLockLock(&This->stream->lock);
+ EnterCriticalSection(&g_sessions_lock);
if(!This->initted){
- OSSpinLockUnlock(&This->stream->lock);
- return AUDCLNT_E_NOT_INITIALIZED;
+ hr = AUDCLNT_E_NOT_INITIALIZED;
+ goto end;
}
if(IsEqualIID(riid, &IID_IAudioRenderClient)){
if(This->dataflow != eRender){
- OSSpinLockUnlock(&This->stream->lock);
- return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+ hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+ goto end;
}
IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
*ppv = &This->IAudioRenderClient_iface;
}else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
if(This->dataflow != eCapture){
- OSSpinLockUnlock(&This->stream->lock);
- return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+ hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE;
+ goto end;
}
IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
*ppv = &This->IAudioCaptureClient_iface;
@@ -2056,8 +2056,8 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->stream->lock);
- return E_OUTOFMEMORY;
+ hr = E_OUTOFMEMORY;
+ goto end;
}
}else
IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface);
@@ -2067,8 +2067,8 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->stream->lock);
- return E_OUTOFMEMORY;
+ hr = E_OUTOFMEMORY;
+ goto end;
}
}else
IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface);
@@ -2078,8 +2078,8 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->stream->lock);
- return E_OUTOFMEMORY;
+ hr = E_OUTOFMEMORY;
+ goto end;
}
}else
ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface);
@@ -2087,15 +2087,15 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
*ppv = &This->session_wrapper->ISimpleAudioVolume_iface;
}
- if(*ppv){
- OSSpinLockUnlock(&This->stream->lock);
- return S_OK;
+ if(*ppv) hr = S_OK;
+ else{
+ return E_NOINTERFACE;
+ FIXME("stub %s\n", debugstr_guid(riid));
}
- OSSpinLockUnlock(&This->stream->lock);
-
- FIXME("stub %s\n", debugstr_guid(riid));
- return E_NOINTERFACE;
+end:
+ LeaveCriticalSection(&g_sessions_lock);
+ return hr;
}
static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface,
@@ -2749,17 +2749,20 @@ static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
{
AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface);
ULONG ref;
+
+ EnterCriticalSection(&g_sessions_lock);
+
ref = InterlockedDecrement(&This->ref);
TRACE("(%p) Refcount now %u\n", This, ref);
if(!ref){
if(This->client){
- OSSpinLockLock(&This->client->stream->lock);
This->client->session_wrapper = NULL;
- OSSpinLockUnlock(&This->client->stream->lock);
AudioClient_Release(&This->client->IAudioClient3_iface);
}
HeapFree(GetProcessHeap(), 0, This);
}
+
+ LeaveCriticalSection(&g_sessions_lock);
return ref;
}
@@ -3189,14 +3192,14 @@ static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
if(index >= This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->stream->lock);
+ EnterCriticalSection(&g_sessions_lock);
This->vols[index] = level;
WARN("CoreAudio doesn't support per-channel volume control\n");
ret = ca_setvol(This, index);
- OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return ret;
}
@@ -3223,7 +3226,7 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
IAudioStreamVolume *iface, UINT32 count, const float *levels)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
- int i;
+ UINT32 i;
HRESULT ret;
TRACE("(%p)->(%d, %p)\n", This, count, levels);
@@ -3234,14 +3237,14 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
if(count != This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->stream->lock);
+ EnterCriticalSection(&g_sessions_lock);
for(i = 0; i < count; ++i)
This->vols[i] = levels[i];
ret = ca_setvol(This, -1);
- OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return ret;
}
@@ -3250,7 +3253,7 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
IAudioStreamVolume *iface, UINT32 count, float *levels)
{
ACImpl *This = impl_from_IAudioStreamVolume(iface);
- int i;
+ UINT32 i;
TRACE("(%p)->(%d, %p)\n", This, count, levels);
@@ -3260,12 +3263,12 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
if(count != This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->stream->lock);
+ EnterCriticalSection(&g_sessions_lock);
for(i = 0; i < count; ++i)
levels[i] = This->vols[i];
- OSSpinLockUnlock(&This->stream->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
--
2.23.0
1
0
15 Nov '21
Mainly just for simplicity.
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winecoreaudio.drv/mmdevdrv.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index 11be188d110..e82962db1ba 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -96,8 +96,6 @@ typedef struct _AudioSession {
float *channel_vols;
BOOL mute;
- CRITICAL_SECTION lock;
-
struct list entry;
} AudioSession;
@@ -827,9 +825,6 @@ static AudioSession *create_session(const GUID *guid, IMMDevice *device,
list_add_head(&g_sessions, &ret->entry);
- InitializeCriticalSection(&ret->lock);
- ret->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": AudioSession.lock");
-
session_init_vols(ret, num_channels);
ret->master_vol = 1.f;
@@ -3056,13 +3051,13 @@ static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume(
if(context)
FIXME("Notifications not supported yet\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
session->master_vol = level;
ret = ca_session_setvol(session, -1);
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return ret;
}
@@ -3094,13 +3089,13 @@ static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface,
if(context)
FIXME("Notifications not supported yet\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
session->mute = mute;
ca_session_setvol(session, -1);
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
@@ -3356,14 +3351,14 @@ static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume(
if(context)
FIXME("Notifications not supported yet\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
session->channel_vols[index] = level;
WARN("CoreAudio doesn't support per-channel volume control\n");
ret = ca_session_setvol(session, index);
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return ret;
}
@@ -3408,14 +3403,14 @@ static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes(
if(context)
FIXME("Notifications not supported yet\n");
- EnterCriticalSection(&session->lock);
+ EnterCriticalSection(&g_sessions_lock);
for(i = 0; i < count; ++i)
session->channel_vols[i] = levels[i];
ret = ca_session_setvol(session, -1);
- LeaveCriticalSection(&session->lock);
+ LeaveCriticalSection(&g_sessions_lock);
return ret;
}
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winecoreaudio.drv/mmdevdrv.c | 637 +++++++++++++++---------------
dlls/winecoreaudio.drv/unixlib.h | 23 ++
2 files changed, 339 insertions(+), 321 deletions(-)
diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index f8b538971f2..11be188d110 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -125,35 +125,21 @@ struct ACImpl {
IMMDevice *parent;
IUnknown *pUnkFTMarshal;
- WAVEFORMATEX *fmt;
-
EDataFlow dataflow;
DWORD flags;
- AUDCLNT_SHAREMODE share;
HANDLE event;
float *vols;
BOOL initted;
AudioDeviceID adevid;
AudioObjectPropertyScope scope;
- AudioConverterRef converter;
- AudioComponentInstance unit;
- AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */
HANDLE timer;
- UINT32 period_ms, bufsize_frames, period_frames;
- UINT64 written_frames;
- UINT32 lcl_offs_frames, wri_offs_frames, held_frames, tmp_buffer_frames;
- UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames, wrap_bufsize_frames, resamp_bufsize_frames;
- INT32 getbuf_last;
- BOOL playing;
- BYTE *cap_buffer, *wrap_buffer, *resamp_buffer, *local_buffer, *tmp_buffer;
AudioSession *session;
AudioSessionWrapper *session_wrapper;
+ struct coreaudio_stream *stream;
struct list entry;
-
- OSSpinLock lock;
};
static const IAudioClient3Vtbl AudioClient3_Vtbl;
@@ -556,6 +542,11 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACImpl));
if(!This)
return E_OUTOFMEMORY;
+ This->stream = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This->stream));
+ if(!This->stream){
+ HeapFree(GetProcessHeap(), 0, This);
+ return E_OUTOFMEMORY;
+ }
This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl;
This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl;
@@ -571,14 +562,16 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
else if(dataflow == eCapture)
This->scope = kAudioDevicePropertyScopeInput;
else{
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
return E_INVALIDARG;
}
- This->lock = 0;
+ This->stream->lock = 0;
hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal);
if (FAILED(hr)) {
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
return hr;
}
@@ -588,7 +581,8 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient
This->adevid = adevid;
- if(!(This->unit = get_audiounit(This->dataflow, This->adevid))){
+ if(!(This->stream->unit = get_audiounit(This->dataflow, This->adevid))){
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
return AUDCLNT_E_DEVICE_INVALIDATED;
}
@@ -650,24 +644,25 @@ static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface)
WaitForSingleObject(event, INFINITE);
CloseHandle(event);
}
- AudioOutputUnitStop(This->unit);
- AudioComponentInstanceDispose(This->unit);
- if(This->converter)
- AudioConverterDispose(This->converter);
+ AudioOutputUnitStop(This->stream->unit);
+ AudioComponentInstanceDispose(This->stream->unit);
+ if(This->stream->converter)
+ AudioConverterDispose(This->stream->converter);
if(This->session){
EnterCriticalSection(&g_sessions_lock);
list_remove(&This->entry);
LeaveCriticalSection(&g_sessions_lock);
}
HeapFree(GetProcessHeap(), 0, This->vols);
- HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
- HeapFree(GetProcessHeap(), 0, This->cap_buffer);
- HeapFree(GetProcessHeap(), 0, This->local_buffer);
- free(This->wrap_buffer);
- HeapFree(GetProcessHeap(), 0, This->resamp_buffer);
- CoTaskMemFree(This->fmt);
+ HeapFree(GetProcessHeap(), 0, This->stream->tmp_buffer);
+ HeapFree(GetProcessHeap(), 0, This->stream->cap_buffer);
+ HeapFree(GetProcessHeap(), 0, This->stream->local_buffer);
+ free(This->stream->wrap_buffer);
+ HeapFree(GetProcessHeap(), 0, This->stream->resamp_buffer);
+ CoTaskMemFree(This->stream->fmt);
IMMDevice_Release(This->parent);
IUnknown_Release(This->pUnkFTMarshal);
+ HeapFree(GetProcessHeap(), 0, This->stream);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
@@ -890,14 +885,14 @@ static void ca_wrap_buffer(BYTE *dst, UINT32 dst_offs, UINT32 dst_bytes,
static void silence_buffer(ACImpl *This, BYTE *buffer, UINT32 frames)
{
- WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->fmt;
- if((This->fmt->wFormatTag == WAVE_FORMAT_PCM ||
- (This->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)This->stream->fmt;
+ if((This->stream->fmt->wFormatTag == WAVE_FORMAT_PCM ||
+ (This->stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) &&
- This->fmt->wBitsPerSample == 8)
- memset(buffer, 128, frames * This->fmt->nBlockAlign);
+ This->stream->fmt->wBitsPerSample == 8)
+ memset(buffer, 128, frames * This->stream->fmt->nBlockAlign);
else
- memset(buffer, 0, frames * This->fmt->nBlockAlign);
+ memset(buffer, 0, frames * This->stream->fmt->nBlockAlign);
}
/* CA is pulling data from us */
@@ -908,31 +903,31 @@ static OSStatus ca_render_cb(void *user, AudioUnitRenderActionFlags *flags,
ACImpl *This = user;
UINT32 to_copy_bytes, to_copy_frames, chunk_bytes, lcl_offs_bytes;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
- if(This->playing){
- lcl_offs_bytes = This->lcl_offs_frames * This->fmt->nBlockAlign;
- to_copy_frames = min(nframes, This->held_frames);
- to_copy_bytes = to_copy_frames * This->fmt->nBlockAlign;
+ if(This->stream->playing){
+ lcl_offs_bytes = This->stream->lcl_offs_frames * This->stream->fmt->nBlockAlign;
+ to_copy_frames = min(nframes, This->stream->held_frames);
+ to_copy_bytes = to_copy_frames * This->stream->fmt->nBlockAlign;
- chunk_bytes = (This->bufsize_frames - This->lcl_offs_frames) * This->fmt->nBlockAlign;
+ chunk_bytes = (This->stream->bufsize_frames - This->stream->lcl_offs_frames) * This->stream->fmt->nBlockAlign;
if(to_copy_bytes > chunk_bytes){
- memcpy(data->mBuffers[0].mData, This->local_buffer + lcl_offs_bytes, chunk_bytes);
- memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, This->local_buffer, to_copy_bytes - chunk_bytes);
+ memcpy(data->mBuffers[0].mData, This->stream->local_buffer + lcl_offs_bytes, chunk_bytes);
+ memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, This->stream->local_buffer, to_copy_bytes - chunk_bytes);
}else
- memcpy(data->mBuffers[0].mData, This->local_buffer + lcl_offs_bytes, to_copy_bytes);
+ memcpy(data->mBuffers[0].mData, This->stream->local_buffer + lcl_offs_bytes, to_copy_bytes);
- This->lcl_offs_frames += to_copy_frames;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->held_frames -= to_copy_frames;
+ This->stream->lcl_offs_frames += to_copy_frames;
+ This->stream->lcl_offs_frames %= This->stream->bufsize_frames;
+ This->stream->held_frames -= to_copy_frames;
}else
to_copy_bytes = to_copy_frames = 0;
if(nframes > to_copy_frames)
silence_buffer(This, ((BYTE *)data->mBuffers[0].mData) + to_copy_bytes, nframes - to_copy_frames);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return noErr;
}
@@ -950,38 +945,38 @@ static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBuffe
{
ACImpl *This = user;
- *nframes = min(*nframes, This->cap_held_frames);
+ *nframes = min(*nframes, This->stream->cap_held_frames);
if(!*nframes){
data->mBuffers[0].mData = NULL;
data->mBuffers[0].mDataByteSize = 0;
- data->mBuffers[0].mNumberChannels = This->fmt->nChannels;
+ data->mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
return noErr;
}
- data->mBuffers[0].mDataByteSize = *nframes * This->fmt->nBlockAlign;
- data->mBuffers[0].mNumberChannels = This->fmt->nChannels;
+ data->mBuffers[0].mDataByteSize = *nframes * This->stream->fmt->nBlockAlign;
+ data->mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
- if(This->cap_offs_frames + *nframes > This->cap_bufsize_frames){
- UINT32 chunk_frames = This->cap_bufsize_frames - This->cap_offs_frames;
+ if(This->stream->cap_offs_frames + *nframes > This->stream->cap_bufsize_frames){
+ UINT32 chunk_frames = This->stream->cap_bufsize_frames - This->stream->cap_offs_frames;
- if(This->wrap_bufsize_frames < *nframes){
- free(This->wrap_buffer);
- This->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
- This->wrap_bufsize_frames = *nframes;
+ if(This->stream->wrap_bufsize_frames < *nframes){
+ free(This->stream->wrap_buffer);
+ This->stream->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize);
+ This->stream->wrap_bufsize_frames = *nframes;
}
- memcpy(This->wrap_buffer, This->cap_buffer + This->cap_offs_frames * This->fmt->nBlockAlign,
- chunk_frames * This->fmt->nBlockAlign);
- memcpy(This->wrap_buffer + chunk_frames * This->fmt->nBlockAlign, This->cap_buffer,
- (*nframes - chunk_frames) * This->fmt->nBlockAlign);
+ memcpy(This->stream->wrap_buffer, This->stream->cap_buffer + This->stream->cap_offs_frames * This->stream->fmt->nBlockAlign,
+ chunk_frames * This->stream->fmt->nBlockAlign);
+ memcpy(This->stream->wrap_buffer + chunk_frames * This->stream->fmt->nBlockAlign, This->stream->cap_buffer,
+ (*nframes - chunk_frames) * This->stream->fmt->nBlockAlign);
- data->mBuffers[0].mData = This->wrap_buffer;
+ data->mBuffers[0].mData = This->stream->wrap_buffer;
}else
- data->mBuffers[0].mData = This->cap_buffer + This->cap_offs_frames * This->fmt->nBlockAlign;
+ data->mBuffers[0].mData = This->stream->cap_buffer + This->stream->cap_offs_frames * This->stream->fmt->nBlockAlign;
- This->cap_offs_frames += *nframes;
- This->cap_offs_frames %= This->cap_bufsize_frames;
- This->cap_held_frames -= *nframes;
+ This->stream->cap_offs_frames += *nframes;
+ This->stream->cap_offs_frames %= This->stream->cap_bufsize_frames;
+ This->stream->cap_held_frames -= *nframes;
if(packets)
*packets = NULL;
@@ -991,48 +986,48 @@ static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBuffe
static void capture_resample(ACImpl *This)
{
- UINT32 resamp_period_frames = MulDiv(This->period_frames, This->dev_desc.mSampleRate, This->fmt->nSamplesPerSec);
+ UINT32 resamp_period_frames = MulDiv(This->stream->period_frames, This->stream->dev_desc.mSampleRate, This->stream->fmt->nSamplesPerSec);
OSStatus sc;
/* the resampling process often needs more source frames than we'd
* guess from a straight conversion using the sample rate ratio. so
* only convert if we have extra source data. */
- while(This->cap_held_frames > resamp_period_frames * 2){
+ while(This->stream->cap_held_frames > resamp_period_frames * 2){
AudioBufferList converted_list;
- UInt32 wanted_frames = This->period_frames;
+ UInt32 wanted_frames = This->stream->period_frames;
converted_list.mNumberBuffers = 1;
- converted_list.mBuffers[0].mNumberChannels = This->fmt->nChannels;
- converted_list.mBuffers[0].mDataByteSize = wanted_frames * This->fmt->nBlockAlign;
+ converted_list.mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
+ converted_list.mBuffers[0].mDataByteSize = wanted_frames * This->stream->fmt->nBlockAlign;
- if(This->resamp_bufsize_frames < wanted_frames){
- HeapFree(GetProcessHeap(), 0, This->resamp_buffer);
- This->resamp_buffer = HeapAlloc(GetProcessHeap(), 0, converted_list.mBuffers[0].mDataByteSize);
- This->resamp_bufsize_frames = wanted_frames;
+ if(This->stream->resamp_bufsize_frames < wanted_frames){
+ HeapFree(GetProcessHeap(), 0, This->stream->resamp_buffer);
+ This->stream->resamp_buffer = HeapAlloc(GetProcessHeap(), 0, converted_list.mBuffers[0].mDataByteSize);
+ This->stream->resamp_bufsize_frames = wanted_frames;
}
- converted_list.mBuffers[0].mData = This->resamp_buffer;
+ converted_list.mBuffers[0].mData = This->stream->resamp_buffer;
- sc = AudioConverterFillComplexBuffer(This->converter, feed_cb,
+ sc = AudioConverterFillComplexBuffer(This->stream->converter, feed_cb,
This, &wanted_frames, &converted_list, NULL);
if(sc != noErr){
WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc);
break;
}
- ca_wrap_buffer(This->local_buffer,
- This->wri_offs_frames * This->fmt->nBlockAlign,
- This->bufsize_frames * This->fmt->nBlockAlign,
- This->resamp_buffer, wanted_frames * This->fmt->nBlockAlign);
-
- This->wri_offs_frames += wanted_frames;
- This->wri_offs_frames %= This->bufsize_frames;
- if(This->held_frames + wanted_frames > This->bufsize_frames){
- This->lcl_offs_frames += buf_ptr_diff(This->lcl_offs_frames,
- This->wri_offs_frames, This->bufsize_frames);
- This->held_frames = This->bufsize_frames;
+ ca_wrap_buffer(This->stream->local_buffer,
+ This->stream->wri_offs_frames * This->stream->fmt->nBlockAlign,
+ This->stream->bufsize_frames * This->stream->fmt->nBlockAlign,
+ This->stream->resamp_buffer, wanted_frames * This->stream->fmt->nBlockAlign);
+
+ This->stream->wri_offs_frames += wanted_frames;
+ This->stream->wri_offs_frames %= This->stream->bufsize_frames;
+ if(This->stream->held_frames + wanted_frames > This->stream->bufsize_frames){
+ This->stream->lcl_offs_frames += buf_ptr_diff(This->stream->lcl_offs_frames,
+ This->stream->wri_offs_frames, This->stream->bufsize_frames);
+ This->stream->held_frames = This->stream->bufsize_frames;
}else
- This->held_frames += wanted_frames;
+ This->stream->held_frames += wanted_frames;
}
}
@@ -1052,48 +1047,48 @@ static OSStatus ca_capture_cb(void *user, AudioUnitRenderActionFlags *flags,
OSStatus sc;
UINT32 cap_wri_offs_frames;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
- cap_wri_offs_frames = (This->cap_offs_frames + This->cap_held_frames) % This->cap_bufsize_frames;
+ cap_wri_offs_frames = (This->stream->cap_offs_frames + This->stream->cap_held_frames) % This->stream->cap_bufsize_frames;
list.mNumberBuffers = 1;
- list.mBuffers[0].mNumberChannels = This->fmt->nChannels;
- list.mBuffers[0].mDataByteSize = nframes * This->fmt->nBlockAlign;
-
- if(!This->playing || cap_wri_offs_frames + nframes > This->cap_bufsize_frames){
- if(This->wrap_bufsize_frames < nframes){
- free(This->wrap_buffer);
- This->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize);
- This->wrap_bufsize_frames = nframes;
+ list.mBuffers[0].mNumberChannels = This->stream->fmt->nChannels;
+ list.mBuffers[0].mDataByteSize = nframes * This->stream->fmt->nBlockAlign;
+
+ if(!This->stream->playing || cap_wri_offs_frames + nframes > This->stream->cap_bufsize_frames){
+ if(This->stream->wrap_bufsize_frames < nframes){
+ free(This->stream->wrap_buffer);
+ This->stream->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize);
+ This->stream->wrap_bufsize_frames = nframes;
}
- list.mBuffers[0].mData = This->wrap_buffer;
+ list.mBuffers[0].mData = This->stream->wrap_buffer;
}else
- list.mBuffers[0].mData = This->cap_buffer + cap_wri_offs_frames * This->fmt->nBlockAlign;
+ list.mBuffers[0].mData = This->stream->cap_buffer + cap_wri_offs_frames * This->stream->fmt->nBlockAlign;
- sc = AudioUnitRender(This->unit, flags, ts, bus, nframes, &list);
+ sc = AudioUnitRender(This->stream->unit, flags, ts, bus, nframes, &list);
if(sc != noErr){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return sc;
}
- if(This->playing){
- if(list.mBuffers[0].mData == This->wrap_buffer){
- ca_wrap_buffer(This->cap_buffer,
- cap_wri_offs_frames * This->fmt->nBlockAlign,
- This->cap_bufsize_frames * This->fmt->nBlockAlign,
- This->wrap_buffer, list.mBuffers[0].mDataByteSize);
+ if(This->stream->playing){
+ if(list.mBuffers[0].mData == This->stream->wrap_buffer){
+ ca_wrap_buffer(This->stream->cap_buffer,
+ cap_wri_offs_frames * This->stream->fmt->nBlockAlign,
+ This->stream->cap_bufsize_frames * This->stream->fmt->nBlockAlign,
+ This->stream->wrap_buffer, list.mBuffers[0].mDataByteSize);
}
- This->cap_held_frames += list.mBuffers[0].mDataByteSize / This->fmt->nBlockAlign;
- if(This->cap_held_frames > This->cap_bufsize_frames){
- This->cap_offs_frames += This->cap_held_frames % This->cap_bufsize_frames;
- This->cap_offs_frames %= This->cap_bufsize_frames;
- This->cap_held_frames = This->cap_bufsize_frames;
+ This->stream->cap_held_frames += list.mBuffers[0].mDataByteSize / This->stream->fmt->nBlockAlign;
+ if(This->stream->cap_held_frames > This->stream->cap_bufsize_frames){
+ This->stream->cap_offs_frames += This->stream->cap_held_frames % This->stream->cap_bufsize_frames;
+ This->stream->cap_offs_frames %= This->stream->cap_bufsize_frames;
+ This->stream->cap_held_frames = This->stream->cap_bufsize_frames;
}
}
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return noErr;
}
@@ -1244,31 +1239,31 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
}
}
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_ALREADY_INITIALIZED;
}
- This->fmt = clone_format(fmt);
- if(!This->fmt){
- OSSpinLockUnlock(&This->lock);
+ This->stream->fmt = clone_format(fmt);
+ if(!This->stream->fmt){
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
- This->period_ms = period / 10000;
- This->period_frames = MulDiv(period, This->fmt->nSamplesPerSec, 10000000);
+ This->stream->period_ms = period / 10000;
+ This->stream->period_frames = MulDiv(period, This->stream->fmt->nSamplesPerSec, 10000000);
- This->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
+ This->stream->bufsize_frames = MulDiv(duration, fmt->nSamplesPerSec, 10000000);
if(mode == AUDCLNT_SHAREMODE_EXCLUSIVE)
- This->bufsize_frames -= This->bufsize_frames % This->period_frames;
+ This->stream->bufsize_frames -= This->stream->bufsize_frames % This->stream->period_frames;
- hr = ca_setup_audiounit(This->dataflow, This->unit, This->fmt, &This->dev_desc, &This->converter);
+ hr = ca_setup_audiounit(This->dataflow, This->stream->unit, This->stream->fmt, &This->stream->dev_desc, &This->stream->converter);
if(FAILED(hr)){
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return hr;
}
@@ -1279,15 +1274,15 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
input.inputProc = &ca_capture_cb;
input.inputProcRefCon = This;
- sc = AudioUnitSetProperty(This->unit, kAudioOutputUnitProperty_SetInputCallback,
+ sc = AudioUnitSetProperty(This->stream->unit, kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Output, 1, &input, sizeof(input));
if(sc != noErr){
WARN("Couldn't set callback: %x\n", (int)sc);
- AudioConverterDispose(This->converter);
- This->converter = NULL;
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ AudioConverterDispose(This->stream->converter);
+ This->stream->converter = NULL;
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return osstatus_to_hresult(sc);
}
}else{
@@ -1297,65 +1292,65 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
input.inputProc = &ca_render_cb;
input.inputProcRefCon = This;
- sc = AudioUnitSetProperty(This->unit, kAudioUnitProperty_SetRenderCallback,
+ sc = AudioUnitSetProperty(This->stream->unit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0, &input, sizeof(input));
if(sc != noErr){
WARN("Couldn't set callback: %x\n", (int)sc);
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return osstatus_to_hresult(sc);
}
}
- sc = AudioUnitInitialize(This->unit);
+ sc = AudioUnitInitialize(This->stream->unit);
if(sc != noErr){
WARN("Couldn't initialize: %x\n", (int)sc);
- if(This->converter){
- AudioConverterDispose(This->converter);
- This->converter = NULL;
+ if(This->stream->converter){
+ AudioConverterDispose(This->stream->converter);
+ This->stream->converter = NULL;
}
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return osstatus_to_hresult(sc);
}
/* we play audio continuously because AudioOutputUnitStart sometimes takes
* a while to return */
- sc = AudioOutputUnitStart(This->unit);
+ sc = AudioOutputUnitStart(This->stream->unit);
if(sc != noErr){
WARN("Unit failed to start: %x\n", (int)sc);
- if(This->converter){
- AudioConverterDispose(This->converter);
- This->converter = NULL;
+ if(This->stream->converter){
+ AudioConverterDispose(This->stream->converter);
+ This->stream->converter = NULL;
}
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return osstatus_to_hresult(sc);
}
- This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_frames * fmt->nBlockAlign);
- silence_buffer(This, This->local_buffer, This->bufsize_frames);
+ This->stream->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->stream->bufsize_frames * fmt->nBlockAlign);
+ silence_buffer(This, This->stream->local_buffer, This->stream->bufsize_frames);
if(This->dataflow == eCapture){
- This->cap_bufsize_frames = MulDiv(duration, This->dev_desc.mSampleRate, 10000000);
- This->cap_buffer = HeapAlloc(GetProcessHeap(), 0, This->cap_bufsize_frames * This->fmt->nBlockAlign);
+ This->stream->cap_bufsize_frames = MulDiv(duration, This->stream->dev_desc.mSampleRate, 10000000);
+ This->stream->cap_buffer = HeapAlloc(GetProcessHeap(), 0, This->stream->cap_bufsize_frames * This->stream->fmt->nBlockAlign);
}
This->vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float));
if(!This->vols){
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
- OSSpinLockUnlock(&This->lock);
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
for(i = 0; i < fmt->nChannels; ++i)
This->vols[i] = 1.f;
- This->share = mode;
+ This->stream->share = mode;
This->flags = flags;
EnterCriticalSection(&g_sessions_lock);
@@ -1364,11 +1359,11 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
&This->session);
if(FAILED(hr)){
LeaveCriticalSection(&g_sessions_lock);
- CoTaskMemFree(This->fmt);
- This->fmt = NULL;
+ CoTaskMemFree(This->stream->fmt);
+ This->stream->fmt = NULL;
HeapFree(GetProcessHeap(), 0, This->vols);
This->vols = NULL;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return E_INVALIDARG;
}
@@ -1380,7 +1375,7 @@ static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface,
This->initted = TRUE;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1395,16 +1390,16 @@ static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface,
if(!frames)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
- *frames = This->bufsize_frames;
+ *frames = This->stream->bufsize_frames;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1477,10 +1472,10 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
if(!out)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
@@ -1493,23 +1488,23 @@ static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface,
&size, &latency);
if(sc != noErr){
WARN("Couldn't get _Latency property: %x\n", (int)sc);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return osstatus_to_hresult(sc);
}
hr = ca_get_max_stream_latency(This, &stream_latency);
if(FAILED(hr)){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return hr;
}
latency += stream_latency;
/* pretend we process audio in Period chunks, so max latency includes
* the period time */
- *out = MulDiv(latency, 10000000, This->fmt->nSamplesPerSec)
- + This->period_ms * 10000;
+ *out = MulDiv(latency, 10000000, This->stream->fmt->nSamplesPerSec)
+ + This->stream->period_ms * 10000;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1523,7 +1518,7 @@ static HRESULT AudioClient_GetCurrentPadding_nolock(ACImpl *This,
if(This->dataflow == eCapture)
capture_resample(This);
- *numpad = This->held_frames;
+ *numpad = This->stream->held_frames;
return S_OK;
}
@@ -1539,11 +1534,11 @@ static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface,
if(!numpad)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
hr = AudioClient_GetCurrentPadding_nolock(This, numpad);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return hr;
}
@@ -1891,35 +1886,35 @@ static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface)
TRACE("(%p)\n", This);
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(This->playing){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->playing){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_STOPPED;
}
if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_EVENTHANDLE_NOT_SET;
}
if(This->event && !This->timer)
if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb,
- This, 0, This->period_ms, WT_EXECUTEINTIMERTHREAD)){
+ This, 0, This->stream->period_ms, WT_EXECUTEINTIMERTHREAD)){
This->timer = NULL;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
WARN("Unable to create timer: %u\n", GetLastError());
return E_OUTOFMEMORY;
}
- This->playing = TRUE;
+ This->stream->playing = TRUE;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1930,21 +1925,21 @@ static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface)
TRACE("(%p)\n", This);
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(!This->playing){
- OSSpinLockUnlock(&This->lock);
+ if(!This->stream->playing){
+ OSSpinLockUnlock(&This->stream->lock);
return S_FALSE;
}
- This->playing = FALSE;
+ This->stream->playing = FALSE;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1955,36 +1950,36 @@ static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface)
TRACE("(%p)\n", This);
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
- if(This->playing){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->playing){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_STOPPED;
}
- if(This->getbuf_last){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->getbuf_last){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_BUFFER_OPERATION_PENDING;
}
if(This->dataflow == eRender){
- This->written_frames = 0;
+ This->stream->written_frames = 0;
}else{
- This->written_frames += This->held_frames;
+ This->stream->written_frames += This->stream->held_frames;
}
- This->held_frames = 0;
- This->lcl_offs_frames = 0;
- This->wri_offs_frames = 0;
- This->cap_offs_frames = 0;
- This->cap_held_frames = 0;
+ This->stream->held_frames = 0;
+ This->stream->lcl_offs_frames = 0;
+ This->stream->wri_offs_frames = 0;
+ This->stream->cap_offs_frames = 0;
+ This->stream->cap_held_frames = 0;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -1999,27 +1994,27 @@ static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface,
if(!event)
return E_INVALIDARG;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED;
}
if (This->event){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
FIXME("called twice\n");
return HRESULT_FROM_WIN32(ERROR_INVALID_NAME);
}
This->event = event;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2035,23 +2030,23 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
return E_POINTER;
*ppv = NULL;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!This->initted){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_NOT_INITIALIZED;
}
if(IsEqualIID(riid, &IID_IAudioRenderClient)){
if(This->dataflow != eRender){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
}
IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface);
*ppv = &This->IAudioRenderClient_iface;
}else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){
if(This->dataflow != eCapture){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_WRONG_ENDPOINT_TYPE;
}
IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface);
@@ -2066,7 +2061,7 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
}else
@@ -2077,7 +2072,7 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
}else
@@ -2088,7 +2083,7 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
if(!This->session_wrapper){
This->session_wrapper = AudioSessionWrapper_Create(This);
if(!This->session_wrapper){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
}else
@@ -2098,11 +2093,11 @@ static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid,
}
if(*ppv){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
FIXME("stub %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
@@ -2274,49 +2269,49 @@ static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface,
return E_POINTER;
*data = NULL;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
- if(This->getbuf_last){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->getbuf_last){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
if(!frames){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
hr = AudioClient_GetCurrentPadding_nolock(This, &pad);
if(FAILED(hr)){
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return hr;
}
- if(pad + frames > This->bufsize_frames){
- OSSpinLockUnlock(&This->lock);
+ if(pad + frames > This->stream->bufsize_frames){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_BUFFER_TOO_LARGE;
}
- if(This->wri_offs_frames + frames > This->bufsize_frames){
- if(This->tmp_buffer_frames < frames){
- HeapFree(GetProcessHeap(), 0, This->tmp_buffer);
- This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, frames * This->fmt->nBlockAlign);
- if(!This->tmp_buffer){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->wri_offs_frames + frames > This->stream->bufsize_frames){
+ if(This->stream->tmp_buffer_frames < frames){
+ HeapFree(GetProcessHeap(), 0, This->stream->tmp_buffer);
+ This->stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, frames * This->stream->fmt->nBlockAlign);
+ if(!This->stream->tmp_buffer){
+ OSSpinLockUnlock(&This->stream->lock);
return E_OUTOFMEMORY;
}
- This->tmp_buffer_frames = frames;
+ This->stream->tmp_buffer_frames = frames;
}
- *data = This->tmp_buffer;
- This->getbuf_last = -frames;
+ *data = This->stream->tmp_buffer;
+ This->stream->getbuf_last = -frames;
}else{
- *data = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
- This->getbuf_last = frames;
+ *data = This->stream->local_buffer + This->stream->wri_offs_frames * This->stream->fmt->nBlockAlign;
+ This->stream->getbuf_last = frames;
}
silence_buffer(This, *data, frames);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2329,46 +2324,46 @@ static HRESULT WINAPI AudioRenderClient_ReleaseBuffer(
TRACE("(%p)->(%u, %x)\n", This, frames, flags);
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!frames){
- This->getbuf_last = 0;
- OSSpinLockUnlock(&This->lock);
+ This->stream->getbuf_last = 0;
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
- if(!This->getbuf_last){
- OSSpinLockUnlock(&This->lock);
+ if(!This->stream->getbuf_last){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
- if(frames > (This->getbuf_last >= 0 ? This->getbuf_last : -This->getbuf_last)){
- OSSpinLockUnlock(&This->lock);
+ if(frames > (This->stream->getbuf_last >= 0 ? This->stream->getbuf_last : -This->stream->getbuf_last)){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_INVALID_SIZE;
}
- if(This->getbuf_last >= 0)
- buffer = This->local_buffer + This->wri_offs_frames * This->fmt->nBlockAlign;
+ if(This->stream->getbuf_last >= 0)
+ buffer = This->stream->local_buffer + This->stream->wri_offs_frames * This->stream->fmt->nBlockAlign;
else
- buffer = This->tmp_buffer;
+ buffer = This->stream->tmp_buffer;
if(flags & AUDCLNT_BUFFERFLAGS_SILENT)
silence_buffer(This, buffer, frames);
- if(This->getbuf_last < 0)
- ca_wrap_buffer(This->local_buffer,
- This->wri_offs_frames * This->fmt->nBlockAlign,
- This->bufsize_frames * This->fmt->nBlockAlign,
- buffer, frames * This->fmt->nBlockAlign);
+ if(This->stream->getbuf_last < 0)
+ ca_wrap_buffer(This->stream->local_buffer,
+ This->stream->wri_offs_frames * This->stream->fmt->nBlockAlign,
+ This->stream->bufsize_frames * This->stream->fmt->nBlockAlign,
+ buffer, frames * This->stream->fmt->nBlockAlign);
- This->wri_offs_frames += frames;
- This->wri_offs_frames %= This->bufsize_frames;
- This->held_frames += frames;
- This->written_frames += frames;
- This->getbuf_last = 0;
+ This->stream->wri_offs_frames += frames;
+ This->stream->wri_offs_frames %= This->stream->bufsize_frames;
+ This->stream->held_frames += frames;
+ This->stream->written_frames += frames;
+ This->stream->getbuf_last = 0;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2436,38 +2431,38 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
if(!frames || !flags)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
- if(This->getbuf_last){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->getbuf_last){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
capture_resample(This);
- if(This->held_frames < This->period_frames){
+ if(This->stream->held_frames < This->stream->period_frames){
*frames = 0;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_S_BUFFER_EMPTY;
}
*flags = 0;
- chunk_frames = This->bufsize_frames - This->lcl_offs_frames;
- if(chunk_frames < This->period_frames){
- chunk_bytes = chunk_frames * This->fmt->nBlockAlign;
- if(!This->tmp_buffer)
- This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->period_frames * This->fmt->nBlockAlign);
- *data = This->tmp_buffer;
- memcpy(*data, This->local_buffer + This->lcl_offs_frames * This->fmt->nBlockAlign, chunk_bytes);
- memcpy((*data) + chunk_bytes, This->local_buffer, This->period_frames * This->fmt->nBlockAlign - chunk_bytes);
+ chunk_frames = This->stream->bufsize_frames - This->stream->lcl_offs_frames;
+ if(chunk_frames < This->stream->period_frames){
+ chunk_bytes = chunk_frames * This->stream->fmt->nBlockAlign;
+ if(!This->stream->tmp_buffer)
+ This->stream->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, This->stream->period_frames * This->stream->fmt->nBlockAlign);
+ *data = This->stream->tmp_buffer;
+ memcpy(*data, This->stream->local_buffer + This->stream->lcl_offs_frames * This->stream->fmt->nBlockAlign, chunk_bytes);
+ memcpy((*data) + chunk_bytes, This->stream->local_buffer, This->stream->period_frames * This->stream->fmt->nBlockAlign - chunk_bytes);
}else
- *data = This->local_buffer + This->lcl_offs_frames * This->fmt->nBlockAlign;
+ *data = This->stream->local_buffer + This->stream->lcl_offs_frames * This->stream->fmt->nBlockAlign;
- This->getbuf_last = *frames = This->period_frames;
+ This->stream->getbuf_last = *frames = This->stream->period_frames;
if(devpos)
- *devpos = This->written_frames;
+ *devpos = This->stream->written_frames;
if(qpcpos){ /* fixme: qpc of recording time */
LARGE_INTEGER stamp, freq;
QueryPerformanceCounter(&stamp);
@@ -2475,7 +2470,7 @@ static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface,
*qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart;
}
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2487,31 +2482,31 @@ static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer(
TRACE("(%p)->(%u)\n", This, done);
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
if(!done){
- This->getbuf_last = 0;
- OSSpinLockUnlock(&This->lock);
+ This->stream->getbuf_last = 0;
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
- if(!This->getbuf_last){
- OSSpinLockUnlock(&This->lock);
+ if(!This->stream->getbuf_last){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_OUT_OF_ORDER;
}
- if(This->getbuf_last != done){
- OSSpinLockUnlock(&This->lock);
+ if(This->stream->getbuf_last != done){
+ OSSpinLockUnlock(&This->stream->lock);
return AUDCLNT_E_INVALID_SIZE;
}
- This->written_frames += done;
- This->held_frames -= done;
- This->lcl_offs_frames += done;
- This->lcl_offs_frames %= This->bufsize_frames;
- This->getbuf_last = 0;
+ This->stream->written_frames += done;
+ This->stream->held_frames -= done;
+ This->stream->lcl_offs_frames += done;
+ This->stream->lcl_offs_frames %= This->stream->bufsize_frames;
+ This->stream->getbuf_last = 0;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2526,16 +2521,16 @@ static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize(
if(!frames)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
capture_resample(This);
- if(This->held_frames >= This->period_frames)
- *frames = This->period_frames;
+ if(This->stream->held_frames >= This->stream->period_frames)
+ *frames = This->stream->period_frames;
else
*frames = 0;
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
@@ -2592,10 +2587,10 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
TRACE("(%p)->(%p)\n", This, freq);
- if(This->share == AUDCLNT_SHAREMODE_SHARED)
- *freq = (UINT64)This->fmt->nSamplesPerSec * This->fmt->nBlockAlign;
+ if(This->stream->share == AUDCLNT_SHAREMODE_SHARED)
+ *freq = (UINT64)This->stream->fmt->nSamplesPerSec * This->stream->fmt->nBlockAlign;
else
- *freq = This->fmt->nSamplesPerSec;
+ *freq = This->stream->fmt->nSamplesPerSec;
return S_OK;
}
@@ -2603,10 +2598,10 @@ static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq)
static HRESULT AudioClock_GetPosition_nolock(ACImpl *This,
UINT64 *pos, UINT64 *qpctime)
{
- *pos = This->written_frames - This->held_frames;
+ *pos = This->stream->written_frames - This->stream->held_frames;
- if(This->share == AUDCLNT_SHAREMODE_SHARED)
- *pos *= This->fmt->nBlockAlign;
+ if(This->stream->share == AUDCLNT_SHAREMODE_SHARED)
+ *pos *= This->stream->fmt->nBlockAlign;
if(qpctime){
LARGE_INTEGER stamp, freq;
@@ -2629,11 +2624,11 @@ static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos,
if(!pos)
return E_POINTER;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
hr = AudioClock_GetPosition_nolock(This, pos, qpctime);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return hr;
}
@@ -2763,9 +2758,9 @@ static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface)
TRACE("(%p) Refcount now %u\n", This, ref);
if(!ref){
if(This->client){
- OSSpinLockLock(&This->client->lock);
+ OSSpinLockLock(&This->client->stream->lock);
This->client->session_wrapper = NULL;
- OSSpinLockUnlock(&This->client->lock);
+ OSSpinLockUnlock(&This->client->stream->lock);
AudioClient_Release(&This->client->IAudioClient3_iface);
}
HeapFree(GetProcessHeap(), 0, This);
@@ -2793,14 +2788,14 @@ static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface,
}
LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){
- OSSpinLockLock(&client->lock);
- if(client->playing){
+ OSSpinLockLock(&client->stream->lock);
+ if(client->stream->playing){
*state = AudioSessionStateActive;
- OSSpinLockUnlock(&client->lock);
+ OSSpinLockUnlock(&client->stream->lock);
LeaveCriticalSection(&g_sessions_lock);
return S_OK;
}
- OSSpinLockUnlock(&client->lock);
+ OSSpinLockUnlock(&client->stream->lock);
}
LeaveCriticalSection(&g_sessions_lock);
@@ -2979,7 +2974,7 @@ static HRESULT ca_setvol(ACImpl *This, UINT32 index)
if(index == (UINT32)-1){
UINT32 i;
level = 1.;
- for(i = 0; i < This->fmt->nChannels; ++i){
+ for(i = 0; i < This->stream->fmt->nChannels; ++i){
Float32 tmp;
tmp = This->session->master_vol *
This->session->channel_vols[i] * This->vols[i];
@@ -2990,7 +2985,7 @@ static HRESULT ca_setvol(ACImpl *This, UINT32 index)
This->session->channel_vols[index] * This->vols[index];
}
- sc = AudioUnitSetParameter(This->unit, kHALOutputParam_Volume,
+ sc = AudioUnitSetParameter(This->stream->unit, kHALOutputParam_Volume,
kAudioUnitScope_Global, 0, level, 0);
if(sc != noErr)
WARN("Couldn't set volume: %x\n", (int)sc);
@@ -3180,7 +3175,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelCount(
if(!out)
return E_POINTER;
- *out = This->fmt->nChannels;
+ *out = This->stream->fmt->nChannels;
return S_OK;
}
@@ -3196,17 +3191,17 @@ static HRESULT WINAPI AudioStreamVolume_SetChannelVolume(
if(level < 0.f || level > 1.f)
return E_INVALIDARG;
- if(index >= This->fmt->nChannels)
+ if(index >= This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
This->vols[index] = level;
WARN("CoreAudio doesn't support per-channel volume control\n");
ret = ca_setvol(This, index);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return ret;
}
@@ -3221,7 +3216,7 @@ static HRESULT WINAPI AudioStreamVolume_GetChannelVolume(
if(!level)
return E_POINTER;
- if(index >= This->fmt->nChannels)
+ if(index >= This->stream->fmt->nChannels)
return E_INVALIDARG;
*level = This->vols[index];
@@ -3241,17 +3236,17 @@ static HRESULT WINAPI AudioStreamVolume_SetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->fmt->nChannels)
+ if(count != This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
for(i = 0; i < count; ++i)
This->vols[i] = levels[i];
ret = ca_setvol(This, -1);
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return ret;
}
@@ -3267,15 +3262,15 @@ static HRESULT WINAPI AudioStreamVolume_GetAllVolumes(
if(!levels)
return E_POINTER;
- if(count != This->fmt->nChannels)
+ if(count != This->stream->fmt->nChannels)
return E_INVALIDARG;
- OSSpinLockLock(&This->lock);
+ OSSpinLockLock(&This->stream->lock);
for(i = 0; i < count; ++i)
levels[i] = This->vols[i];
- OSSpinLockUnlock(&This->lock);
+ OSSpinLockUnlock(&This->stream->lock);
return S_OK;
}
diff --git a/dlls/winecoreaudio.drv/unixlib.h b/dlls/winecoreaudio.drv/unixlib.h
index 7c1200464b9..6a991f1de98 100644
--- a/dlls/winecoreaudio.drv/unixlib.h
+++ b/dlls/winecoreaudio.drv/unixlib.h
@@ -18,6 +18,29 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+struct coreaudio_stream /* To be made private */
+{
+ OSSpinLock lock;
+ AudioComponentInstance unit;
+ AudioConverterRef converter;
+ AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */
+ AudioDeviceID dev_id;
+ EDataFlow flow;
+ AUDCLNT_SHAREMODE share;
+
+ BOOL playing;
+ SIZE_T local_buffer_size, tmp_buffer_size;
+ UINT32 period_ms, period_frames;
+ UINT32 bufsize_frames, resamp_bufsize_frames;
+ UINT32 lcl_offs_frames, held_frames, wri_offs_frames, tmp_buffer_frames;
+ UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames;
+ UINT32 wrap_bufsize_frames;
+ UINT64 written_frames;
+ INT32 getbuf_last;
+ WAVEFORMATEX *fmt;
+ BYTE *local_buffer, *cap_buffer, *wrap_buffer, *resamp_buffer, *tmp_buffer;
+};
+
struct endpoint
{
WCHAR *name;
--
2.23.0
1
0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/winecoreaudio.drv/Makefile.in | 1 +
dlls/winecoreaudio.drv/coreaudio.c | 229 ++++++++++++++++++++++++++++-
dlls/winecoreaudio.drv/mmdevdrv.c | 203 +++++++------------------
dlls/winecoreaudio.drv/unixlib.h | 44 ++++++
4 files changed, 322 insertions(+), 155 deletions(-)
create mode 100644 dlls/winecoreaudio.drv/unixlib.h
diff --git a/dlls/winecoreaudio.drv/Makefile.in b/dlls/winecoreaudio.drv/Makefile.in
index afbc50c7148..b6bf5bd4587 100644
--- a/dlls/winecoreaudio.drv/Makefile.in
+++ b/dlls/winecoreaudio.drv/Makefile.in
@@ -1,4 +1,5 @@
MODULE = winecoreaudio.drv
+UNIXLIB = winecoreaudio.so
IMPORTS = uuid ole32 user32 advapi32
DELAYIMPORTS = winmm
EXTRALIBS = $(COREAUDIO_LIBS)
diff --git a/dlls/winecoreaudio.drv/coreaudio.c b/dlls/winecoreaudio.drv/coreaudio.c
index 1f222367bed..f3af24f80fb 100644
--- a/dlls/winecoreaudio.drv/coreaudio.c
+++ b/dlls/winecoreaudio.drv/coreaudio.c
@@ -1,5 +1,8 @@
/*
- * Wine Driver for CoreAudio
+ * Unixlib for winecoreaudio driver.
+ *
+ * Copyright 2011 Andrew Eikum for CodeWeavers
+ * Copyright 2021 Huw Davies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -15,16 +18,230 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+#if 0
+#pragma makedep unix
+#endif
#include "config.h"
+#define LoadResource __carbon_LoadResource
+#define CompareString __carbon_CompareString
+#define GetCurrentThread __carbon_GetCurrentThread
+#define GetCurrentProcess __carbon_GetCurrentProcess
+
#include <stdarg.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <fenv.h>
+#include <unistd.h>
+
+#include <libkern/OSAtomic.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioToolbox/AudioFormat.h>
+#include <AudioToolbox/AudioConverter.h>
+#include <AudioUnit/AudioUnit.h>
+
+#undef LoadResource
+#undef CompareString
+#undef GetCurrentThread
+#undef GetCurrentProcess
+#undef _CDECL
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "mmddk.h"
-#include "coreaudio.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "mmdeviceapi.h"
+#include "initguid.h"
+#include "audioclient.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "wine/unixlib.h"
+
+#include "unixlib.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
+
+static HRESULT osstatus_to_hresult(OSStatus sc)
+{
+ switch(sc){
+ case kAudioFormatUnsupportedDataFormatError:
+ case kAudioFormatUnknownFormatError:
+ case kAudioDeviceUnsupportedFormatError:
+ return AUDCLNT_E_UNSUPPORTED_FORMAT;
+ case kAudioHardwareBadDeviceError:
+ return AUDCLNT_E_DEVICE_INVALIDATED;
+ }
+ return E_FAIL;
+}
+
+static AudioObjectPropertyScope get_scope(EDataFlow flow)
+{
+ return (flow == eRender) ? kAudioDevicePropertyScopeOutput : kAudioDevicePropertyScopeInput;
+}
+
+static BOOL device_has_channels(AudioDeviceID device, EDataFlow flow)
+{
+ AudioObjectPropertyAddress addr;
+ AudioBufferList *buffers;
+ BOOL ret = FALSE;
+ OSStatus sc;
+ UInt32 size;
+ int i;
+
+ addr.mSelector = kAudioDevicePropertyStreamConfiguration;
+ addr.mScope = get_scope(flow);
+ addr.mElement = 0;
+
+ sc = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size);
+ if(sc != noErr){
+ WARN("Unable to get _StreamConfiguration property size for device %u: %x\n",
+ (unsigned int)device, (int)sc);
+ return FALSE;
+ }
+
+ buffers = malloc(size);
+ if(!buffers) return FALSE;
+
+ sc = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, buffers);
+ if(sc != noErr){
+ WARN("Unable to get _StreamConfiguration property for device %u: %x\n",
+ (unsigned int)device, (int)sc);
+ free(buffers);
+ return FALSE;
+ }
+
+ for(i = 0; i < buffers->mNumberBuffers; i++){
+ if(buffers->mBuffers[i].mNumberChannels > 0){
+ ret = TRUE;
+ break;
+ }
+ }
+ free(buffers);
+ return ret;
+}
+
+static NTSTATUS get_endpoint_ids(void *args)
+{
+ struct get_endpoint_ids_params *params = args;
+ unsigned int num_devices, i, needed;
+ AudioDeviceID *devices, default_id;
+ AudioObjectPropertyAddress addr;
+ struct endpoint *endpoint;
+ UInt32 devsize, size;
+ struct endpoint_info
+ {
+ CFStringRef name;
+ AudioDeviceID id;
+ } *info;
+ OSStatus sc;
+ WCHAR *ptr;
+
+ params->num = 0;
+ params->default_idx = 0;
+
+ addr.mScope = kAudioObjectPropertyScopeGlobal;
+ addr.mElement = kAudioObjectPropertyElementMaster;
+ if(params->flow == eRender) addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ else if(params->flow == eCapture) addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+ else{
+ params->result = E_INVALIDARG;
+ return STATUS_SUCCESS;
+ }
+
+ size = sizeof(default_id);
+ sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, &default_id);
+ if(sc != noErr){
+ WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
+ default_id = -1;
+ }
+
+ addr.mSelector = kAudioHardwarePropertyDevices;
+ sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devsize);
+ if(sc != noErr){
+ WARN("Getting _Devices property size failed: %x\n", (int)sc);
+ params->result = osstatus_to_hresult(sc);
+ return STATUS_SUCCESS;
+ }
+
+ num_devices = devsize / sizeof(AudioDeviceID);
+ devices = malloc(devsize);
+ info = malloc(num_devices * sizeof(*info));
+ if(!devices || !info){
+ free(info);
+ free(devices);
+ params->result = E_OUTOFMEMORY;
+ return STATUS_SUCCESS;
+ }
+
+ sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devsize, devices);
+ if(sc != noErr){
+ WARN("Getting _Devices property failed: %x\n", (int)sc);
+ free(info);
+ free(devices);
+ params->result = osstatus_to_hresult(sc);
+ return STATUS_SUCCESS;
+ }
+
+ addr.mSelector = kAudioObjectPropertyName;
+ addr.mScope = get_scope(params->flow);
+ addr.mElement = 0;
+
+ for(i = 0; i < num_devices; i++){
+ if(!device_has_channels(devices[i], params->flow)) continue;
+
+ size = sizeof(CFStringRef);
+ sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].name);
+ if(sc != noErr){
+ WARN("Unable to get _Name property for device %u: %x\n",
+ (unsigned int)devices[i], (int)sc);
+ continue;
+ }
+ info[params->num++].id = devices[i];
+ }
+ free(devices);
+
+ needed = sizeof(*endpoint) * params->num;
+ endpoint = params->endpoints;
+ ptr = (WCHAR *)(endpoint + params->num);
+
+ for(i = 0; i < params->num; i++){
+ SIZE_T len = CFStringGetLength(info[i].name);
+ needed += (len + 1) * sizeof(WCHAR);
+
+ if(needed <= params->size){
+ endpoint->name = ptr;
+ CFStringGetCharacters(info[i].name, CFRangeMake(0, len), (UniChar*)endpoint->name);
+ ptr[len] = 0;
+ endpoint->id = info[i].id;
+ endpoint++;
+ ptr += len + 1;
+ }
+ CFRelease(info[i].name);
+ if(info[i].id == default_id) params->default_idx = i;
+ }
+ free(info);
+
+ if(needed > params->size){
+ params->size = needed;
+ params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ }
+ else params->result = S_OK;
+
+ return STATUS_SUCCESS;
+}
+
+unixlib_entry_t __wine_unix_call_funcs[] =
+{
+ get_endpoint_ids,
+};
diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c
index f07f4bae5fb..f8b538971f2 100644
--- a/dlls/winecoreaudio.drv/mmdevdrv.c
+++ b/dlls/winecoreaudio.drv/mmdevdrv.c
@@ -56,8 +56,10 @@
#include "winnls.h"
#include "winreg.h"
#include "wine/debug.h"
+#include "wine/heap.h"
#include "wine/unicode.h"
#include "wine/list.h"
+#include "wine/unixlib.h"
#include "ole2.h"
#include "mmdeviceapi.h"
@@ -69,9 +71,12 @@
#include "endpointvolume.h"
#include "audioclient.h"
#include "audiopolicy.h"
+#include "unixlib.h"
WINE_DEFAULT_DEBUG_CHANNEL(coreaudio);
+unixlib_handle_t coreaudio_handle = 0;
+
#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER)
static const REFERENCE_TIME DefaultPeriod = 100000;
@@ -245,6 +250,9 @@ BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved)
switch (reason)
{
case DLL_PROCESS_ATTACH:
+ if(NtQueryVirtualMemory(GetCurrentProcess(), dll, MemoryWineUnixFuncs,
+ &coreaudio_handle, sizeof(coreaudio_handle), NULL))
+ return FALSE;
g_timer_q = CreateTimerQueue();
if(!g_timer_q)
return FALSE;
@@ -319,7 +327,7 @@ exit:
RegCloseKey(drv_key);
}
-static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
+static void get_device_guid(EDataFlow flow, DWORD device_id, GUID *guid)
{
HKEY key = NULL, dev_key;
DWORD type, size = sizeof(*guid);
@@ -333,7 +341,7 @@ static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
key_name[0] = '0';
key_name[1] = ',';
- sprintfW(key_name + 2, key_fmt, device);
+ sprintfW(key_name + 2, key_fmt, device_id);
if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){
if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){
@@ -359,164 +367,61 @@ static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid)
RegCloseKey(key);
}
-HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids,
- GUID **guids, UINT *num, UINT *def_index)
+HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out,
+ GUID **guids_out, UINT *num, UINT *def_index)
{
- UInt32 devsize, size;
- AudioDeviceID *devices;
- AudioDeviceID default_id;
- AudioObjectPropertyAddress addr;
- OSStatus sc;
- int i, ndevices;
-
- TRACE("%d %p %p %p\n", flow, ids, num, def_index);
-
- addr.mScope = kAudioObjectPropertyScopeGlobal;
- addr.mElement = kAudioObjectPropertyElementMaster;
- if(flow == eRender)
- addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- else if(flow == eCapture)
- addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
- else
- return E_INVALIDARG;
-
- size = sizeof(default_id);
- sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0,
- NULL, &size, &default_id);
- if(sc != noErr){
- WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc);
- default_id = -1;
- }
-
- addr.mSelector = kAudioHardwarePropertyDevices;
- sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0,
- NULL, &devsize);
- if(sc != noErr){
- WARN("Getting _Devices property size failed: %x\n", (int)sc);
- return osstatus_to_hresult(sc);
- }
+ struct get_endpoint_ids_params params;
+ unsigned int i;
+ GUID *guids;
+ WCHAR **ids;
- devices = HeapAlloc(GetProcessHeap(), 0, devsize);
- if(!devices)
- return E_OUTOFMEMORY;
-
- sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL,
- &devsize, devices);
- if(sc != noErr){
- WARN("Getting _Devices property failed: %x\n", (int)sc);
- HeapFree(GetProcessHeap(), 0, devices);
- return osstatus_to_hresult(sc);
- }
+ TRACE("%d %p %p %p\n", flow, ids_out, num, def_index);
- ndevices = devsize / sizeof(AudioDeviceID);
+ params.flow = flow;
+ params.size = 1000;
+ params.endpoints = NULL;
+ do{
+ heap_free(params.endpoints);
+ params.endpoints = heap_alloc(params.size);
+ UNIX_CALL(get_endpoint_ids, ¶ms);
+ }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
- *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *));
- if(!*ids){
- HeapFree(GetProcessHeap(), 0, devices);
- return E_OUTOFMEMORY;
- }
+ if(FAILED(params.result)) goto end;
- *guids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(GUID));
- if(!*guids){
- HeapFree(GetProcessHeap(), 0, *ids);
- HeapFree(GetProcessHeap(), 0, devices);
- return E_OUTOFMEMORY;
+ ids = heap_alloc_zero(params.num * sizeof(*ids));
+ guids = heap_alloc(params.num * sizeof(*guids));
+ if(!ids || !guids){
+ params.result = E_OUTOFMEMORY;
+ goto end;
}
- *num = 0;
- *def_index = (UINT)-1;
- for(i = 0; i < ndevices; ++i){
- AudioBufferList *buffers;
- CFStringRef name;
- SIZE_T len;
- int j;
-
- addr.mSelector = kAudioDevicePropertyStreamConfiguration;
- if(flow == eRender)
- addr.mScope = kAudioDevicePropertyScopeOutput;
- else
- addr.mScope = kAudioDevicePropertyScopeInput;
- addr.mElement = 0;
- sc = AudioObjectGetPropertyDataSize(devices[i], &addr, 0, NULL, &size);
- if(sc != noErr){
- WARN("Unable to get _StreamConfiguration property size for "
- "device %u: %x\n", (unsigned int)devices[i], (int)sc);
- continue;
- }
-
- buffers = HeapAlloc(GetProcessHeap(), 0, size);
- if(!buffers){
- HeapFree(GetProcessHeap(), 0, devices);
- for(j = 0; j < *num; ++j)
- HeapFree(GetProcessHeap(), 0, (*ids)[j]);
- HeapFree(GetProcessHeap(), 0, *guids);
- HeapFree(GetProcessHeap(), 0, *ids);
- return E_OUTOFMEMORY;
- }
-
- sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
- &size, buffers);
- if(sc != noErr){
- WARN("Unable to get _StreamConfiguration property for "
- "device %u: %x\n", (unsigned int)devices[i], (int)sc);
- HeapFree(GetProcessHeap(), 0, buffers);
- continue;
- }
-
- /* check that there's at least one channel in this device before
- * we claim it as usable */
- for(j = 0; j < buffers->mNumberBuffers; ++j)
- if(buffers->mBuffers[j].mNumberChannels > 0)
- break;
- if(j >= buffers->mNumberBuffers){
- HeapFree(GetProcessHeap(), 0, buffers);
- continue;
- }
-
- HeapFree(GetProcessHeap(), 0, buffers);
-
- size = sizeof(name);
- addr.mSelector = kAudioObjectPropertyName;
- sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL,
- &size, &name);
- if(sc != noErr){
- WARN("Unable to get _Name property for device %u: %x\n",
- (unsigned int)devices[i], (int)sc);
- continue;
+ for(i = 0; i < params.num; i++){
+ int size = (strlenW(params.endpoints[i].name) + 1) * sizeof(WCHAR);
+ ids[i] = heap_alloc(size);
+ if(!ids[i]){
+ params.result = E_OUTOFMEMORY;
+ goto end;
}
-
- len = CFStringGetLength(name) + 1;
- (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
- if(!(*ids)[*num]){
- CFRelease(name);
- HeapFree(GetProcessHeap(), 0, devices);
- for(j = 0; j < *num; ++j)
- HeapFree(GetProcessHeap(), 0, (*ids)[j]);
- HeapFree(GetProcessHeap(), 0, *ids);
- HeapFree(GetProcessHeap(), 0, *guids);
- return E_OUTOFMEMORY;
+ memcpy(ids[i], params.endpoints[i].name, size);
+ get_device_guid(flow, params.endpoints[i].id, guids + i);
+ }
+ *def_index = params.default_idx;
+
+end:
+ heap_free(params.endpoints);
+ if(FAILED(params.result)){
+ heap_free(guids);
+ if(ids){
+ for(i = 0; i < params.num; i++) heap_free(ids[i]);
+ heap_free(ids);
}
- CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]);
- ((*ids)[*num])[len - 1] = 0;
- CFRelease(name);
-
- get_device_guid(flow, devices[i], &(*guids)[*num]);
-
- if(*def_index == (UINT)-1 && devices[i] == default_id)
- *def_index = *num;
-
- TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]),
- (unsigned int)devices[i], (*def_index == *num) ? " (default)" : "");
-
- (*num)++;
+ }else{
+ *ids_out = ids;
+ *guids_out = guids;
+ *num = params.num;
}
- if(*def_index == (UINT)-1)
- *def_index = 0;
-
- HeapFree(GetProcessHeap(), 0, devices);
-
- return S_OK;
+ return params.result;
}
static BOOL get_deviceid_by_guid(GUID *guid, AudioDeviceID *id, EDataFlow *flow)
diff --git a/dlls/winecoreaudio.drv/unixlib.h b/dlls/winecoreaudio.drv/unixlib.h
new file mode 100644
index 00000000000..7c1200464b9
--- /dev/null
+++ b/dlls/winecoreaudio.drv/unixlib.h
@@ -0,0 +1,44 @@
+/*
+ * Unixlib header file for winecoreaudio driver.
+ *
+ * Copyright 2021 Huw Davies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+struct endpoint
+{
+ WCHAR *name;
+ DWORD id;
+};
+
+struct get_endpoint_ids_params
+{
+ EDataFlow flow;
+ struct endpoint *endpoints;
+ unsigned int size;
+ HRESULT result;
+ unsigned int num;
+ unsigned int default_idx;
+};
+
+enum unix_funcs
+{
+ unix_get_endpoint_ids,
+};
+
+extern unixlib_handle_t coreaudio_handle;
+
+#define UNIX_CALL( func, params ) __wine_unix_call( coreaudio_handle, unix_ ## func, params )
--
2.23.0
1
0