Basically, this is the tests from https://gitlab.winehq.org/wine/wine/-/merge_requests/3420 with fixes applied where they originate, rather than later in the series.
From: Matthew Wong itsmattkc@gmail.com
--- dlls/ddraw/tests/ddraw1.c | 127 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index cde80c58e99..2e4fc8eda42 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15432,6 +15432,132 @@ static void test_enum_devices(void) ok(!refcount, "Device has %lu references left.\n", refcount); }
+static void test_pick(void) +{ + static D3DTLVERTEX tquad[] = + { + {{320.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{320.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + }; + IDirect3DExecuteBuffer *execute_buffer; + D3DEXECUTEBUFFERDESC exec_desc; + IDirect3DViewport *viewport; + IDirect3DDevice *device; + IDirectDraw *ddraw; + UINT inst_length; + HWND window; + HRESULT hr; + void *ptr; + DWORD rec_count; + D3DRECT pick_rect; + UINT screen_width = 640; + UINT screen_height = 480; + UINT hits = 0; + UINT nohits = 0; + int i, j; + + 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, skipping test.\n"); + IDirectDraw_Release(ddraw); + DestroyWindow(window); + return; + } + + viewport = create_viewport(device, 0, 0, screen_width, screen_height); + + 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(SUCCEEDED(hr), "Failed to create execute buffer, hr %#lx.\n", hr); + hr = IDirect3DExecuteBuffer_Lock(execute_buffer, &exec_desc); + ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr); + memcpy(exec_desc.lpData, tquad, sizeof(tquad)); + ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad); + emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4); + emit_tquad(&ptr, 0); + emit_end(&ptr); + inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData; + inst_length -= sizeof(tquad); + hr = IDirect3DExecuteBuffer_Unlock(execute_buffer); + ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr); + + set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length); + + /* Perform a number of picks, we should have a specific amount by the end. + * We should get precisely equal numbers of hits and no hits since our quad + * covers exactly half the screen. */ + for (i = 0; i < screen_width; i += 80) + { + for (j = 0; j < screen_height; j += 60) + { + pick_rect.x1 = pick_rect.x2 = i; + pick_rect.y1 = pick_rect.y2 = j; + + hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); + ok(SUCCEEDED(hr), "Failed to perform pick, hr %#lx.\n", hr); + rec_count = ~0; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + if (rec_count == 0) + nohits++; + else if (rec_count != ~0) + hits++; + } + } + + todo_wine ok(hits + nohits > 0, "Did not get any pick hits or misses.\n"); + ok(hits == nohits, "Got a non-equal amount of pick hits/misses: %i vs %i.\n", hits, nohits); + + /* Try some specific pixel picks */ + pick_rect.x1 = pick_rect.x2 = 480; + pick_rect.y1 = pick_rect.y2 = 360; + hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); + ok(SUCCEEDED(hr), "Failed to perform pick, hr %#lx.\n", hr); + rec_count = ~0; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + todo_wine ok(rec_count == 0, "Got incorrect number of pick records (expected 0): %lu.\n", rec_count); + + pick_rect.x1 = pick_rect.x2 = 240; + pick_rect.y1 = pick_rect.y2 = 120; + hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); + ok(SUCCEEDED(hr), "Failed to perform pick, hr %#lx.\n", hr); + rec_count = ~0; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + todo_wine ok(rec_count == 1, "Got incorrect number of pick records (expected 1): %lu.\n", rec_count); + + if (rec_count == 1) + { + D3DPICKRECORD record; + + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + + /* Tests D3DPICKRECORD for correct information */ + ok(record.bOpcode == 3, "Got incorrect bOpcode: %i.\n", record.bOpcode); + ok(record.bPad == 0, "Got incorrect bPad: %i.\n", record.bPad); + ok(record.dwOffset == 24, "Got incorrect dwOffset: %lu.\n", record.dwOffset); + ok(compare_float(record.dvZ, 1.0, 4096), "Got incorrect dvZ: %.8e.\n", record.dvZ); + } + + destroy_viewport(device, viewport); + IDirect3DExecuteBuffer_Release(execute_buffer); + IDirect3DDevice_Release(device); + IDirectDraw_Release(ddraw); + DestroyWindow(window); +} + START_TEST(ddraw1) { DDDEVICEIDENTIFIER identifier; @@ -15551,4 +15677,5 @@ START_TEST(ddraw1) run_for_each_device_type(test_texture_wrong_caps); test_filling_convention(); test_enum_devices(); + test_pick(); }
From: Jeff Smith whydoubt@gmail.com
--- dlls/ddraw/tests/ddraw1.c | 63 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 2e4fc8eda42..1d1f8eea426 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15436,10 +15436,21 @@ static void test_pick(void) { static D3DTLVERTEX tquad[] = { + /* Left half of viewport */ {{320.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, {{ 0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, {{320.0f}, { 0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, {{ 0.0f}, { 0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + /* Lower-left quarter of viewport */ + {{320.0f}, {480.0f}, {-0.3f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{ 0.0f}, {480.0f}, { 1.7f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{320.0f}, {240.0f}, {-0.3f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{ 0.0f}, {240.0f}, { 1.7f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + /* Right half of lower-left quarter of viewport */ + {{320.0f}, {480.0f}, { 0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{160.0f}, {480.0f}, { 0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{320.0f}, {240.0f}, { 0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, + {{160.0f}, {240.0f}, { 0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}}, }; IDirect3DExecuteBuffer *execute_buffer; D3DEXECUTEBUFFERDESC exec_desc; @@ -15483,15 +15494,17 @@ static void test_pick(void) ok(SUCCEEDED(hr), "Failed to lock execute buffer, hr %#lx.\n", hr); memcpy(exec_desc.lpData, tquad, sizeof(tquad)); ptr = ((BYTE *)exec_desc.lpData) + sizeof(tquad); - emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 4); + emit_process_vertices(&ptr, D3DPROCESSVERTICES_COPY, 0, 12); emit_tquad(&ptr, 0); + emit_tquad(&ptr, 4); + emit_tquad(&ptr, 8); emit_end(&ptr); inst_length = (BYTE *)ptr - (BYTE *)exec_desc.lpData; inst_length -= sizeof(tquad); hr = IDirect3DExecuteBuffer_Unlock(execute_buffer); ok(SUCCEEDED(hr), "Failed to unlock execute buffer, hr %#lx.\n", hr);
- set_execute_data(execute_buffer, 4, sizeof(tquad), inst_length); + set_execute_data(execute_buffer, 12, sizeof(tquad), inst_length);
/* Perform a number of picks, we should have a specific amount by the end. * We should get precisely equal numbers of hits and no hits since our quad @@ -15518,7 +15531,7 @@ static void test_pick(void) todo_wine ok(hits + nohits > 0, "Did not get any pick hits or misses.\n"); ok(hits == nohits, "Got a non-equal amount of pick hits/misses: %i vs %i.\n", hits, nohits);
- /* Try some specific pixel picks */ + /* Pick a pixel where no quads are present */ pick_rect.x1 = pick_rect.x2 = 480; pick_rect.y1 = pick_rect.y2 = 360; hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); @@ -15528,6 +15541,7 @@ static void test_pick(void) ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); todo_wine ok(rec_count == 0, "Got incorrect number of pick records (expected 0): %lu.\n", rec_count);
+ /* Pick a pixel where one quad is present */ pick_rect.x1 = pick_rect.x2 = 240; pick_rect.y1 = pick_rect.y2 = 120; hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); @@ -15551,6 +15565,49 @@ static void test_pick(void) ok(compare_float(record.dvZ, 1.0, 4096), "Got incorrect dvZ: %.8e.\n", record.dvZ); }
+ /* Pick a pixel where three quads are present */ + pick_rect.x1 = pick_rect.x2 = 240; + pick_rect.y1 = pick_rect.y2 = 360; + hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); + ok(SUCCEEDED(hr), "Failed to perform pick, hr %#lx.\n", hr); + rec_count = ~0; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + todo_wine ok(rec_count == 3, "Got incorrect number of pick records (expected 3): %lu.\n", rec_count); + + if (rec_count == 3) + { + D3DPICKRECORD record[3] = {0}; + const D3DPICKRECORD empty_record = {0}; + + /* If the count is wrong, do not populate any records */ + rec_count = 1; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record[0]); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + ok(rec_count == 3, "Got incorrect number of pick records (expected 3): %lu.\n", rec_count); + ok(memcmp(&record[0], &empty_record, sizeof(D3DPICKRECORD)) == 0, "Got unexpected pick record.\n"); + ok(memcmp(&record[1], &empty_record, sizeof(D3DPICKRECORD)) == 0, "Got unexpected pick record.\n"); + ok(memcmp(&record[2], &empty_record, sizeof(D3DPICKRECORD)) == 0, "Got unexpected pick record.\n"); + + rec_count = 3; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record[0]); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + + /* Documentation states this list is z-ordered, but it appears that it is not. */ + ok(record[0].bOpcode == 3, "Got incorrect bOpcode: %i.\n", record[0].bOpcode); + ok(record[0].bPad == 0, "Got incorrect bPad: %i.\n", record[0].bPad); + ok(record[0].dwOffset == 24, "Got incorrect dwOffset: %lu.\n", record[0].dwOffset); + ok(compare_float(record[0].dvZ, 1.0, 4096), "Got incorrect dvZ: %.8e.\n", record[0].dvZ); + ok(record[1].bOpcode == 3, "Got incorrect bOpcode: %i.\n", record[1].bOpcode); + ok(record[1].bPad == 0, "Got incorrect bPad: %i.\n", record[1].bPad); + ok(record[1].dwOffset == 44, "Got incorrect dwOffset: %lu.\n", record[1].dwOffset); + ok(compare_float(record[1].dvZ, 0.2, 4096), "Got incorrect dvZ: %.8e.\n", record[1].dvZ); + ok(record[2].bOpcode == 3, "Got incorrect bOpcode: %i.\n", record[2].bOpcode); + ok(record[2].bPad == 0, "Got incorrect bPad: %i.\n", record[2].bPad); + ok(record[2].dwOffset == 64, "Got incorrect dwOffset: %lu.\n", record[2].dwOffset); + ok(compare_float(record[2].dvZ, 0.5, 4096), "Got incorrect dvZ: %.8e.\n", record[2].dvZ); + } + destroy_viewport(device, viewport); IDirect3DExecuteBuffer_Release(execute_buffer); IDirect3DDevice_Release(device);
From: Jeff Smith whydoubt@gmail.com
--- dlls/ddraw/tests/ddraw1.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 1d1f8eea426..dc468d8a21a 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15608,6 +15608,31 @@ static void test_pick(void) ok(compare_float(record[2].dvZ, 0.5, 4096), "Got incorrect dvZ: %.8e.\n", record[2].dvZ); }
+ /* Pick a rectange, though it appears that only the upper-left corner is checked. */ + pick_rect.x1 = 240; + pick_rect.y1 = 120; + pick_rect.x2 = screen_width - 1; + pick_rect.y2 = screen_height - 1; + hr = IDirect3DDevice_Pick(device, execute_buffer, viewport, 0, &pick_rect); + ok(SUCCEEDED(hr), "Failed to perform pick, hr %#lx.\n", hr); + rec_count = ~0; + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, NULL); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + todo_wine ok(rec_count == 1, "Got incorrect number of pick records (expected 1): %lu.\n", rec_count); + + if (rec_count == 1) + { + D3DPICKRECORD record; + + hr = IDirect3DDevice_GetPickRecords(device, &rec_count, &record); + ok(SUCCEEDED(hr), "Failed to get pick records, hr %#lx.\n", hr); + + ok(record.bOpcode == 3, "Got incorrect bOpcode: %i.\n", record.bOpcode); + ok(record.bPad == 0, "Got incorrect bPad: %i.\n", record.bPad); + ok(record.dwOffset == 24, "Got incorrect dwOffset: %lu.\n", record.dwOffset); + ok(compare_float(record.dvZ, 1.0, 4096), "Got incorrect dvZ: %.8e.\n", record.dvZ); + } + destroy_viewport(device, viewport); IDirect3DExecuteBuffer_Release(execute_buffer); IDirect3DDevice_Release(device);
From: Jeff Smith whydoubt@gmail.com
--- dlls/ddraw/tests/ddraw1.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index dc468d8a21a..b009cb755a3 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -15633,6 +15633,11 @@ static void test_pick(void) ok(compare_float(record.dvZ, 1.0, 4096), "Got incorrect dvZ: %.8e.\n", record.dvZ); }
+ if (0) /* This crashes on Windows. */ + { + IDirect3DDevice_GetPickRecords(device, NULL, NULL); + } + destroy_viewport(device, viewport); IDirect3DExecuteBuffer_Release(execute_buffer); IDirect3DDevice_Release(device);
I am curious how picking interacts with functionality that can discard geometry, i.e. clipping, culling and depth testing.
The tests draw geometry outside z [0.0; 1.0], and it doesn't seem to influence the result (at least the initial test that counts hit vs miss is easy-ish to read there). That indicates the near and far clip planes don't matter. Testing a z result < 0 or > 1 would be more confirmation.
Relatedly, can you get a hit for a coordinate outside the viewport? x = -1, x > 640 or so?
Afaics user clip planes were not supported before d3ddevice7, so they won't influence picking.
I don't expect the depth test to influence the result, this would be rather difficult to implement. But you could e.g. enable the depth test and clear the depth buffer to 0.5 and show hits < 0.5 and > 0.5.
Culling is the most likely one to matter IMHO since it is easy to implement without consulting the GPU.
Finally got back around to this... I have since: 1. Given up on trying to have one commit with a tidied-up version of the original author's work, followed by several incremental commits. It's now squashed into a single commit. 2. Expanded the z-range of several quads, so that z results cover a range larger than [0.0, 1.0] 3. Added a quad and test point that are outside of the viewport. 4. Discovered that while not much affects pre-transformed vertices, untransformed vertices (that is, transformed when executing the execute buffer) are affected by the transform/render state, so I added some tests with that in mind.
Note: I believe that when I looked at this a while back, I decided that clearing to a depth value other than 1.0 is more trouble than it's worth for this, and none of the other ddraw1 tests are enabling z-depth testing.