From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Derek Lesho dlesho@codeweavers.com --- dlls/win32u/tests/d3dkmt.c | 179 +++++++++++++++++++++++++++++-------- 1 file changed, 144 insertions(+), 35 deletions(-)
diff --git a/dlls/win32u/tests/d3dkmt.c b/dlls/win32u/tests/d3dkmt.c index 619ac2eacba..3dcaa747d50 100644 --- a/dlls/win32u/tests/d3dkmt.c +++ b/dlls/win32u/tests/d3dkmt.c @@ -193,6 +193,24 @@ static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expec debugstr_w(str->Buffer), debugstr_w(expected_name) ); }
+static NTSTATUS open_shared_resource( const WCHAR *name, HANDLE *handle ) +{ + D3DKMT_OPENNTHANDLEFROMNAME open_name = {0}; + UNICODE_STRING name_str; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + + RtlInitUnicodeString( &name_str, name ); + InitializeObjectAttributes( &attr, &name_str, OBJ_OPENIF, NULL, NULL ); + + open_name.dwDesiredAccess = GENERIC_ALL; + open_name.pObjAttrib = &attr; + + status = D3DKMTOpenNtHandleFromName( &open_name ); + *handle = open_name.hNtHandle; + return status; +} + struct dxgi_runtime_desc { UINT size; @@ -4276,12 +4294,11 @@ static struct opengl_device *create_opengl_device( HWND hwnd, LUID *luid ) return dev; }
-static void import_opengl_image( struct opengl_device *dev, UINT width, UINT height, UINT depth, UINT bpp, - const WCHAR *name, HANDLE handle, UINT handle_type ) +static GLuint import_opengl_image( struct opengl_device *dev, UINT width, UINT height, UINT depth, + UINT bpp, const WCHAR *name, HANDLE handle, UINT handle_type ) { PFN_glMemoryObjectParameterivEXT p_glMemoryObjectParameterivEXT; PFN_glCreateMemoryObjectsEXT p_glCreateMemoryObjectsEXT; - PFN_glDeleteMemoryObjectsEXT p_glDeleteMemoryObjectsEXT; const GLint dedicated = GL_TRUE; GLuint memory;
@@ -4290,7 +4307,14 @@ static void import_opengl_image( struct opengl_device *dev, UINT width, UINT hei if (dev->broken && handle_type != GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT && handle_type != GL_HANDLE_TYPE_OPAQUE_WIN32_EXT) { win_skip( "Skipping unsupported handle types\n" ); - return; + return 0; + } + + if (dev->broken && name) + { + win_skip( "Skipping glImportMemoryWin32NameEXT: AMD driver leaks handle\n" ); + if (handle) name = NULL; + else return 0; }
ret = wglMakeCurrent( dev->hdc, dev->rc ); @@ -4298,8 +4322,6 @@ static void import_opengl_image( struct opengl_device *dev, UINT width, UINT hei
p_glCreateMemoryObjectsEXT = (void *)wglGetProcAddress( "glCreateMemoryObjectsEXT" ); ok_ptr( p_glCreateMemoryObjectsEXT, !=, NULL ); - p_glDeleteMemoryObjectsEXT = (void *)wglGetProcAddress( "glDeleteMemoryObjectsEXT" ); - ok_ptr( p_glDeleteMemoryObjectsEXT, !=, NULL ); p_glMemoryObjectParameterivEXT = (void *)wglGetProcAddress( "glMemoryObjectParameterivEXT" ); ok_ptr( p_glMemoryObjectParameterivEXT, !=, NULL );
@@ -4307,26 +4329,48 @@ static void import_opengl_image( struct opengl_device *dev, UINT width, UINT hei { PFN_glImportMemoryWin32NameEXT p_glImportMemoryWin32NameEXT = (void *)wglGetProcAddress( "glImportMemoryWin32NameEXT" ); todo_wine ok_ptr( p_glImportMemoryWin32NameEXT, !=, NULL ); - if (!p_glImportMemoryWin32NameEXT) return; + if (!p_glImportMemoryWin32NameEXT) return 0;
p_glCreateMemoryObjectsEXT( 1, &memory ); p_glMemoryObjectParameterivEXT( memory, GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated ); p_glImportMemoryWin32NameEXT( memory, width * height * depth * bpp, handle_type, name ); - p_glDeleteMemoryObjectsEXT( 1, &memory ); + return memory; } else { PFN_glImportMemoryWin32HandleEXT p_glImportMemoryWin32HandleEXT = (void *)wglGetProcAddress( "glImportMemoryWin32HandleEXT" ); todo_wine ok_ptr( p_glImportMemoryWin32HandleEXT, !=, NULL ); - if (!p_glImportMemoryWin32HandleEXT) return; + if (!p_glImportMemoryWin32HandleEXT) return 0;
p_glCreateMemoryObjectsEXT( 1, &memory ); p_glMemoryObjectParameterivEXT( memory, GL_DEDICATED_MEMORY_OBJECT_EXT, &dedicated ); p_glImportMemoryWin32HandleEXT( memory, width * height * depth * bpp, handle_type, handle ); - p_glDeleteMemoryObjectsEXT( 1, &memory ); + return memory; } }
+static void destroy_opengl_image( struct opengl_device *dev, GLuint memory ) +{ + PFN_glDeleteMemoryObjectsEXT p_glDeleteMemoryObjectsEXT; + UINT ret; + + p_glDeleteMemoryObjectsEXT = (void *)wglGetProcAddress( "glDeleteMemoryObjectsEXT" ); + ok_ptr( p_glDeleteMemoryObjectsEXT, !=, NULL ); + + ret = wglMakeCurrent( dev->hdc, dev->rc ); + todo_wine_if( ret == 0 ) ok_u4( ret, !=, 0 ); + + if (memory) p_glDeleteMemoryObjectsEXT( 1, &memory ); + + glFinish(); +} + +static void test_import_opengl_image( struct opengl_device *dev, UINT width, UINT height, UINT depth, + UINT bpp, const WCHAR *name, HANDLE handle, UINT handle_type ) +{ + destroy_opengl_image( dev, import_opengl_image( dev, width, height, depth, bpp, name, handle, handle_type ) ); +} + static HRESULT get_dxgi_global_handle( IUnknown *obj, HANDLE *handle ) { IDXGIResource *res; @@ -4583,6 +4627,7 @@ static void test_shared_resources(void) BOOL stencil_broken, is_wow64 = FALSE; IDXGIFactory3 *dxgi = NULL; IDXGIAdapter *adapter; + WCHAR path[MAX_PATH]; LUID luid = {0}; VkResult vr; HRESULT hr; @@ -5381,7 +5426,6 @@ static void test_shared_resources(void)
if (name) { - WCHAR path[MAX_PATH]; swprintf( path, ARRAY_SIZE(path), L"\Sessions\1\BaseNamedObjects\%s", name ); check_object_name( handle, path ); } @@ -5654,27 +5698,27 @@ static void test_shared_resources(void) switch (GET_DIM(test)) { case 0: - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 1: - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 2: - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 3: - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT ); ok_x4( glGetError(), ==, 0 ); break; } @@ -5684,49 +5728,114 @@ static void test_shared_resources(void) switch (GET_DIM(test)) { case 0: - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); + test_import_opengl_image( opengl_imp, resource_size, 1, 1, 1, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 1: - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); + test_import_opengl_image( opengl_imp, width_1d, 1, array_1d, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 2: - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); + test_import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); ok_x4( glGetError(), ==, 0 ); break; case 3: - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D11_IMAGE_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT ); ok_x4( glGetError(), ==, 0 ); - import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); + test_import_opengl_image( opengl_imp, width_3d, height_3d, depth_3d, 4, name, handle, GL_HANDLE_TYPE_D3D12_RESOURCE_EXT ); ok_x4( glGetError(), ==, 0 ); break; } } }
+ /* test shared resource handle lifetime */ + if (name) + { + IUnknown *import_d3d11 = NULL, *import_d3d12 = NULL; + struct vulkan_image *img_imp = NULL; + GLuint gl_img = 0; + NTSTATUS status; + + /* On AMD, export-VkDeviceMemory holds a reference, make sure to only hold one with handle */ + if (img) destroy_vulkan_image( vulkan_exp, img ); + img = NULL; + + if (vulkan_imp && GET_DIM(test) == 2) + { + VkResult vr = import_vulkan_image( vulkan_imp, width_2d, height_2d, 1, name, handle, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, &img_imp ); + ok_vk( VK_SUCCESS, vr ); + + CloseHandle( handle ); + status = open_shared_resource( path, &handle ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + + destroy_vulkan_image( vulkan_imp, img_imp ); + } + + /* On NVIDIA: + * - Memory object holds shared resource handle + * On AMD: + * - glImportMemoryWin32NameEXT: leaks a shared resource handle + * - glImportMemoryWin32HandleEXT: doesn't hold a shared resource handle + */ + if (opengl_imp && GET_DIM(test) == 2 && !opengl_imp->broken) + { + gl_img = import_opengl_image( opengl_imp, width_2d, height_2d, 1, 4, name, handle, GL_HANDLE_TYPE_OPAQUE_WIN32_EXT ); + ok_x4( glGetError(), ==, 0 ); + + CloseHandle( handle ); + status = open_shared_resource( path, &handle ); + todo_wine ok_nt( STATUS_SUCCESS, status ); + + destroy_opengl_image( opengl_imp, gl_img ); + glFinish(); + } + + /* D3D objects don't hold shared resource handle */ + + if (d3d11_imp && GET_API(test) <= 3) + { + hr = ID3D11Device1_OpenSharedResourceByName( d3d11_imp, name, GENERIC_ALL, &IID_ID3D11Resource, (void **)&import_d3d11 ); + ok_hr( S_OK, hr ); + } + + if (d3d12_imp && GET_API(test) <= 3) + { + hr = open_d3d12_named_shared_handle( d3d12_imp, name, &IID_ID3D12Resource, (void **)&import_d3d12 ); + ok_hr( S_OK, hr ); + } + + CloseHandle( handle ); + status = open_shared_resource( path, &handle ); + ok_nt( STATUS_OBJECT_NAME_NOT_FOUND, status ); + + if (import_d3d11) IUnknown_Release( import_d3d11 ); + if (import_d3d12) IUnknown_Release( import_d3d12 ); + } + skip_tests: if (handle && !is_d3dkmt_handle( handle )) CloseHandle( handle ); if (export) ok_ref( 0, IUnknown_Release( export ) );