From 04fd8e9bc00e722ed1e7f1baba81c545979b43f9 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 16:36:37 +0300 Subject: [PATCH 01/83] amd_ags_x64: Implement agsDriverExtensionsDX11_CreateDevice(). CW-Bug-Id: #19944 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 106 +++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index ebb026da35e..d4a558729aa 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -3,7 +3,7 @@ @ stdcall agsCheckDriverVersion(ptr long) @ stub agsDriverExtensionsDX11_BeginUAVOverlap @ stub agsDriverExtensionsDX11_CreateBuffer -@ stub agsDriverExtensionsDX11_CreateDevice +@ stdcall agsDriverExtensionsDX11_CreateDevice(ptr ptr ptr ptr) @ stub agsDriverExtensionsDX11_CreateFromDevice @ stub agsDriverExtensionsDX11_CreateTexture1D @ stub agsDriverExtensionsDX11_CreateTexture2D diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 24b16021acf..6ae20547e7a 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -38,18 +38,19 @@ static const struct int minor; int patch; unsigned int device_size; + unsigned int dx11_returned_params_size; } amd_ags_info[AMD_AGS_VERSION_COUNT] = { - {5, 1, 1, sizeof(AGSDeviceInfo_511)}, - {5, 2, 0, sizeof(AGSDeviceInfo_520)}, - {5, 2, 1, sizeof(AGSDeviceInfo_520)}, - {5, 3, 0, sizeof(AGSDeviceInfo_520)}, - {5, 4, 0, sizeof(AGSDeviceInfo_540)}, - {5, 4, 1, sizeof(AGSDeviceInfo_541)}, - {5, 4, 2, sizeof(AGSDeviceInfo_542)}, - {6, 0, 0, sizeof(AGSDeviceInfo_600)}, - {6, 0, 1, sizeof(AGSDeviceInfo_600)}, + {5, 1, 1, sizeof(AGSDeviceInfo_511), sizeof(AGSDX11ReturnedParams_511)}, + {5, 2, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)}, + {5, 2, 1, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)}, + {5, 3, 0, sizeof(AGSDeviceInfo_520), sizeof(AGSDX11ReturnedParams_520)}, + {5, 4, 0, sizeof(AGSDeviceInfo_540), sizeof(AGSDX11ReturnedParams_520)}, + {5, 4, 1, sizeof(AGSDeviceInfo_541), sizeof(AGSDX11ReturnedParams_520)}, + {5, 4, 2, sizeof(AGSDeviceInfo_542), sizeof(AGSDX11ReturnedParams_520)}, + {6, 0, 0, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, + {6, 0, 1, sizeof(AGSDeviceInfo_600), sizeof(AGSDX11ReturnedParams_600)}, }; #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ @@ -117,8 +118,10 @@ struct AGSContext VkPhysicalDeviceMemoryProperties *memory_properties; }; -static HMODULE hd3d12; +static HMODULE hd3d11, hd3d12; static typeof(D3D12CreateDevice) *pD3D12CreateDevice; +static typeof(D3D11CreateDevice) *pD3D11CreateDevice; +static typeof(D3D11CreateDeviceAndSwapChain) *pD3D11CreateDeviceAndSwapChain; static BOOL load_d3d12_functions(void) { @@ -132,6 +135,19 @@ static BOOL load_d3d12_functions(void) return TRUE; } +static BOOL load_d3d11_functions(void) +{ + if (hd3d11) + return TRUE; + + if (!(hd3d11 = LoadLibraryA("d3d11.dll"))) + return FALSE; + + pD3D11CreateDevice = (void *)GetProcAddress(hd3d11, "D3D11CreateDevice"); + pD3D11CreateDeviceAndSwapChain = (void *)GetProcAddress(hd3d11, "D3D11CreateDeviceAndSwapChain"); + return TRUE; +} + static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) { @@ -605,6 +621,76 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count return AGS_SUCCESS; } +AGSReturnCode WINAPI agsDriverExtensionsDX11_CreateDevice( AGSContext* context, + const AGSDX11DeviceCreationParams* creation_params, const AGSDX11ExtensionParams* extension_params, + AGSDX11ReturnedParams* returned_params ) +{ + ID3D11DeviceContext *device_context; + IDXGISwapChain *swapchain = NULL; + D3D_FEATURE_LEVEL feature_level; + ID3D11Device *device; + HRESULT hr; + + TRACE("feature levels %u, pSwapChainDesc %p, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevels, + creation_params->pSwapChainDesc, + debugstr_w(extension_params->agsDX11ExtensionParams511.pAppName), + debugstr_w(extension_params->agsDX11ExtensionParams511.pEngineName), + extension_params->agsDX11ExtensionParams511.appVersion, + extension_params->agsDX11ExtensionParams511.engineVersion); + + if (!load_d3d11_functions()) + { + ERR("Could not load d3d11.dll.\n"); + return AGS_MISSING_D3D_DLL; + } + memset( returned_params, 0, amd_ags_info[context->version].dx11_returned_params_size ); + if (creation_params->pSwapChainDesc) + { + hr = pD3D11CreateDeviceAndSwapChain(creation_params->pAdapter, creation_params->DriverType, + creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels, + creation_params->FeatureLevels, creation_params->SDKVersion, creation_params->pSwapChainDesc, + &swapchain, &device, &feature_level, &device_context); + } + else + { + hr = pD3D11CreateDevice(creation_params->pAdapter, creation_params->DriverType, + creation_params->Software, creation_params->Flags, creation_params->pFeatureLevels, + creation_params->FeatureLevels, creation_params->SDKVersion, + &device, &feature_level, &device_context); + } + if (FAILED(hr)) + { + ERR("Device creation failed, hr %#x.\n", hr); + return AGS_DX_FAILURE; + } + if (context->version < AMD_AGS_VERSION_5_2_0) + { + AGSDX11ReturnedParams_511 *r = &returned_params->agsDX11ReturnedParams511; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->FeatureLevel = feature_level; + } + else if (context->version < AMD_AGS_VERSION_6_0_0) + { + AGSDX11ReturnedParams_520 *r = &returned_params->agsDX11ReturnedParams520; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->FeatureLevel = feature_level; + } + else + { + AGSDX11ReturnedParams_600 *r = &returned_params->agsDX11ReturnedParams600; + r->pDevice = device; + r->pImmediateContext = device_context; + r->pSwapChain = swapchain; + r->featureLevel = feature_level; + } + + return AGS_SUCCESS; +} + AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, const AGSDX12DeviceCreationParams *creation_params, const AGSDX12ExtensionParams *extension_params, AGSDX12ReturnedParams *returned_params) From 50a9b4f7421858ccd8e1440359aec829982cac15 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 17:07:53 +0300 Subject: [PATCH 02/83] amd_ags_x64: Add stub for agsDriverExtensionsDX11_SetDepthBounds(). CW-Bug-Id: #19944 --- dlls/amd_ags_x64/amd_ags.h | 6 ++++-- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 30 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h index 20fef455f00..9b521de75b8 100644 --- a/dlls/amd_ags_x64/amd_ags.h +++ b/dlls/amd_ags_x64/amd_ags.h @@ -1506,8 +1506,10 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* con /// \param [in] minDepth The near depth range to clip against. /// \param [in] maxDepth The far depth range to clip against. /// -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_520( AGSContext* context, bool enabled, float minDepth, float maxDepth ); -AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ); +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, bool enabled, float minDepth, float maxDepth ); + +/* Since 5.3.0 */ +AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_530( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ); /// @} diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index d4a558729aa..e531dda9340 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -24,7 +24,7 @@ @ stub agsDriverExtensionsDX11_NotifyResourceEndWrites @ stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs @ stub agsDriverExtensionsDX11_SetClipRects -@ stub agsDriverExtensionsDX11_SetDepthBounds +@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_SetDepthBounds() DX11_SetDepthBounds_impl @ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled @ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount @ stub agsDriverExtensionsDX11_SetViewBroadcastMasks diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 6ae20547e7a..589996594f8 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -8,6 +8,7 @@ #include "wine/heap.h" #include "wine/vulkan.h" +#include "wine/asm.h" #define COBJMACROS #include "d3d11.h" @@ -770,3 +771,32 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) return TRUE; } + +#ifdef __x86_64__ +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds(AGSContext* context, bool enabled, + float minDepth, float maxDepth ) +{ + static int once; + + if (!once++) + FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth); + return AGS_EXTENSION_NOT_SUPPORTED; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_SetDepthBounds_530(AGSContext* context, + ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ) +{ + static int once; + + if (!once++) + FIXME("context %p, enabled %#x, minDepth %f, maxDepth %f stub.\n", context, enabled, minDepth, maxDepth); + return AGS_EXTENSION_NOT_SUPPORTED; +} + +__ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $3,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) +#endif From 7a996657fda91d90e007e5d4507bcd64b7069f05 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 17:42:41 +0300 Subject: [PATCH 03/83] amd_ags_x64: Implement agsDriverExtensionsDX11_DestroyDevice(). CW-Bug-Id: #19944 --- dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- dlls/amd_ags_x64/amd_ags_x64_main.c | 39 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec index e531dda9340..3d9800469a1 100644 --- a/dlls/amd_ags_x64/amd_ags_x64.spec +++ b/dlls/amd_ags_x64/amd_ags_x64.spec @@ -10,7 +10,7 @@ @ stub agsDriverExtensionsDX11_CreateTexture3D @ stub agsDriverExtensionsDX11_DeInit @ stub agsDriverExtensionsDX11_Destroy -@ stub agsDriverExtensionsDX11_DestroyDevice +@ stdcall -norelay -arch=win64 agsDriverExtensionsDX11_DestroyDevice() @ stub agsDriverExtensionsDX11_EndUAVOverlap @ stub agsDriverExtensionsDX11_GetMaxClipRects @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 589996594f8..b58926c928c 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -799,4 +799,43 @@ __ASM_GLOBAL_FUNC( DX11_SetDepthBounds_impl, "jge 1f\n\t" "jmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds") "\n\t" "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_SetDepthBounds_530") ) + +AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_520(AGSContext *context, ID3D11Device* device, + unsigned int *device_ref, ID3D11DeviceContext *device_context, + unsigned int *context_ref) +{ + ULONG ref; + + TRACE("context %p, device %p, device_ref %p, device_context %p, context_ref %p.\n", + context, device, device_ref, device_context, context_ref); + + if (!device) + return AGS_SUCCESS; + + ref = ID3D11Device_Release(device); + if (device_ref) + *device_ref = ref; + + if (!device_context) + return AGS_SUCCESS; + + ref = ID3D11DeviceContext_Release(device_context); + if (context_ref) + *context_ref = ref; + return AGS_SUCCESS; +} + +AGSReturnCode WINAPI agsDriverExtensionsDX11_DestroyDevice_511(AGSContext *context, ID3D11Device *device, + unsigned int *references ) +{ + TRACE("context %p, device %p, references %p.\n", context, device, references); + + return agsDriverExtensionsDX11_DestroyDevice_520(context, device, references, NULL, NULL); +} +__ASM_GLOBAL_FUNC( agsDriverExtensionsDX11_DestroyDevice, + "mov (%rcx),%eax\n\t" /* version */ + "cmp $1,%eax\n\t" + "jge 1f\n\t" + "jmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_511") "\n\t" + "1:\tjmp " __ASM_NAME("agsDriverExtensionsDX11_DestroyDevice_520") ) #endif From 56d7e0b56dcc27373e8be9fd43dfc8b17bd71720 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 18:26:36 +0300 Subject: [PATCH 04/83] wine.inf: Use built-in atiadlxx for STAR WARS Squadrons. CW-Bug-Id: #19944 --- loader/wine.inf.in | 1 + 1 file changed, 1 insertion(+) diff --git a/loader/wine.inf.in b/loader/wine.inf.in index fe8370742b2..a08568eb9a3 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -5930,6 +5930,7 @@ HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" HKCU,Software\Wine\AppDefaults\msedgewebview2.exe,"Version",,"win81" HKCU,Software\Wine\AppDefaults\Avengers.exe\DllOverrides,"atiadlxx",,"builtin" +HKCU,Software\Wine\AppDefaults\starwarssquadrons.exe\DllOverrides,"atiadlxx",,"builtin" ;;App-specific overrides to limit the number of resolutions HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" From 69afcb164ccf8d3ecd5e94cf79c1e31698e14e5c Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Wed, 2 Feb 2022 17:02:44 -0500 Subject: [PATCH 05/83] esync: Type-check HANDLE in esync_set_event. Signed-off-by: Derek Lesho --- dlls/ntdll/unix/esync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c index 55c5695964d..4663374653a 100644 --- a/dlls/ntdll/unix/esync.c +++ b/dlls/ntdll/unix/esync.c @@ -526,6 +526,9 @@ NTSTATUS esync_set_event( HANDLE handle ) if ((ret = get_object( handle, &obj ))) return ret; event = obj->shm; + if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) + return STATUS_OBJECT_TYPE_MISMATCH; + if (obj->type == ESYNC_MANUAL_EVENT) { /* Acquire the spinlock. */ From a87274a02545769139937772a8620c781c8ca80a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 22:39:42 +0300 Subject: [PATCH 06/83] ntdll: Use .seh handler instead of __TRY in RtlUserThreadStart() on x64. CW-Bug-Id: #19913 --- dlls/ntdll/thread.c | 36 +++++++++++++++++++++++++++++++++++- include/wine/asm.h | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 5fc956b1dc4..4cec391cf8b 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -240,7 +240,41 @@ void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *ar __ENDTRY } -#else /* __i386__ */ +#elif /* __i386__ */ defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED) +EXCEPTION_DISPOSITION WINAPI call_thread_func_handler( EXCEPTION_RECORD *rec, ULONG64 frame, + CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) +{ + EXCEPTION_POINTERS ep = { rec, context }; + + WARN( "Unhandled exception, calling filter.\n" ); + + switch (call_unhandled_exception_filter( &ep )) + { + case EXCEPTION_CONTINUE_SEARCH: + return ExceptionContinueSearch; + case EXCEPTION_CONTINUE_EXECUTION: + return ExceptionContinueExecution; + case EXCEPTION_EXECUTE_HANDLER: + break; + } + NtTerminateProcess( GetCurrentProcess(), rec->ExceptionCode ); + return ExceptionContinueExecution; +} + +extern void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg ); +__ASM_GLOBAL_FUNC( RtlUserThreadStart, + "subq $0x28, %rsp\n\t" + __ASM_SEH(".seh_stackalloc 0x28\n\t") + __ASM_SEH(".seh_endprologue\n\t") + "movq %rdx,%r8\n\t" + "movq %rcx,%rdx\n\t" + "xorq %rcx,%rcx\n\t" + "movq pBaseThreadInitThunk(%rip),%r9\n\t" + "call *%r9\n\t" + "int3\n\t" + __ASM_SEH(".seh_handler call_thread_func_handler, @except\n\t") ) + +#else /* defined(__x86_64__) && defined(__ASM_SEH_SUPPORTED) */ void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg ) { diff --git a/include/wine/asm.h b/include/wine/asm.h index 0547ee94b19..9200491afd0 100644 --- a/include/wine/asm.h +++ b/include/wine/asm.h @@ -50,6 +50,7 @@ # define __ASM_SEH(str) # else # define __ASM_SEH(str) str +# define __ASM_SEH_SUPPORTED # endif #else # define __ASM_SEH(str) From 177132546d5b7f1142ebdc1232f308aca3b34d80 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Thu, 3 Feb 2022 17:03:48 -0500 Subject: [PATCH 07/83] userenv: Set ProgramData in CreateEnvironmentBlock. --- dlls/userenv/tests/userenv.c | 17 ++++++++++++++++- dlls/userenv/userenv_main.c | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dlls/userenv/tests/userenv.c b/dlls/userenv/tests/userenv.c index a91edeef260..c7a6791e2be 100644 --- a/dlls/userenv/tests/userenv.c +++ b/dlls/userenv/tests/userenv.c @@ -78,7 +78,7 @@ static void test_create_env(void) BOOL r, is_wow64 = FALSE; HANDLE htok; WCHAR * env[4]; - char * st, systemroot[100]; + char * st, systemroot[100], programdata[100]; int i, j; static const struct profile_item common_vars[] = { @@ -96,6 +96,7 @@ static void test_create_env(void) }; static const struct profile_item common_post_nt4_vars[] = { { "ALLUSERSPROFILE" }, + { "ProgramData" }, { "TEMP" }, { "TMP" }, { "CommonProgramFiles" }, @@ -119,6 +120,12 @@ static void test_create_env(void) r = SetEnvironmentVariableA("SystemRoot", "overwrite"); expect(TRUE, r); + r = GetEnvironmentVariableA("ProgramData", programdata, sizeof(programdata)); + ok(r != 0, "GetEnvironmentVariable failed (%d)\n", GetLastError()); + + r = SetEnvironmentVariableA("ProgramData", "overwrite"); + expect(TRUE, r); + if (0) { /* Crashes on NT4 */ @@ -151,12 +158,20 @@ static void test_create_env(void) r = SetEnvironmentVariableA("SystemRoot", systemroot); expect(TRUE, r); + r = SetEnvironmentVariableA("ProgramData", programdata); + expect(TRUE, r); + for(i=0; i<4; i++) { r = get_env(env[i], "SystemRoot", &st); ok(!strcmp(st, "SystemRoot=overwrite"), "%s\n", st); expect(TRUE, r); HeapFree(GetProcessHeap(), 0, st); + + r = get_env(env[i], "ProgramData", &st); + ok(strcmp(st, "ProgramData=overwrite"), "%s\n", st); + expect(TRUE, r); + HeapFree(GetProcessHeap(), 0, st); } /* Test for common environment variables (NT4 and higher) */ diff --git a/dlls/userenv/userenv_main.c b/dlls/userenv/userenv_main.c index 87ace7d5c11..08dede60d35 100644 --- a/dlls/userenv/userenv_main.c +++ b/dlls/userenv/userenv_main.c @@ -243,7 +243,10 @@ BOOL WINAPI CreateEnvironmentBlock( LPVOID* lpEnvironment, } if (get_reg_value(env, hkey, L"Public", buf, UNICODE_STRING_MAX_CHARS)) + { set_env_var(&env, L"ALLUSERSPROFILE", buf); + set_env_var(&env, L"ProgramData", buf); + } } else { From 5934e8b69cad0b42c34bb9c576a11bcdcca97c1e Mon Sep 17 00:00:00 2001 From: Fabian Maurer Date: Sat, 29 Jan 2022 00:37:03 +0100 Subject: [PATCH 08/83] winhttp/tests: Avoid "misleading indentation" warnings. Signed-off-by: Fabian Maurer Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard (cherry picked from commit 19c758dc56d3171854111908aacb70afe78eeda1) --- dlls/winhttp/tests/winhttp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c index 7e46a43aa05..053f8315fec 100644 --- a/dlls/winhttp/tests/winhttp.c +++ b/dlls/winhttp/tests/winhttp.c @@ -4816,7 +4816,7 @@ static void test_IWinHttpRequest_Invoke(void) VariantInit(&arg[2]); params.cArgs = 3; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYPUT, ¶ms, &ret, NULL, &err); -todo_wine + todo_wine ok(hr == S_OK, "error %#x\n", hr); VariantInit(&arg[0]); @@ -4861,7 +4861,7 @@ todo_wine params.cArgs = 2; hr = IWinHttpRequest_Invoke(request, DISPID_HTTPREQUEST_OPTION, &IID_NULL, 0, DISPATCH_PROPERTYGET, ¶ms, NULL, NULL, NULL); -todo_wine + todo_wine ok(hr == S_OK, "error %#x\n", hr); params.cArgs = 0; From 97ac1bfe354f0c1c3a0121b9e969ac7104313774 Mon Sep 17 00:00:00 2001 From: Alex Henrie Date: Wed, 2 Feb 2022 00:23:17 -0700 Subject: [PATCH 09/83] winhttp: Fix memory leak on error path in WinHttpCrackUrl (Coverity). And use a single variable for the encoded or decoded URL so that free only has to be called once. Signed-off-by: Alex Henrie Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard (cherry picked from commit 2b63fdd9a5fb58951e90af877f79c0a65bd445ec) --- dlls/winhttp/url.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dlls/winhttp/url.c b/dlls/winhttp/url.c index 0d9dfb76de6..8efd5ed0c49 100644 --- a/dlls/winhttp/url.c +++ b/dlls/winhttp/url.c @@ -172,7 +172,7 @@ static DWORD parse_port( const WCHAR *str, DWORD len, INTERNET_PORT *ret ) */ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc ) { - WCHAR *p, *q, *r, *url_decoded = NULL, *url_escaped = NULL; + WCHAR *p, *q, *r, *url_transformed = NULL; INTERNET_SCHEME scheme_number = 0; struct url_component scheme, username, password, hostname, path, extra; BOOL overflow = FALSE; @@ -189,25 +189,26 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN if (flags & ICU_ESCAPE) { - if ((err = escape_url( url, &len, &url_escaped ))) + if ((err = escape_url( url, &len, &url_transformed ))) { SetLastError( err ); return FALSE; } - url = url_escaped; + url = url_transformed; } else if (flags & ICU_DECODE) { - if (!(url_decoded = decode_url( url, &len ))) + if (!(url_transformed = decode_url( url, &len ))) { SetLastError( ERROR_OUTOFMEMORY ); return FALSE; } - url = url_decoded; + url = url_transformed; } if (!(p = wcschr( url, ':' ))) { SetLastError( ERROR_WINHTTP_UNRECOGNIZED_SCHEME ); + free( url_transformed ); return FALSE; } if (p - url == 4 && !wcsnicmp( url, L"http", 4 )) scheme_number = INTERNET_SCHEME_HTTP; @@ -331,8 +332,7 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN if (overflow) err = ERROR_INSUFFICIENT_BUFFER; uc->nScheme = scheme_number; } - free( url_decoded ); - free( url_escaped ); + free( url_transformed ); SetLastError( err ); return !err; } From 7cbc5bf88b98653249b09f17c6e28e27669f951a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:19 +0300 Subject: [PATCH 10/83] hnetcfg: Use CRT allocation functions. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit f20f98825922030364df3ae0ae9c52ac270964f2) CW-Bug-Id: #20062 --- dlls/hnetcfg/apps.c | 21 ++++++++++----------- dlls/hnetcfg/manager.c | 4 ++-- dlls/hnetcfg/policy.c | 14 +++++++------- dlls/hnetcfg/port.c | 13 ++++++------- dlls/hnetcfg/profile.c | 4 ++-- dlls/hnetcfg/service.c | 8 ++++---- 6 files changed, 31 insertions(+), 33 deletions(-) diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index b6447cf4d63..16379e3457b 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -29,7 +29,6 @@ #include "natupnp.h" #include "wine/debug.h" -#include "wine/heap.h" #include "hnetcfg_private.h" WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg); @@ -62,7 +61,7 @@ static ULONG WINAPI fw_app_Release( { TRACE("destroying %p\n", fw_app); SysFreeString( fw_app->filename ); - HeapFree( GetProcessHeap(), 0, fw_app ); + free( fw_app ); } return refs; } @@ -281,7 +280,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( res = WNetGetUniversalNameW(image, UNIVERSAL_NAME_INFO_LEVEL, NULL, &sz); if (res == WN_MORE_DATA) { - if (!(path = heap_alloc(sz))) + if (!(path = malloc(sz))) return E_OUTOFMEMORY; info = (UNIVERSAL_NAME_INFOW *)&path; @@ -291,21 +290,21 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( SysFreeString(This->filename); This->filename = SysAllocString(info->lpUniversalName); } - heap_free(path); + free(path); return HRESULT_FROM_WIN32(res); } sz = GetFullPathNameW(image, 0, NULL, NULL); - if (!(path = heap_alloc(++sz * sizeof(WCHAR)))) + if (!(path = malloc(++sz * sizeof(WCHAR)))) return E_OUTOFMEMORY; GetFullPathNameW(image, sz, path, NULL); longsz = GetLongPathNameW(path, path, sz); if (longsz > sz) { - if (!(path = heap_realloc(path, longsz * sizeof(WCHAR)))) + if (!(path = realloc(path, longsz * sizeof(WCHAR)))) { - heap_free(path); + free(path); return E_OUTOFMEMORY; } GetLongPathNameW(path, path, longsz); @@ -313,7 +312,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( SysFreeString( This->filename ); This->filename = SysAllocString(path); - heap_free(path); + free(path); return This->filename ? S_OK : E_OUTOFMEMORY; } @@ -432,7 +431,7 @@ HRESULT NetFwAuthorizedApplication_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) ); + fa = malloc( sizeof(*fa) ); if (!fa) return E_OUTOFMEMORY; fa->INetFwAuthorizedApplication_iface.lpVtbl = &fw_app_vtbl; @@ -470,7 +469,7 @@ static ULONG WINAPI fw_apps_Release( if (!refs) { TRACE("destroying %p\n", fw_apps); - HeapFree( GetProcessHeap(), 0, fw_apps ); + free( fw_apps ); } return refs; } @@ -645,7 +644,7 @@ HRESULT NetFwAuthorizedApplications_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fa = HeapAlloc( GetProcessHeap(), 0, sizeof(*fa) ); + fa = malloc( sizeof(*fa) ); if (!fa) return E_OUTOFMEMORY; fa->INetFwAuthorizedApplications_iface.lpVtbl = &fw_apps_vtbl; diff --git a/dlls/hnetcfg/manager.c b/dlls/hnetcfg/manager.c index 2c0790a73b5..fda69729901 100644 --- a/dlls/hnetcfg/manager.c +++ b/dlls/hnetcfg/manager.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_manager_Release( if (!refs) { TRACE("destroying %p\n", fw_manager); - HeapFree( GetProcessHeap(), 0, fw_manager ); + free( fw_manager ); } return refs; } @@ -244,7 +244,7 @@ HRESULT NetFwMgr_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fm = HeapAlloc( GetProcessHeap(), 0, sizeof(*fm) ); + fm = malloc( sizeof(*fm) ); if (!fm) return E_OUTOFMEMORY; fm->INetFwMgr_iface.lpVtbl = &fw_manager_vtbl; diff --git a/dlls/hnetcfg/policy.c b/dlls/hnetcfg/policy.c index 1f5b0daa568..7bdc1563d90 100644 --- a/dlls/hnetcfg/policy.c +++ b/dlls/hnetcfg/policy.c @@ -105,7 +105,7 @@ static ULONG WINAPI netfw_rules_Release( if (!refs) { TRACE("destroying %p\n", This); - HeapFree( GetProcessHeap(), 0, This ); + free( This ); } return refs; } @@ -265,7 +265,7 @@ static HRESULT create_INetFwRules(INetFwRules **object) TRACE("(%p)\n", object); - rules = HeapAlloc( GetProcessHeap(), 0, sizeof(*rules) ); + rules = malloc( sizeof(*rules) ); if (!rules) return E_OUTOFMEMORY; rules->INetFwRules_iface.lpVtbl = &fw_rules_vtbl; @@ -292,7 +292,7 @@ static ULONG WINAPI fw_policy_Release( if (!refs) { TRACE("destroying %p\n", fw_policy); - HeapFree( GetProcessHeap(), 0, fw_policy ); + free( fw_policy ); } return refs; } @@ -435,7 +435,7 @@ HRESULT NetFwPolicy_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwPolicy_iface.lpVtbl = &fw_policy_vtbl; @@ -487,7 +487,7 @@ static ULONG WINAPI fwpolicy2_Release(INetFwPolicy2 *iface) { INetFwRules_Release(fw_policy->fw_policy2_rules); TRACE("destroying %p\n", fw_policy); - HeapFree( GetProcessHeap(), 0, fw_policy ); + free( fw_policy ); } return refs; } @@ -768,7 +768,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj ) TRACE("(%p,%p)\n", outer, obj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwPolicy2_iface.lpVtbl = &fw_policy2_vtbl; @@ -778,7 +778,7 @@ HRESULT NetFwPolicy2_create( IUnknown *outer, void **obj ) if (FAILED(create_INetFwRules(&fp->fw_policy2_rules))) { - HeapFree( GetProcessHeap(), 0, fp ); + free( fp ); return E_OUTOFMEMORY; } diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index fd4ac4977d3..9e9264df1dc 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -28,7 +28,6 @@ #include "netfw.h" #include "natupnp.h" -#include "wine/heap.h" #include "wine/debug.h" #include "hnetcfg_private.h" @@ -64,7 +63,7 @@ static ULONG WINAPI fw_port_Release( { TRACE("destroying %p\n", fw_port); SysFreeString( fw_port->name ); - HeapFree( GetProcessHeap(), 0, fw_port ); + free( fw_port ); } return refs; } @@ -363,7 +362,7 @@ HRESULT NetFwOpenPort_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwOpenPort_iface.lpVtbl = &fw_port_vtbl; @@ -404,7 +403,7 @@ static ULONG WINAPI fw_ports_Release( if (!refs) { TRACE("destroying %p\n", fw_ports); - HeapFree( GetProcessHeap(), 0, fw_ports ); + free( fw_ports ); } return refs; } @@ -592,7 +591,7 @@ HRESULT NetFwOpenPorts_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwOpenPorts_iface.lpVtbl = &fw_ports_vtbl; @@ -653,7 +652,7 @@ static ULONG WINAPI upnpnat_Release(IUPnPNAT *iface) LONG refs = InterlockedDecrement( &This->ref ); if (!refs) { - heap_free( This ); + free( This ); } return refs; } @@ -762,7 +761,7 @@ HRESULT IUPnPNAT_create(IUnknown *outer, void **object) TRACE("(%p,%p)\n", outer, object); - nat = heap_alloc( sizeof(*nat) ); + nat = malloc( sizeof(*nat) ); if (!nat) return E_OUTOFMEMORY; nat->IUPnPNAT_iface.lpVtbl = &upnpnat_vtbl; diff --git a/dlls/hnetcfg/profile.c b/dlls/hnetcfg/profile.c index d0e9f48dab4..63f6d0cc7ed 100644 --- a/dlls/hnetcfg/profile.c +++ b/dlls/hnetcfg/profile.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_profile_Release( if (!refs) { TRACE("destroying %p\n", fw_profile); - HeapFree( GetProcessHeap(), 0, fw_profile ); + free( fw_profile ); } return refs; } @@ -334,7 +334,7 @@ HRESULT NetFwProfile_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwProfile_iface.lpVtbl = &fw_profile_vtbl; diff --git a/dlls/hnetcfg/service.c b/dlls/hnetcfg/service.c index 5bfeedaaedf..122d9797bab 100644 --- a/dlls/hnetcfg/service.c +++ b/dlls/hnetcfg/service.c @@ -58,7 +58,7 @@ static ULONG WINAPI fw_service_Release( if (!refs) { TRACE("destroying %p\n", fw_service); - HeapFree( GetProcessHeap(), 0, fw_service ); + free( fw_service ); } return refs; } @@ -290,7 +290,7 @@ static HRESULT NetFwService_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwService_iface.lpVtbl = &fw_service_vtbl; @@ -328,7 +328,7 @@ static ULONG WINAPI fw_services_Release( if (!refs) { TRACE("destroying %p\n", fw_services); - HeapFree( GetProcessHeap(), 0, fw_services ); + free( fw_services ); } return refs; } @@ -464,7 +464,7 @@ HRESULT NetFwServices_create( IUnknown *pUnkOuter, LPVOID *ppObj ) TRACE("(%p,%p)\n", pUnkOuter, ppObj); - fp = HeapAlloc( GetProcessHeap(), 0, sizeof(*fp) ); + fp = malloc( sizeof(*fp) ); if (!fp) return E_OUTOFMEMORY; fp->INetFwServices_iface.lpVtbl = &fw_services_vtbl; From 3f16573dae877da487e511c5c9646565a8902e3d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:20 +0300 Subject: [PATCH 11/83] hnetcfg/tests: Add tests for static port mapping collection. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 162dc17e09aaeb169807bf076140ba62805284f0) CW-Bug-Id: #20062 --- dlls/hnetcfg/tests/policy.c | 132 +++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index e2606933079..6abdcd7fb4e 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -29,6 +29,12 @@ #include "netfw.h" #include "natupnp.h" +static ULONG get_refcount(IUnknown *unk) +{ + IUnknown_AddRef(unk); + return IUnknown_Release(unk); +} + static void test_policy2_rules(INetFwPolicy2 *policy2) { HRESULT hr; @@ -164,6 +170,119 @@ static void test_NetFwAuthorizedApplication(void) INetFwAuthorizedApplication_Release(app); } +static void test_static_port_mapping_collection( IStaticPortMappingCollection *ports ) +{ + LONG i, count, count2, expected_count, external_port; + IStaticPortMapping *pm, *pm2; + ULONG refcount, refcount2; + IEnumVARIANT *enum_ports; + IUnknown *unk; + ULONG fetched; + BSTR protocol; + VARIANT var; + HRESULT hr; + + refcount = get_refcount((IUnknown *)ports); + hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + refcount2 = get_refcount((IUnknown *)ports); + ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2); + + hr = IEnumVARIANT_Reset(enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + count = 0xdeadbeef; + hr = IStaticPortMappingCollection_get_Count(ports, &count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", &pm); + if (SUCCEEDED(hr)) + { + expected_count = count; + IStaticPortMapping_Release(pm); + } + else + { + expected_count = count + 1; + } + + hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4", + VARIANT_TRUE, (BSTR)L"wine_test", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4", + VARIANT_TRUE, (BSTR)L"wine_test", &pm); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Count(ports, &count2); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"UDP", NULL); + ok(hr == E_POINTER, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12345, (BSTR)L"udp", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, -1, (BSTR)L"UDP", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 65536, (BSTR)L"UDP", &pm); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_get_Item(ports, 12346, (BSTR)L"UDP", &pm); + ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "Got unexpected hr %#x.\n", hr); + + hr = IEnumVARIANT_Reset(enum_ports); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + for (i = 0; i < count2; ++i) + { + VariantInit(&var); + + fetched = 0xdeadbeef; + hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(fetched == 1, "Got unexpected fetched %u.\n", fetched); + ok(V_VT(&var) == VT_DISPATCH, "Got unexpected variant type %u.\n", V_VT(&var)); + + hr = IDispatch_QueryInterface(V_DISPATCH(&var), &IID_IStaticPortMapping, (void **)&pm); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMapping_get_Protocol(pm, &protocol); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + external_port = 0xdeadbeef; + hr = IStaticPortMapping_get_ExternalPort(pm, &external_port); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + ok(!wcscmp(protocol, L"UDP") || !wcscmp(protocol, L"TCP"), "Got unexpected protocol %s.\n", + debugstr_w(protocol)); + hr = IStaticPortMappingCollection_get_Item(ports, external_port, protocol, &pm2); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(pm2 != pm, "Got same interface.\n"); + + IStaticPortMapping_Release(pm); + IStaticPortMapping_Release(pm2); + + SysFreeString(protocol); + + VariantClear(&var); + } + hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched); + ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr); + + hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + IEnumVARIANT_Release(enum_ports); +} + static void test_IUPnPNAT(void) { IUPnPNAT *nat; @@ -171,6 +290,7 @@ static void test_IUPnPNAT(void) IDynamicPortMappingCollection *dync_ports; INATEventManager *manager; IProvideClassInfo *provider; + ULONG refcount, refcount2; HRESULT hr; hr = CoCreateInstance(&CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER, &IID_IUPnPNAT, (void**)&nat); @@ -179,11 +299,21 @@ static void test_IUPnPNAT(void) hr = IUPnPNAT_QueryInterface(nat, &IID_IProvideClassInfo, (void**)&provider); ok(hr == E_NOINTERFACE, "got: %08x\n", hr); + refcount = get_refcount((IUnknown *)nat); hr = IUPnPNAT_get_StaticPortMappingCollection(nat, &static_ports); + ok(hr == S_OK, "got: %08x\n", hr); if(hr == S_OK && static_ports) + { + refcount2 = get_refcount((IUnknown *)nat); + ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2); + test_static_port_mapping_collection( static_ports ); IStaticPortMappingCollection_Release(static_ports); - + } + else if (hr == S_OK) + { + skip( "UPNP gateway not found.\n" ); + } hr = IUPnPNAT_get_DynamicPortMappingCollection(nat, &dync_ports); ok(hr == S_OK || hr == E_NOTIMPL /* Windows 8.1 */, "got: %08x\n", hr); if(hr == S_OK && dync_ports) From a4caa6be02bcead729c6b6dab1c5b9df35f17d0f Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:21 +0300 Subject: [PATCH 12/83] hnetcfg: Return stub interface from upnpnat_get_StaticPortMappingCollection() if UPNP IGD is found. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit cbf2ca57749874a34f0ce19f30431577fa8a4e66) CW-Bug-Id: #20062 --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/apps.c | 3 +- dlls/hnetcfg/hnetcfg_private.h | 1 + dlls/hnetcfg/port.c | 348 ++++++++++++++++++++++++++++++++- dlls/hnetcfg/tests/policy.c | 3 +- 5 files changed, 350 insertions(+), 7 deletions(-) diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 0a4cb8dd334..5eef7af473f 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,6 +1,6 @@ MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid - +DELAYIMPORTS = ws2_32 EXTRADLLFLAGS = -Wb,--prefer-native C_SRCS = \ diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index 16379e3457b..c5fe5e41f5e 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -114,7 +114,8 @@ static REFIID tid_id[] = &IID_INetFwPolicy, &IID_INetFwPolicy2, &IID_INetFwProfile, - &IID_IUPnPNAT + &IID_IUPnPNAT, + &IID_IStaticPortMappingCollection, }; HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret ) diff --git a/dlls/hnetcfg/hnetcfg_private.h b/dlls/hnetcfg/hnetcfg_private.h index be2d0f3c7c6..91fef756464 100644 --- a/dlls/hnetcfg/hnetcfg_private.h +++ b/dlls/hnetcfg/hnetcfg_private.h @@ -28,6 +28,7 @@ enum type_id INetFwProfile_tid, INetFwRules_tid, IUPnPNAT_tid, + IStaticPortMappingCollection_tid, last_tid }; diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 9e9264df1dc..89a3f571d45 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -24,6 +24,9 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "string.h" +#include "assert.h" +#include "winsock2.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -33,6 +36,343 @@ WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg); +static struct +{ + LONG refs; + BOOL winsock_initialized; +} +upnp_gateway_connection; + +static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT; + +static void gateway_connection_cleanup(void) +{ + TRACE( ".\n" ); + if (upnp_gateway_connection.winsock_initialized) WSACleanup(); + memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) ); +} + +static BOOL init_gateway_connection(void) +{ + static const char upnp_search_request[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST:239.255.255.250:1900\r\n" + "ST:upnp:rootdevice\r\n" + "MX:2\r\n" + "MAN:\"ssdp:discover\"\r\n" + "\r\n"; + + const DWORD timeout = 1000; + int len, address_len; + char buffer[2048]; + SOCKADDR_IN addr; + WSADATA wsa_data; + unsigned int i; + SOCKET s; + + upnp_gateway_connection.winsock_initialized = WSAStartup( MAKEWORD( 2, 2 ), &wsa_data ); + if ((s = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == -1) + { + ERR( "Failed to create socket, error %u.\n", WSAGetLastError() ); + return FALSE; + } + if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)) == SOCKET_ERROR) + { + ERR( "setsockopt(SO_RCVTIME0) failed, error %u.\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + addr.sin_family = AF_INET; + addr.sin_port = htons( 1900 ); + addr.sin_addr.S_un.S_addr = inet_addr( "239.255.255.250" ); + if (sendto( s, upnp_search_request, strlen( upnp_search_request ), 0, (SOCKADDR *)&addr, sizeof(addr) ) + == SOCKET_ERROR) + { + ERR( "sendto failed, error %u\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + /* Windows has a dedicated SSDP discovery service which maintains gateway device info and does + * not usually delay in get_StaticPortMappingCollection(). Although it may still delay depending + * on network connection state and always delays in IUPnPNAT_get_NATEventManager(). */ + FIXME( "Waiting for reply from router.\n" ); + for (i = 0; i < 2; ++i) + { + address_len = sizeof(addr); + len = recvfrom( s, buffer, sizeof(buffer) - 1, 0, (SOCKADDR *)&addr, &address_len ); + if (len == -1) + { + if (WSAGetLastError() != WSAETIMEDOUT) + { + WARN( "recvfrom error %u.\n", WSAGetLastError() ); + closesocket( s ); + return FALSE; + } + } + else break; + } + closesocket( s ); + if (i == 2) + { + TRACE( "No reply from router.\n" ); + return FALSE; + } + TRACE( "Received reply from gateway, len %d.\n", len ); + return TRUE; +} + +static BOOL grab_gateway_connection(void) +{ + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + if (!upnp_gateway_connection.refs && !init_gateway_connection()) + { + gateway_connection_cleanup(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return FALSE; + } + ++upnp_gateway_connection.refs; + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return TRUE; +} + +static void release_gateway_connection(void) +{ + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + assert( upnp_gateway_connection.refs ); + if (!--upnp_gateway_connection.refs) + gateway_connection_cleanup(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); +} + +struct static_port_mapping_collection +{ + IStaticPortMappingCollection IStaticPortMappingCollection_iface; + LONG refs; +}; + +static inline struct static_port_mapping_collection *impl_from_IStaticPortMappingCollection + ( IStaticPortMappingCollection *iface ) +{ + return CONTAINING_RECORD(iface, struct static_port_mapping_collection, IStaticPortMappingCollection_iface); +} + +static ULONG WINAPI static_ports_AddRef( + IStaticPortMappingCollection *iface ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + return InterlockedIncrement( &ports->refs ); +} + +static ULONG WINAPI static_ports_Release( + IStaticPortMappingCollection *iface ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + LONG refs = InterlockedDecrement( &ports->refs ); + if (!refs) + { + TRACE("destroying %p\n", ports); + release_gateway_connection(); + free( ports ); + } + return refs; +} + +static HRESULT WINAPI static_ports_QueryInterface( + IStaticPortMappingCollection *iface, + REFIID riid, + void **ppvObject ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %s %p\n", ports, debugstr_guid( riid ), ppvObject ); + + if ( IsEqualGUID( riid, &IID_IStaticPortMappingCollection ) || + IsEqualGUID( riid, &IID_IDispatch ) || + IsEqualGUID( riid, &IID_IUnknown ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IStaticPortMappingCollection_AddRef( iface ); + return S_OK; +} + +static HRESULT WINAPI static_ports_GetTypeInfoCount( + IStaticPortMappingCollection *iface, + UINT *pctinfo ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %p\n", ports, pctinfo); + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI static_ports_GetTypeInfo( + IStaticPortMappingCollection *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + + TRACE("%p %u %u %p\n", ports, iTInfo, lcid, ppTInfo); + return get_typeinfo( IStaticPortMappingCollection_tid, ppTInfo ); +} + +static HRESULT WINAPI static_ports_GetIDsOfNames( + IStaticPortMappingCollection *iface, + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %s %p %u %u %p\n", ports, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetIDsOfNames( typeinfo, rgszNames, cNames, rgDispId ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_ports_Invoke( + IStaticPortMappingCollection *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr ) +{ + struct static_port_mapping_collection *ports = impl_from_IStaticPortMappingCollection( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %d %s %d %d %p %p %p %p\n", ports, dispIdMember, debugstr_guid(riid), + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + hr = get_typeinfo( IStaticPortMappingCollection_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_Invoke( typeinfo, &ports->IStaticPortMappingCollection_iface, dispIdMember, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_ports__NewEnum( + IStaticPortMappingCollection *iface, + IUnknown **ret ) +{ + FIXME( "iface %p, ret %p stub.\n", iface, ret ); + + if (ret) *ret = NULL; + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_get_Item( + IStaticPortMappingCollection *iface, + LONG port, + BSTR protocol, + IStaticPortMapping **mapping ) +{ + FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + + if (mapping) *mapping = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_get_Count( + IStaticPortMappingCollection *iface, + LONG *count ) +{ + FIXME( "iface %p, count %p stub.\n", iface, count ); + + if (count) *count = 0; + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_Remove( + IStaticPortMappingCollection *iface, + LONG port, + BSTR protocol ) +{ + FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_ports_Add( + IStaticPortMappingCollection *iface, + LONG external, + BSTR protocol, + LONG internal, + BSTR client, + VARIANT_BOOL enabled, + BSTR description, + IStaticPortMapping **mapping ) +{ + FIXME( "iface %p, external %d, protocol %s, internal %d, client %s, enabled %d, descritption %s, mapping %p stub.\n", + iface, external, debugstr_w(protocol), internal, debugstr_w(client), enabled, debugstr_w(description), + mapping ); + + if (mapping) *mapping = NULL; + return E_NOTIMPL; +} + +static const IStaticPortMappingCollectionVtbl static_ports_vtbl = +{ + static_ports_QueryInterface, + static_ports_AddRef, + static_ports_Release, + static_ports_GetTypeInfoCount, + static_ports_GetTypeInfo, + static_ports_GetIDsOfNames, + static_ports_Invoke, + static_ports__NewEnum, + static_ports_get_Item, + static_ports_get_Count, + static_ports_Remove, + static_ports_Add, +}; + +static HRESULT static_port_mapping_collection_create(IStaticPortMappingCollection **object) +{ + struct static_port_mapping_collection *ports; + + if (!object) return E_POINTER; + if (!grab_gateway_connection()) + { + *object = NULL; + return S_OK; + } + if (!(ports = calloc( 1, sizeof(*ports) ))) + { + release_gateway_connection(); + return E_OUTOFMEMORY; + } + ports->refs = 1; + ports->IStaticPortMappingCollection_iface.lpVtbl = &static_ports_vtbl; + *object = &ports->IStaticPortMappingCollection_iface; + return S_OK; +} + typedef struct fw_port { INetFwOpenPort INetFwOpenPort_iface; @@ -716,10 +1056,10 @@ static HRESULT WINAPI upnpnat_Invoke(IUPnPNAT *iface, DISPID dispIdMember, REFII static HRESULT WINAPI upnpnat_get_StaticPortMappingCollection(IUPnPNAT *iface, IStaticPortMappingCollection **collection) { upnpnat *This = impl_from_IUPnPNAT( iface ); - FIXME("%p, %p\n", This, collection); - if(collection) - *collection = NULL; - return S_OK; + + TRACE("%p, %p\n", This, collection); + + return static_port_mapping_collection_create( collection ); } static HRESULT WINAPI upnpnat_get_DynamicPortMappingCollection(IUPnPNAT *iface, IDynamicPortMappingCollection **collection) diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index 6abdcd7fb4e..19b6e3f6f2e 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -184,7 +184,8 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p refcount = get_refcount((IUnknown *)ports); hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + if (FAILED(hr)) return; hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); From de1d4516db488748343615e264cb1afba76818d3 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:22 +0300 Subject: [PATCH 13/83] hnetcfg: Get gateway description location in init_gateway_connection(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 583605be049af1ad8a7551b7073c15832b2644a0) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 89a3f571d45..fa866d874c9 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -27,6 +27,7 @@ #include "string.h" #include "assert.h" #include "winsock2.h" +#include "winhttp.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -40,11 +41,49 @@ static struct { LONG refs; BOOL winsock_initialized; + WCHAR locationW[256]; } upnp_gateway_connection; static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT; +static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned int location_size ) +{ + char *saveptr = NULL, *tok, *tok2; + unsigned int status; + + tok = strtok_s( response, "\n", &saveptr ); + if (!tok) return FALSE; + + /* HTTP/1.1 200 OK */ + tok2 = strtok( tok, " " ); + if (!tok2) return FALSE; + tok2 = strtok( NULL, " " ); + if (!tok2) return FALSE; + status = atoi( tok2 ); + if (status != HTTP_STATUS_OK) + { + WARN( "status %u.\n", status ); + return FALSE; + } + while ((tok = strtok_s( NULL, "\n", &saveptr ))) + { + tok2 = strtok( tok, " " ); + if (!tok2) continue; + if (!stricmp( tok2, "LOCATION:" )) + { + tok2 = strtok( NULL, " \r" ); + if (!tok2) + { + WARN( "Error parsing location.\n" ); + return FALSE; + } + return !!MultiByteToWideChar( CP_UTF8, 0, tok2, -1, locationW, location_size / 2 ); + } + } + return FALSE; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); @@ -118,6 +157,13 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Received reply from gateway, len %d.\n", len ); + buffer[len] = 0; + if (!parse_search_response( buffer, upnp_gateway_connection.locationW, sizeof(upnp_gateway_connection.locationW) )) + { + WARN( "Error parsing response.\n" ); + return FALSE; + } + TRACE( "Gateway description location %s.\n", debugstr_w(upnp_gateway_connection.locationW) ); return TRUE; } From f6b2602110a931ac36a4795478815512b237126d Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:23 +0300 Subject: [PATCH 14/83] hnetcfg: Open connection to gateway in init_gateway_connection(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit c091620889195e761854dfd1cbdfb9ff58548abd) CW-Bug-Id: #20062 --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/port.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 5eef7af473f..99677c314f8 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,6 +1,6 @@ MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid -DELAYIMPORTS = ws2_32 +DELAYIMPORTS = ws2_32 winhttp EXTRADLLFLAGS = -Wb,--prefer-native C_SRCS = \ diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index fa866d874c9..b1d5398a01a 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -42,6 +42,7 @@ static struct LONG refs; BOOL winsock_initialized; WCHAR locationW[256]; + HINTERNET session, connection; } upnp_gateway_connection; @@ -84,9 +85,43 @@ static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned in return FALSE; } +static BOOL open_gateway_connection(void) +{ + static const int timeout = 3000; + + WCHAR hostname[64], urlpath[128]; + URL_COMPONENTS url; + + memset( &url, 0, sizeof(url) ); + url.dwStructSize = sizeof(url); + url.lpszHostName = hostname; + url.dwHostNameLength = ARRAY_SIZE(hostname); + url.lpszUrlPath = urlpath; + url.dwUrlPathLength = ARRAY_SIZE(urlpath); + + if (!WinHttpCrackUrl( upnp_gateway_connection.locationW, 0, 0, &url )) return FALSE; + + upnp_gateway_connection.session = WinHttpOpen( L"hnetcfg", WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0 ); + if (!upnp_gateway_connection.session) return FALSE; + if (!WinHttpSetTimeouts( upnp_gateway_connection.session, timeout, timeout, timeout, timeout )) + return FALSE; + + TRACE( "hostname %s, urlpath %s, port %u.\n", debugstr_w(hostname), debugstr_w(urlpath), url.nPort ); + upnp_gateway_connection.connection = WinHttpConnect ( upnp_gateway_connection.session, hostname, url.nPort, 0 ); + if (!upnp_gateway_connection.connection) + { + WARN( "WinHttpConnect error %u.\n", GetLastError() ); + return FALSE; + } + return TRUE; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); + WinHttpCloseHandle( upnp_gateway_connection.connection ); + WinHttpCloseHandle( upnp_gateway_connection.session ); if (upnp_gateway_connection.winsock_initialized) WSACleanup(); memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) ); } @@ -164,6 +199,12 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Gateway description location %s.\n", debugstr_w(upnp_gateway_connection.locationW) ); + if (!open_gateway_connection()) + { + WARN( "Error opening gateway connection.\n" ); + return FALSE; + } + TRACE( "Opened gateway connection.\n" ); return TRUE; } From 1a49f69ebb19368c611986cfd6333b6cfe99659b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Feb 2022 13:49:24 +0300 Subject: [PATCH 15/83] hnetcfg: Get control URL for WANIPConnection service in init_gateway_connection(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 42d12db0ee5c9d77a5be960c897bdff169341629) CW-Bug-Id: #20062 --- dlls/hnetcfg/Makefile.in | 2 +- dlls/hnetcfg/port.c | 166 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 5 deletions(-) diff --git a/dlls/hnetcfg/Makefile.in b/dlls/hnetcfg/Makefile.in index 99677c314f8..0ff7c511eb4 100644 --- a/dlls/hnetcfg/Makefile.in +++ b/dlls/hnetcfg/Makefile.in @@ -1,6 +1,6 @@ MODULE = hnetcfg.dll IMPORTS = oleaut32 ole32 advapi32 mpr uuid -DELAYIMPORTS = ws2_32 winhttp +DELAYIMPORTS = ws2_32 winhttp shcore xmllite EXTRADLLFLAGS = -Wb,--prefer-native C_SRCS = \ diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index b1d5398a01a..389e36f4d50 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -25,9 +25,12 @@ #include "winbase.h" #include "winuser.h" #include "string.h" +#include "initguid.h" #include "assert.h" #include "winsock2.h" #include "winhttp.h" +#include "shlwapi.h" +#include "xmllite.h" #include "ole2.h" #include "netfw.h" #include "natupnp.h" @@ -43,6 +46,9 @@ static struct BOOL winsock_initialized; WCHAR locationW[256]; HINTERNET session, connection; + WCHAR desc_urlpath[128]; + WCHAR control_url[256]; + unsigned int version; } upnp_gateway_connection; @@ -85,19 +91,99 @@ static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned in return FALSE; } +static BOOL parse_desc_xml( const char *desc_xml ) +{ + static const WCHAR urn_wanipconnection[] = L"urn:schemas-upnp-org:service:WANIPConnection:"; + WCHAR control_url[ARRAY_SIZE(upnp_gateway_connection.control_url)]; + BOOL service_type_matches, control_url_found, found = FALSE; + unsigned int version = 0; + XmlNodeType node_type; + IXmlReader *reader; + const WCHAR *value; + BOOL ret = FALSE; + IStream *stream; + HRESULT hr; + + if (!(stream = SHCreateMemStream( (BYTE *)desc_xml, strlen( desc_xml ) + 1 ))) return FALSE; + if (FAILED(hr = CreateXmlReader( &IID_IXmlReader, (void **)&reader, NULL ))) + { + IStream_Release( stream ); + return FALSE; + } + if (FAILED(hr = IXmlReader_SetInput( reader, (IUnknown*)stream ))) goto done; + + while (SUCCEEDED(IXmlReader_Read( reader, &node_type )) && node_type != XmlNodeType_None) + { + if (node_type != XmlNodeType_Element) continue; + + if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL ))) goto done; + if (wcsicmp( value, L"service" )) continue; + control_url_found = service_type_matches = FALSE; + while (SUCCEEDED(IXmlReader_Read( reader, &node_type ))) + { + if (node_type != XmlNodeType_Element && node_type != XmlNodeType_EndElement) continue; + if (FAILED(IXmlReader_GetLocalName( reader, &value, NULL ))) + { + WARN( "IXmlReader_GetLocalName failed.\n" ); + goto done; + } + if (node_type == XmlNodeType_EndElement) + { + if (!wcsicmp( value, L"service" )) break; + continue; + } + if (!wcsicmp( value, L"serviceType" )) + { + if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done; + if (node_type != XmlNodeType_Text) goto done; + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + if (wcsnicmp( value, urn_wanipconnection, ARRAY_SIZE(urn_wanipconnection) - 1 )) break; + version = _wtoi( value + ARRAY_SIZE(urn_wanipconnection) - 1 ); + service_type_matches = version >= 1; + } + else if (!wcsicmp( value, L"controlURL" )) + { + if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done; + if (node_type != XmlNodeType_Text) goto done; + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + if (wcslen( value ) + 1 > ARRAY_SIZE(control_url)) goto done; + wcscpy( control_url, value ); + control_url_found = TRUE; + } + } + if (service_type_matches && control_url_found) + { + if (found) + { + FIXME( "Found another WANIPConnection service, ignoring.\n" ); + continue; + } + found = TRUE; + wcscpy( upnp_gateway_connection.control_url, control_url ); + upnp_gateway_connection.version = version; + } + } + + ret = found; +done: + IXmlReader_Release( reader ); + IStream_Release( stream ); + return ret; +} + static BOOL open_gateway_connection(void) { static const int timeout = 3000; - WCHAR hostname[64], urlpath[128]; + WCHAR hostname[64]; URL_COMPONENTS url; memset( &url, 0, sizeof(url) ); url.dwStructSize = sizeof(url); url.lpszHostName = hostname; url.dwHostNameLength = ARRAY_SIZE(hostname); - url.lpszUrlPath = urlpath; - url.dwUrlPathLength = ARRAY_SIZE(urlpath); + url.lpszUrlPath = upnp_gateway_connection.desc_urlpath; + url.dwUrlPathLength = ARRAY_SIZE(upnp_gateway_connection.desc_urlpath); if (!WinHttpCrackUrl( upnp_gateway_connection.locationW, 0, 0, &url )) return FALSE; @@ -107,7 +193,8 @@ static BOOL open_gateway_connection(void) if (!WinHttpSetTimeouts( upnp_gateway_connection.session, timeout, timeout, timeout, timeout )) return FALSE; - TRACE( "hostname %s, urlpath %s, port %u.\n", debugstr_w(hostname), debugstr_w(urlpath), url.nPort ); + TRACE( "hostname %s, urlpath %s, port %u.\n", + debugstr_w(hostname), debugstr_w(upnp_gateway_connection.desc_urlpath), url.nPort ); upnp_gateway_connection.connection = WinHttpConnect ( upnp_gateway_connection.session, hostname, url.nPort, 0 ); if (!upnp_gateway_connection.connection) { @@ -117,6 +204,69 @@ static BOOL open_gateway_connection(void) return TRUE; } +static BOOL get_control_url(void) +{ + static const WCHAR *accept_types[] = + { + L"text/xml", + NULL + }; + unsigned int desc_xml_size, offset; + DWORD size, status = 0; + HINTERNET request; + char *desc_xml; + BOOL ret; + + request = WinHttpOpenRequest( upnp_gateway_connection.connection, NULL, upnp_gateway_connection.desc_urlpath, NULL, + WINHTTP_NO_REFERER, accept_types, 0 ); + if (!request) return FALSE; + + if (!WinHttpSendRequest( request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, NULL, 0, 0, 0 )) + { + WARN( "Error sending request %u.\n", GetLastError() ); + WinHttpCloseHandle( request ); + return FALSE; + } + if (!WinHttpReceiveResponse(request, NULL)) + { + WARN( "Error receiving response %u.\n", GetLastError() ); + WinHttpCloseHandle( request ); + return FALSE; + } + size = sizeof(status); + if (!WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, &status, &size, NULL) || status != HTTP_STATUS_OK ) + { + WARN( "Error response from server, error %u, http status %u.\n", GetLastError(), status ); + WinHttpCloseHandle( request ); + return FALSE; + } + desc_xml_size = 1024; + desc_xml = malloc( desc_xml_size ); + offset = 0; + while (WinHttpReadData( request, desc_xml + offset, desc_xml_size - offset - 1, &size ) && size) + { + offset += size; + if (offset + 1 == desc_xml_size) + { + char *new; + + desc_xml_size *= 2; + if (!(new = realloc( desc_xml, desc_xml_size ))) + { + ERR( "No memory.\n" ); + break; + } + desc_xml = new; + } + } + desc_xml[offset] = 0; + WinHttpCloseHandle( request ); + ret = parse_desc_xml( desc_xml ); + free( desc_xml ); + return ret; +} + static void gateway_connection_cleanup(void) { TRACE( ".\n" ); @@ -205,6 +355,14 @@ static BOOL init_gateway_connection(void) return FALSE; } TRACE( "Opened gateway connection.\n" ); + if (!get_control_url()) + { + WARN( "Could not get_control URL.\n" ); + gateway_connection_cleanup(); + return FALSE; + } + TRACE( "control_url %s, version %u.\n", debugstr_w(upnp_gateway_connection.control_url), + upnp_gateway_connection.version ); return TRUE; } From 47a84b577b46ae6bdb5c03a4c3953ac35d326812 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:53 +0300 Subject: [PATCH 16/83] hnetcfg: Fix realloc handling in fw_app_put_ProcessImageFileName(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 42b2a69a67b78163a1b2ed091dee0abd74745c57) CW-Bug-Id: #20062 --- dlls/hnetcfg/apps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index c5fe5e41f5e..f351e2482e8 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -269,7 +269,7 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( fw_app *This = impl_from_INetFwAuthorizedApplication( iface ); UNIVERSAL_NAME_INFOW *info; DWORD sz, longsz; - WCHAR *path; + WCHAR *path, *new_path; DWORD res; FIXME("%p, %s\n", This, debugstr_w(image)); @@ -303,11 +303,12 @@ static HRESULT WINAPI fw_app_put_ProcessImageFileName( longsz = GetLongPathNameW(path, path, sz); if (longsz > sz) { - if (!(path = realloc(path, longsz * sizeof(WCHAR)))) + if (!(new_path = realloc(path, longsz * sizeof(WCHAR)))) { free(path); return E_OUTOFMEMORY; } + path = new_path; GetLongPathNameW(path, path, longsz); } From 7d5625594724cbf8052949364428c67af35592ba Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:54 +0300 Subject: [PATCH 17/83] hnetcfg: Get port mapping list in init_gateway_connection(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit e98a102bdda143aec57851f93220cc362fa7e325) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 306 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 389e36f4d50..070ba1ef7ab 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -40,6 +40,23 @@ WINE_DEFAULT_DEBUG_CHANNEL(hnetcfg); +struct port_mapping +{ + BSTR external_ip; + LONG external; + BSTR protocol; + LONG internal; + BSTR client; + VARIANT_BOOL enabled; + BSTR descr; +}; + +struct xml_value_desc +{ + const WCHAR *name; + BSTR value; +}; + static struct { LONG refs; @@ -49,11 +66,32 @@ static struct WCHAR desc_urlpath[128]; WCHAR control_url[256]; unsigned int version; + struct port_mapping *mappings; + unsigned int mapping_count; } upnp_gateway_connection; static SRWLOCK upnp_gateway_connection_lock = SRWLOCK_INIT; +static void free_port_mapping( struct port_mapping *mapping ) +{ + SysFreeString( mapping->external_ip ); + SysFreeString( mapping->protocol ); + SysFreeString( mapping->client ); + SysFreeString( mapping->descr ); +} + +static void free_mappings(void) +{ + unsigned int i; + + for (i = 0; i < upnp_gateway_connection.mapping_count; ++i) + free_port_mapping( &upnp_gateway_connection.mappings[i] ); + free( upnp_gateway_connection.mappings ); + upnp_gateway_connection.mappings = NULL; + upnp_gateway_connection.mapping_count = 0; +} + static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned int location_size ) { char *saveptr = NULL, *tok, *tok2; @@ -171,6 +209,64 @@ static BOOL parse_desc_xml( const char *desc_xml ) return ret; } +static BOOL get_xml_elements( const char *desc_xml, struct xml_value_desc *values, unsigned int value_count ) +{ + XmlNodeType node_type; + IXmlReader *reader; + const WCHAR *value; + BOOL ret = FALSE; + IStream *stream; + unsigned int i; + HRESULT hr; + + for (i = 0; i < value_count; ++i) assert( !values[i].value ); + + if (!(stream = SHCreateMemStream( (BYTE *)desc_xml, strlen( desc_xml ) + 1 ))) return FALSE; + if (FAILED(hr = CreateXmlReader( &IID_IXmlReader, (void **)&reader, NULL ))) + { + IStream_Release( stream ); + return FALSE; + } + if (FAILED(hr = IXmlReader_SetInput( reader, (IUnknown*)stream ))) goto done; + + while (SUCCEEDED(IXmlReader_Read( reader, &node_type )) && node_type != XmlNodeType_None) + { + if (node_type != XmlNodeType_Element) continue; + + if (FAILED(IXmlReader_GetQualifiedName( reader, &value, NULL ))) goto done; + for (i = 0; i < value_count; ++i) + if (!wcsicmp( value, values[i].name )) break; + if (i == value_count) continue; + if (FAILED(IXmlReader_Read(reader, &node_type ))) goto done; + if (node_type != XmlNodeType_Text) + { + if (node_type == XmlNodeType_EndElement) value = L""; + else goto done; + } + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + if (values[i].value) + { + WARN( "Duplicate value %s.\n", debugstr_w(values[i].name) ); + goto done; + } + if (!(values[i].value = SysAllocString( value ))) goto done; + } + ret = TRUE; + +done: + if (!ret) + { + for (i = 0; i < value_count; ++i) + { + SysFreeString( values[i].value ); + values[i].value = NULL; + } + } + IXmlReader_Release( reader ); + IStream_Release( stream ); + return ret; +} + static BOOL open_gateway_connection(void) { static const int timeout = 3000; @@ -270,12 +366,220 @@ static BOOL get_control_url(void) static void gateway_connection_cleanup(void) { TRACE( ".\n" ); + free_mappings(); WinHttpCloseHandle( upnp_gateway_connection.connection ); WinHttpCloseHandle( upnp_gateway_connection.session ); if (upnp_gateway_connection.winsock_initialized) WSACleanup(); memset( &upnp_gateway_connection, 0, sizeof(upnp_gateway_connection) ); } +static BOOL request_service( const WCHAR *function, const struct xml_value_desc *request_param, + unsigned int request_param_count, struct xml_value_desc *result, + unsigned int result_count, DWORD *http_status, BSTR *server_error_code_str ) +{ + static const char request_template_header[] = + "\r\n" + "\r\n" + " \r\n" + " \r\n"; + static const char request_template_footer[] = + " \r\n" + " \r\n" + "\r\n"; + + unsigned int request_data_size, request_len, offset, i, reply_buffer_size; + char *request_data, *reply_buffer = NULL, *ptr; + struct xml_value_desc error_value_desc; + WCHAR request_headers[1024]; + HINTERNET request = NULL; + BOOL ret = FALSE; + DWORD size; + + *server_error_code_str = NULL; + request_data_size = strlen(request_template_header) + strlen(request_template_footer) + 2 * wcslen( function ) + + 9 /* version + zero terminator */; + for (i = 0; i < request_param_count; ++i) + { + request_data_size += 13 + 2 * wcslen( request_param[i].name ) + wcslen( request_param[i].value ); + } + if (!(request_data = malloc( request_data_size ))) return FALSE; + + request = WinHttpOpenRequest( upnp_gateway_connection.connection, L"POST", upnp_gateway_connection.control_url, + NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0 ); + if (!request) goto done; + + ptr = request_data; + snprintf( ptr, request_data_size, request_template_header, function, upnp_gateway_connection.version ); + offset = strlen( ptr ); + ptr += offset; + request_data_size -= offset; + for (i = 0; i < request_param_count; ++i) + { + snprintf( ptr, request_data_size, " <%S>%S\r\n", + request_param[i].name, request_param[i].value, request_param[i].name); + offset = strlen( ptr ); + ptr += offset; + request_data_size -= offset; + } + snprintf( ptr, request_data_size, request_template_footer, function ); + + request_len = strlen( request_data ); + swprintf( request_headers, ARRAY_SIZE(request_headers), + L"SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:%u#%s\"\r\n" + L"Content-Type: text/xml", + upnp_gateway_connection.version, function ); + if (!WinHttpSendRequest( request, request_headers, -1, request_data, request_len, request_len, 0 )) + { + WARN( "Error sending request %u.\n", GetLastError() ); + goto done; + } + if (!WinHttpReceiveResponse(request, NULL)) + { + WARN( "Error receiving response %u.\n", GetLastError() ); + goto done; + } + size = sizeof(*http_status); + if (!WinHttpQueryHeaders( request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + NULL, http_status, &size, NULL) || *http_status != HTTP_STATUS_OK ) + { + if (*http_status != HTTP_STATUS_SERVER_ERROR) + { + ret = TRUE; + goto done; + } + } + + offset = 0; + reply_buffer_size = 1024; + if (!(reply_buffer = malloc( reply_buffer_size ))) goto done; + while ((ret = WinHttpReadData( request, reply_buffer + offset, reply_buffer_size - offset - 1, &size )) && size) + { + offset += size; + if (offset + 1 == reply_buffer_size) + { + char *new; + + reply_buffer_size *= 2; + if (!(new = realloc( reply_buffer, reply_buffer_size ))) goto done; + reply_buffer = new; + } + } + reply_buffer[offset] = 0; + + if (*http_status == HTTP_STATUS_OK) ret = get_xml_elements( reply_buffer, result, result_count ); + else + { + error_value_desc.name = L"errorCode"; + error_value_desc.value = NULL; + if ((ret = get_xml_elements( reply_buffer, &error_value_desc, 1 ))) + *server_error_code_str = error_value_desc.value; + } + +done: + free( reply_buffer ); + free( request_data ); + WinHttpCloseHandle( request ); + return ret; +} + +enum port_mapping_parameter +{ + PM_EXTERNAL_IP, + PM_EXTERNAL, + PM_PROTOCOL, + PM_INTERNAL, + PM_CLIENT, + PM_ENABLED, + PM_DESC, + PM_LEASE_DURATION, + PM_LAST +}; + +static struct xml_value_desc port_mapping_template[] = +{ + { L"NewRemoteHost" }, + { L"NewExternalPort" }, + { L"NewProtocol" }, + { L"NewInternalPort" }, + { L"NewInternalClient" }, + { L"NewEnabled" }, + { L"NewPortMappingDescription" }, + { L"NewLeaseDuration" }, +}; + +static LONG long_from_bstr( BSTR s ) +{ + if (!s) return 0; + return _wtoi( s ); +} + +static void update_mapping_list(void) +{ + struct xml_value_desc mapping_desc[ARRAY_SIZE(port_mapping_template)]; + struct xml_value_desc index_param; + struct port_mapping *new_mappings; + unsigned int i, index; + WCHAR index_str[9]; + BSTR error_str; + DWORD status; + BOOL ret; + + free_mappings(); + + index_param.name = L"NewPortMappingIndex"; + + index = 0; + while (1) + { + new_mappings = realloc( upnp_gateway_connection.mappings, (index + 1) * sizeof(*new_mappings) ); + if (!new_mappings) break; + upnp_gateway_connection.mappings = new_mappings; + + memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) ); + swprintf( index_str, ARRAY_SIZE(index_str), L"%u", index ); + index_param.value = SysAllocString( index_str ); + ret = request_service( L"GetGenericPortMappingEntry", &index_param, 1, + mapping_desc, ARRAY_SIZE(mapping_desc), &status, &error_str ); + SysFreeString( index_param.value ); + if (!ret) break; + if (status != HTTP_STATUS_OK) + { + if (error_str) + { + if (long_from_bstr( error_str ) != 713) + WARN( "Server returned error %s.\n", debugstr_w(error_str) ); + SysFreeString( error_str ); + } + break; + } + new_mappings[index].external_ip = mapping_desc[PM_EXTERNAL_IP].value; + mapping_desc[PM_EXTERNAL_IP].value = NULL; + new_mappings[index].external = long_from_bstr( mapping_desc[PM_EXTERNAL].value ); + new_mappings[index].protocol = mapping_desc[PM_PROTOCOL].value; + mapping_desc[PM_PROTOCOL].value = NULL; + new_mappings[index].internal = long_from_bstr( mapping_desc[PM_INTERNAL].value ); + new_mappings[index].client = mapping_desc[PM_CLIENT].value; + mapping_desc[PM_CLIENT].value = NULL; + if (!wcsicmp( mapping_desc[PM_ENABLED].value, L"true" ) || long_from_bstr( mapping_desc[PM_ENABLED].value )) + new_mappings[index].enabled = VARIANT_TRUE; + else + new_mappings[index].enabled = VARIANT_FALSE; + new_mappings[index].descr = mapping_desc[PM_DESC].value; + mapping_desc[PM_DESC].value = NULL; + + TRACE( "%s %s %s:%u -> %s:%u, enabled %d.\n", debugstr_w(new_mappings[index].descr), + debugstr_w(new_mappings[index].protocol), debugstr_w(new_mappings[index].external_ip), + new_mappings[index].external, debugstr_w(new_mappings[index].client), + new_mappings[index].internal, new_mappings[index].enabled ); + + for (i = 0; i < ARRAY_SIZE(mapping_desc); ++i) + SysFreeString( mapping_desc[i].value ); + upnp_gateway_connection.mappings = new_mappings; + upnp_gateway_connection.mapping_count = ++index; + } +} + static BOOL init_gateway_connection(void) { static const char upnp_search_request[] = @@ -363,6 +667,8 @@ static BOOL init_gateway_connection(void) } TRACE( "control_url %s, version %u.\n", debugstr_w(upnp_gateway_connection.control_url), upnp_gateway_connection.version ); + + update_mapping_list(); return TRUE; } From fdc6c5317a8685a7bf281bef4c637e5e24b2344e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:55 +0300 Subject: [PATCH 18/83] hnetcfg: Implement static_ports_get_Item(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 15fac20f2c2cc9bde7576d41ab92b4cf8884d238) CW-Bug-Id: #20062 --- dlls/hnetcfg/apps.c | 1 + dlls/hnetcfg/hnetcfg_private.h | 1 + dlls/hnetcfg/port.c | 358 ++++++++++++++++++++++++++++++++- 3 files changed, 357 insertions(+), 3 deletions(-) diff --git a/dlls/hnetcfg/apps.c b/dlls/hnetcfg/apps.c index f351e2482e8..9f0b30cd28a 100644 --- a/dlls/hnetcfg/apps.c +++ b/dlls/hnetcfg/apps.c @@ -116,6 +116,7 @@ static REFIID tid_id[] = &IID_INetFwProfile, &IID_IUPnPNAT, &IID_IStaticPortMappingCollection, + &IID_IStaticPortMapping, }; HRESULT get_typeinfo( enum type_id tid, ITypeInfo **ret ) diff --git a/dlls/hnetcfg/hnetcfg_private.h b/dlls/hnetcfg/hnetcfg_private.h index 91fef756464..9e6c4ec9618 100644 --- a/dlls/hnetcfg/hnetcfg_private.h +++ b/dlls/hnetcfg/hnetcfg_private.h @@ -29,6 +29,7 @@ enum type_id INetFwRules_tid, IUPnPNAT_tid, IStaticPortMappingCollection_tid, + IStaticPortMapping_tid, last_tid }; diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 070ba1ef7ab..c04aaefe56a 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -92,6 +92,28 @@ static void free_mappings(void) upnp_gateway_connection.mapping_count = 0; } +static BOOL copy_port_mapping( struct port_mapping *dst, const struct port_mapping *src ) +{ + memset( dst, 0, sizeof(*dst) ); + +#define COPY_BSTR_CHECK(name) if (src->name && !(dst->name = SysAllocString( src->name ))) \ + { \ + free_port_mapping( dst ); \ + return FALSE; \ + } + + COPY_BSTR_CHECK( external_ip ); + COPY_BSTR_CHECK( protocol ); + COPY_BSTR_CHECK( client ); + COPY_BSTR_CHECK( descr ); +#undef COPY_BSTR_CHECK + + dst->external = src->external; + dst->internal = src->internal; + dst->enabled = src->enabled; + return TRUE; +} + static BOOL parse_search_response( char *response, WCHAR *locationW, unsigned int location_size ) { char *saveptr = NULL, *tok, *tok2; @@ -695,6 +717,327 @@ static void release_gateway_connection(void) ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); } +static BOOL find_port_mapping( LONG port, BSTR protocol, struct port_mapping *ret ) +{ + unsigned int i; + BOOL found; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + for (i = 0; i < upnp_gateway_connection.mapping_count; ++i) + { + if (upnp_gateway_connection.mappings[i].external == port + && !wcscmp( upnp_gateway_connection.mappings[i].protocol, protocol )) + break; + } + found = i < upnp_gateway_connection.mapping_count; + if (found) copy_port_mapping( ret, &upnp_gateway_connection.mappings[i] ); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return found; +} + +static BOOL is_valid_protocol( BSTR protocol ) +{ + if (!protocol) return FALSE; + return !wcscmp( protocol, L"UDP" ) || !wcscmp( protocol, L"TCP" ); +} + +struct static_port_mapping +{ + IStaticPortMapping IStaticPortMapping_iface; + LONG refs; + struct port_mapping data; +}; + +static inline struct static_port_mapping *impl_from_IStaticPortMapping( IStaticPortMapping *iface ) +{ + return CONTAINING_RECORD(iface, struct static_port_mapping, IStaticPortMapping_iface); +} + +static ULONG WINAPI static_port_mapping_AddRef( + IStaticPortMapping *iface ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + return InterlockedIncrement( &mapping->refs ); +} + +static ULONG WINAPI static_port_mapping_Release( + IStaticPortMapping *iface ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + LONG refs = InterlockedDecrement( &mapping->refs ); + if (!refs) + { + TRACE("destroying %p\n", mapping); + free_port_mapping( &mapping->data ); + free( mapping ); + } + return refs; +} + +static HRESULT WINAPI static_port_mapping_QueryInterface( + IStaticPortMapping *iface, + REFIID riid, + void **ppvObject ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE("%p %s %p\n", mapping, debugstr_guid( riid ), ppvObject ); + + if ( IsEqualGUID( riid, &IID_IStaticPortMapping ) || + IsEqualGUID( riid, &IID_IDispatch ) || + IsEqualGUID( riid, &IID_IUnknown ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IStaticPortMapping_AddRef( iface ); + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_GetTypeInfoCount( + IStaticPortMapping *iface, + UINT *pctinfo ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE("%p %p\n", mapping, pctinfo); + *pctinfo = 1; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_GetTypeInfo( + IStaticPortMapping *iface, + UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE("%p %u %u %p\n", mapping, iTInfo, lcid, ppTInfo); + return get_typeinfo( IStaticPortMapping_tid, ppTInfo ); +} + +static HRESULT WINAPI static_port_mapping_GetIDsOfNames( + IStaticPortMapping *iface, + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %s %p %u %u %p\n", mapping, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + hr = get_typeinfo( IStaticPortMapping_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetIDsOfNames( typeinfo, rgszNames, cNames, rgDispId ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_port_mapping_Invoke( + IStaticPortMapping *iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + ITypeInfo *typeinfo; + HRESULT hr; + + TRACE("%p %d %s %d %d %p %p %p %p\n", mapping, dispIdMember, debugstr_guid(riid), + lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + hr = get_typeinfo( IStaticPortMapping_tid, &typeinfo ); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_Invoke( typeinfo, &mapping->IStaticPortMapping_iface, dispIdMember, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr ); + ITypeInfo_Release( typeinfo ); + } + return hr; +} + +static HRESULT WINAPI static_port_mapping_get_ExternalIPAddress( + IStaticPortMapping *iface, + BSTR *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = SysAllocString( mapping->data.external_ip ); + if (mapping->data.external_ip && !*value) return E_OUTOFMEMORY; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_ExternalPort( + IStaticPortMapping *iface, + LONG *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = mapping->data.external; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_InternalPort( + IStaticPortMapping *iface, + LONG *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = mapping->data.internal; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_Protocol( + IStaticPortMapping *iface, + BSTR *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = SysAllocString( mapping->data.protocol ); + if (mapping->data.protocol && !*value) return E_OUTOFMEMORY; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_InternalClient( + IStaticPortMapping *iface, + BSTR *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = SysAllocString( mapping->data.client ); + if (mapping->data.client && !*value) return E_OUTOFMEMORY; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_Enabled( + IStaticPortMapping *iface, + VARIANT_BOOL *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = mapping->data.enabled; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_get_Description( + IStaticPortMapping *iface, + BSTR *value ) +{ + struct static_port_mapping *mapping = impl_from_IStaticPortMapping( iface ); + + TRACE( "iface %p, value %p.\n", iface, value ); + + if (!value) return E_POINTER; + *value = SysAllocString( mapping->data.descr ); + if (mapping->data.descr && !*value) return E_OUTOFMEMORY; + return S_OK; +} + +static HRESULT WINAPI static_port_mapping_EditInternalClient( + IStaticPortMapping *iface, + BSTR value ) +{ + FIXME( "iface %p, value %s stub.\n", iface, debugstr_w(value) ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_port_mapping_Enable( + IStaticPortMapping *iface, + VARIANT_BOOL value ) +{ + FIXME( "iface %p, value %d stub.\n", iface, value ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_port_mapping_EditDescription( + IStaticPortMapping *iface, + BSTR value ) +{ + FIXME( "iface %p, value %s stub.\n", iface, debugstr_w(value) ); + + return E_NOTIMPL; +} + +static HRESULT WINAPI static_port_mapping_EditInternalPort( + IStaticPortMapping *iface, + LONG value ) +{ + FIXME( "iface %p, value %d stub.\n", iface, value ); + + return E_NOTIMPL; +} + +static const IStaticPortMappingVtbl static_port_mapping_vtbl = +{ + static_port_mapping_QueryInterface, + static_port_mapping_AddRef, + static_port_mapping_Release, + static_port_mapping_GetTypeInfoCount, + static_port_mapping_GetTypeInfo, + static_port_mapping_GetIDsOfNames, + static_port_mapping_Invoke, + static_port_mapping_get_ExternalIPAddress, + static_port_mapping_get_ExternalPort, + static_port_mapping_get_InternalPort, + static_port_mapping_get_Protocol, + static_port_mapping_get_InternalClient, + static_port_mapping_get_Enabled, + static_port_mapping_get_Description, + static_port_mapping_EditInternalClient, + static_port_mapping_Enable, + static_port_mapping_EditDescription, + static_port_mapping_EditInternalPort, +}; + +static HRESULT static_port_mapping_create( const struct port_mapping *mapping_data, IStaticPortMapping **ret ) +{ + struct static_port_mapping *mapping; + + if (!(mapping = calloc( 1, sizeof(*mapping) ))) return E_OUTOFMEMORY; + + mapping->refs = 1; + mapping->IStaticPortMapping_iface.lpVtbl = &static_port_mapping_vtbl; + mapping->data = *mapping_data; + *ret = &mapping->IStaticPortMapping_iface; + return S_OK; +} + struct static_port_mapping_collection { IStaticPortMappingCollection IStaticPortMappingCollection_iface; @@ -843,10 +1186,19 @@ static HRESULT WINAPI static_ports_get_Item( BSTR protocol, IStaticPortMapping **mapping ) { - FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + struct port_mapping mapping_data; + HRESULT ret; - if (mapping) *mapping = NULL; - return E_NOTIMPL; + TRACE( "iface %p, port %d, protocol %s.\n", iface, port, debugstr_w(protocol) ); + + if (!mapping) return E_POINTER; + *mapping = NULL; + if (!is_valid_protocol( protocol )) return E_INVALIDARG; + if (port < 0 || port > 65535) return E_INVALIDARG; + + if (!find_port_mapping( port, protocol, &mapping_data )) return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + if (FAILED(ret = static_port_mapping_create( &mapping_data, mapping ))) free_port_mapping( &mapping_data ); + return ret; } static HRESULT WINAPI static_ports_get_Count( From fafdc407815582df4f17da727bc06291c79e3af7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:56 +0300 Subject: [PATCH 19/83] hnetcfg: Implement static_ports_get_Count(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 7ed9fb0a6876aa6f3ebaf92ec7f519d37a2a7b7a) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index c04aaefe56a..34e054527d9 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -735,6 +735,16 @@ static BOOL find_port_mapping( LONG port, BSTR protocol, struct port_mapping *re return found; } +static unsigned int get_port_mapping_count(void) +{ + unsigned int ret; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + ret = upnp_gateway_connection.mapping_count; + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + return ret; +} + static BOOL is_valid_protocol( BSTR protocol ) { if (!protocol) return FALSE; @@ -1205,10 +1215,11 @@ static HRESULT WINAPI static_ports_get_Count( IStaticPortMappingCollection *iface, LONG *count ) { - FIXME( "iface %p, count %p stub.\n", iface, count ); + TRACE( "iface %p, count %p.\n", iface, count ); - if (count) *count = 0; - return E_NOTIMPL; + if (!count) return E_POINTER; + *count = get_port_mapping_count(); + return S_OK; } static HRESULT WINAPI static_ports_Remove( From a81ab804a1db27307d53342b6d7a726d88f90a60 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:57 +0300 Subject: [PATCH 20/83] hnetcfg: Implement static_ports__NewEnum(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit de05efdea217d25c296ecd9fb698075cc91528e5) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 181 +++++++++++++++++++++++++++++++++++- dlls/hnetcfg/tests/policy.c | 11 ++- 2 files changed, 184 insertions(+), 8 deletions(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 34e054527d9..8c80b02babc 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -735,6 +735,22 @@ static BOOL find_port_mapping( LONG port, BSTR protocol, struct port_mapping *re return found; } +static unsigned int get_port_mapping_range( unsigned int index, unsigned int count, struct port_mapping *ret ) +{ + unsigned int i; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + for (i = 0; i < count && index + i < upnp_gateway_connection.mapping_count; ++i) + if (!copy_port_mapping( &ret[i], &upnp_gateway_connection.mappings[index + i] )) + { + ERR( "No memory.\n" ); + break; + } + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + + return i; +} + static unsigned int get_port_mapping_count(void) { unsigned int ret; @@ -1048,6 +1064,164 @@ static HRESULT static_port_mapping_create( const struct port_mapping *mapping_da return S_OK; } +struct port_mapping_enum +{ + IEnumVARIANT IEnumVARIANT_iface; + LONG refs; + unsigned int index; +}; + +static inline struct port_mapping_enum *impl_from_IEnumVARIANT( IEnumVARIANT *iface ) +{ + return CONTAINING_RECORD(iface, struct port_mapping_enum, IEnumVARIANT_iface); +} + +static ULONG WINAPI port_mapping_enum_AddRef( + IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + return InterlockedIncrement( &mapping_enum->refs ); +} + +static ULONG WINAPI port_mapping_enum_Release( + IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + LONG refs = InterlockedDecrement( &mapping_enum->refs ); + if (!refs) + { + TRACE("destroying %p\n", mapping_enum); + free( mapping_enum ); + release_gateway_connection(); + } + return refs; +} + +static HRESULT WINAPI port_mapping_enum_QueryInterface( + IEnumVARIANT *iface, + REFIID riid, + void **ppvObject ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + + TRACE("%p %s %p\n", mapping_enum, debugstr_guid( riid ), ppvObject ); + + if ( IsEqualGUID( riid, &IID_IEnumVARIANT ) || + IsEqualGUID( riid, &IID_IUnknown ) ) + { + *ppvObject = iface; + } + else + { + FIXME("interface %s not implemented\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + IEnumVARIANT_AddRef( iface ); + return S_OK; +} + +static HRESULT WINAPI port_mapping_enum_Next( IEnumVARIANT *iface, ULONG celt, VARIANT *var, ULONG *fetched ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + struct port_mapping *data; + IStaticPortMapping *pm; + unsigned int i, count; + HRESULT ret; + + TRACE( "iface %p, celt %u, var %p, fetched %p.\n", iface, celt, var, fetched ); + + if (fetched) *fetched = 0; + if (!celt) return S_OK; + if (!var) return E_POINTER; + + if (!(data = calloc( 1, celt * sizeof(*data) ))) return E_OUTOFMEMORY; + count = get_port_mapping_range( mapping_enum->index, celt, data ); + TRACE( "count %u.\n", count ); + for (i = 0; i < count; ++i) + { + if (FAILED(static_port_mapping_create( &data[i], &pm ))) break; + + V_VT(&var[i]) = VT_DISPATCH; + V_DISPATCH(&var[i]) = (IDispatch *)pm; + } + mapping_enum->index += i; + if (fetched) *fetched = i; + ret = (i < celt) ? S_FALSE : S_OK; + for ( ; i < count; ++i) + { + free_port_mapping( &data[i] ); + VariantInit( &var[i] ); + } + for ( ; i < celt; ++i) + VariantInit( &var[i] ); + + free( data ); + return ret; +} + +static HRESULT WINAPI port_mapping_enum_Skip( IEnumVARIANT *iface, ULONG celt ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + unsigned int count = get_port_mapping_count(); + + TRACE( "iface %p, celt %u.\n", iface, celt ); + + mapping_enum->index += celt; + return mapping_enum->index <= count ? S_OK : S_FALSE; +} + +static HRESULT WINAPI port_mapping_enum_Reset( IEnumVARIANT *iface ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + + TRACE( "iface %p.\n", iface ); + + mapping_enum->index = 0; + return S_OK; +} + +static HRESULT create_port_mapping_enum( IUnknown **ret ); + +static HRESULT WINAPI port_mapping_enum_Clone( IEnumVARIANT *iface, IEnumVARIANT **ret ) +{ + struct port_mapping_enum *mapping_enum = impl_from_IEnumVARIANT( iface ); + HRESULT hr; + + TRACE( "iface %p, ret %p.\n", iface, ret ); + + if (!ret) return E_POINTER; + *ret = NULL; + if (FAILED(hr = create_port_mapping_enum( (IUnknown **)ret ))) return hr; + impl_from_IEnumVARIANT( *ret )->index = mapping_enum->index; + return S_OK; +} + +static const IEnumVARIANTVtbl port_mapping_enum_vtbl = +{ + port_mapping_enum_QueryInterface, + port_mapping_enum_AddRef, + port_mapping_enum_Release, + port_mapping_enum_Next, + port_mapping_enum_Skip, + port_mapping_enum_Reset, + port_mapping_enum_Clone, +}; + +static HRESULT create_port_mapping_enum( IUnknown **ret ) +{ + struct port_mapping_enum *mapping_enum; + + if (!(mapping_enum = calloc( 1, sizeof(*mapping_enum) ))) return E_OUTOFMEMORY; + + grab_gateway_connection(); + + mapping_enum->refs = 1; + mapping_enum->IEnumVARIANT_iface.lpVtbl = &port_mapping_enum_vtbl; + mapping_enum->index = 0; + *ret = (IUnknown *)&mapping_enum->IEnumVARIANT_iface; + return S_OK; +} + struct static_port_mapping_collection { IStaticPortMappingCollection IStaticPortMappingCollection_iface; @@ -1183,11 +1357,12 @@ static HRESULT WINAPI static_ports__NewEnum( IStaticPortMappingCollection *iface, IUnknown **ret ) { - FIXME( "iface %p, ret %p stub.\n", iface, ret ); + TRACE( "iface %p, ret %p.\n", iface, ret ); - if (ret) *ret = NULL; + if (!ret) return E_POINTER; - return E_NOTIMPL; + *ret = NULL; + return create_port_mapping_enum( ret ); } static HRESULT WINAPI static_ports_get_Item( diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index 19b6e3f6f2e..ffe3442dcd0 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -184,8 +184,7 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p refcount = get_refcount((IUnknown *)ports); hr = IStaticPortMappingCollection_get__NewEnum(ports, &unk); - todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); - if (FAILED(hr)) return; + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); @@ -213,14 +212,14 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_get_Count(ports, &count2); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); - ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); + todo_wine ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm); ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); @@ -280,6 +279,8 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); + todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); IEnumVARIANT_Release(enum_ports); } From 7f599205380b6c7a34d8596a6b94ed85b70f608b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:58 +0300 Subject: [PATCH 21/83] hnetcfg: Implement static_ports_Remove(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 559b1d2ccf09b4a567468603035fd31477644722) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 47 ++++++++++++++++++++++++++++++++++--- dlls/hnetcfg/tests/policy.c | 2 +- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 8c80b02babc..88816b7ee34 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -515,7 +515,8 @@ enum port_mapping_parameter PM_ENABLED, PM_DESC, PM_LEASE_DURATION, - PM_LAST + PM_LAST, + PM_REMOVE_PORT_LAST = PM_INTERNAL, }; static struct xml_value_desc port_mapping_template[] = @@ -602,6 +603,41 @@ static void update_mapping_list(void) } } +static BOOL remove_port_mapping( LONG port, BSTR protocol ) +{ + struct xml_value_desc mapping_desc[PM_REMOVE_PORT_LAST]; + DWORD status = 0; + BSTR error_str; + WCHAR portW[6]; + BOOL ret; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) ); + swprintf( portW, ARRAY_SIZE(portW), L"%u", port ); + mapping_desc[PM_EXTERNAL_IP].value = SysAllocString( L"" ); + mapping_desc[PM_EXTERNAL].value = SysAllocString( portW ); + mapping_desc[PM_PROTOCOL].value = protocol; + + ret = request_service( L"DeletePortMapping", mapping_desc, PM_REMOVE_PORT_LAST, + NULL, 0, &status, &error_str ); + if (ret && status != HTTP_STATUS_OK) + { + WARN( "status %u, server returned error %s.\n", status, debugstr_w(error_str) ); + SysFreeString( error_str ); + ret = FALSE; + } + else if (!ret) + { + WARN( "Request failed.\n" ); + } + update_mapping_list(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + + SysFreeString( mapping_desc[PM_EXTERNAL_IP].value ); + SysFreeString( mapping_desc[PM_EXTERNAL].value ); + return ret; +} + static BOOL init_gateway_connection(void) { static const char upnp_search_request[] = @@ -1402,9 +1438,14 @@ static HRESULT WINAPI static_ports_Remove( LONG port, BSTR protocol ) { - FIXME( "iface %p, port %d, protocol %s stub.\n", iface, port, debugstr_w(protocol) ); + TRACE( "iface %p, port %d, protocol %s.\n", iface, port, debugstr_w(protocol) ); - return E_NOTIMPL; + if (!is_valid_protocol( protocol )) return E_INVALIDARG; + if (port < 0 || port > 65535) return E_INVALIDARG; + + if (!remove_port_mapping( port, protocol )) return E_FAIL; + + return S_OK; } static HRESULT WINAPI static_ports_Add( diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index ffe3442dcd0..f9178f9b07b 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -280,7 +280,7 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); - todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); IEnumVARIANT_Release(enum_ports); } From f1529373bcf5c625b5f3945c5d78c1ff5d0d18b7 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Wed, 2 Feb 2022 11:32:59 +0300 Subject: [PATCH 22/83] hnetcfg: Implement static_ports_Add(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 8f8fe74f89ec5e76e03d702e67dd3233d0b6af4c) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 76 +++++++++++++++++++++++++++++++++++-- dlls/hnetcfg/tests/policy.c | 6 +-- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 88816b7ee34..def77621764 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -638,6 +638,51 @@ static BOOL remove_port_mapping( LONG port, BSTR protocol ) return ret; } +static BOOL add_port_mapping( LONG external, BSTR protocol, LONG internal, BSTR client, + VARIANT_BOOL enabled, BSTR description ) +{ + struct xml_value_desc mapping_desc[PM_LAST]; + WCHAR externalW[6], internalW[6]; + DWORD status = 0; + BSTR error_str; + BOOL ret; + + AcquireSRWLockExclusive( &upnp_gateway_connection_lock ); + memcpy( mapping_desc, port_mapping_template, sizeof(mapping_desc) ); + swprintf( externalW, ARRAY_SIZE(externalW), L"%u", external ); + swprintf( internalW, ARRAY_SIZE(internalW), L"%u", internal ); + mapping_desc[PM_EXTERNAL_IP].value = SysAllocString( L"" ); + mapping_desc[PM_EXTERNAL].value = SysAllocString( externalW ); + mapping_desc[PM_PROTOCOL].value = protocol; + mapping_desc[PM_INTERNAL].value = SysAllocString( internalW ); + mapping_desc[PM_CLIENT].value = client; + mapping_desc[PM_ENABLED].value = SysAllocString( enabled ? L"1" : L"0" ); + mapping_desc[PM_DESC].value = description; + mapping_desc[PM_LEASE_DURATION].value = SysAllocString( L"0" ); + + ret = request_service( L"AddPortMapping", mapping_desc, PM_LAST, + NULL, 0, &status, &error_str ); + if (ret && status != HTTP_STATUS_OK) + { + WARN( "status %u, server returned error %s.\n", status, debugstr_w(error_str) ); + SysFreeString( error_str ); + ret = FALSE; + } + else if (!ret) + { + WARN( "Request failed.\n" ); + } + update_mapping_list(); + ReleaseSRWLockExclusive( &upnp_gateway_connection_lock ); + + SysFreeString( mapping_desc[PM_EXTERNAL_IP].value ); + SysFreeString( mapping_desc[PM_EXTERNAL].value ); + SysFreeString( mapping_desc[PM_INTERNAL].value ); + SysFreeString( mapping_desc[PM_ENABLED].value ); + SysFreeString( mapping_desc[PM_LEASE_DURATION].value ); + return ret; +} + static BOOL init_gateway_connection(void) { static const char upnp_search_request[] = @@ -1458,12 +1503,37 @@ static HRESULT WINAPI static_ports_Add( BSTR description, IStaticPortMapping **mapping ) { - FIXME( "iface %p, external %d, protocol %s, internal %d, client %s, enabled %d, descritption %s, mapping %p stub.\n", + struct port_mapping mapping_data; + HRESULT ret; + + TRACE( "iface %p, external %d, protocol %s, internal %d, client %s, enabled %d, descritption %s, mapping %p.\n", iface, external, debugstr_w(protocol), internal, debugstr_w(client), enabled, debugstr_w(description), mapping ); - if (mapping) *mapping = NULL; - return E_NOTIMPL; + if (!mapping) return E_POINTER; + *mapping = NULL; + + if (!is_valid_protocol( protocol )) return E_INVALIDARG; + if (external < 0 || external > 65535) return E_INVALIDARG; + if (internal < 0 || internal > 65535) return E_INVALIDARG; + if (!client || !description) return E_INVALIDARG; + + if (!add_port_mapping( external, protocol, internal, client, enabled, description )) return E_FAIL; + + mapping_data.external_ip = NULL; + mapping_data.external = external; + mapping_data.protocol = SysAllocString( protocol ); + mapping_data.internal = internal; + mapping_data.client = SysAllocString( client ); + mapping_data.enabled = enabled; + mapping_data.descr = SysAllocString( description ); + if (!mapping_data.protocol || !mapping_data.client || !mapping_data.descr) + { + free_port_mapping( &mapping_data ); + return E_OUTOFMEMORY; + } + if (FAILED(ret = static_port_mapping_create( &mapping_data, mapping ))) free_port_mapping( &mapping_data ); + return ret; } static const IStaticPortMappingCollectionVtbl static_ports_vtbl = diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index f9178f9b07b..b6b353ac87d 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -212,14 +212,14 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"udp", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - todo_wine ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_Add(ports, 12345, (BSTR)L"UDP", 12345, (BSTR)L"1.2.3.4", VARIANT_TRUE, (BSTR)L"wine_test", &pm); - todo_wine ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_get_Count(ports, &count2); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); - todo_wine ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); + ok(count2 == expected_count, "Got unexpected count2 %u, expected %u.\n", count2, expected_count); hr = IStaticPortMappingCollection_get_Item(ports, 12345, NULL, &pm); ok(hr == E_INVALIDARG, "Got unexpected hr %#x.\n", hr); From b51ecfc033fab508b94e9f2a6639bc68a8470d56 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 3 Feb 2022 14:28:31 +0300 Subject: [PATCH 23/83] hnetcfg: Don't use _GetValue() if text element is missing in get_xml_elements(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit d907c8959c9b638962e387ab651bdc21b572aff3) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index def77621764..611a652ce5e 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -265,7 +265,10 @@ static BOOL get_xml_elements( const char *desc_xml, struct xml_value_desc *value if (node_type == XmlNodeType_EndElement) value = L""; else goto done; } - if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + else + { + if (FAILED(IXmlReader_GetValue( reader, &value, NULL ))) goto done; + } if (values[i].value) { WARN( "Duplicate value %s.\n", debugstr_w(values[i].name) ); From 170addbcc77101d615f9b02f86a4cbf57de2f8a0 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 3 Feb 2022 14:28:32 +0300 Subject: [PATCH 24/83] hnetcfg: Handle NULL strings in update_mapping_list(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 31f0509b72e2bfdef83c313e0dd41374f4fb6828) CW-Bug-Id: #20062 --- dlls/hnetcfg/port.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/dlls/hnetcfg/port.c b/dlls/hnetcfg/port.c index 611a652ce5e..47bfc16be79 100644 --- a/dlls/hnetcfg/port.c +++ b/dlls/hnetcfg/port.c @@ -540,6 +540,22 @@ static LONG long_from_bstr( BSTR s ) return _wtoi( s ); } +static BSTR mapping_move_bstr( BSTR *s ) +{ + BSTR ret; + + if (*s) + { + ret = *s; + *s = NULL; + } + else if (!(ret = SysAllocString( L"" ))) + { + ERR( "No memory.\n" ); + } + return ret; +} + static void update_mapping_list(void) { struct xml_value_desc mapping_desc[ARRAY_SIZE(port_mapping_template)]; @@ -579,20 +595,17 @@ static void update_mapping_list(void) } break; } - new_mappings[index].external_ip = mapping_desc[PM_EXTERNAL_IP].value; - mapping_desc[PM_EXTERNAL_IP].value = NULL; + new_mappings[index].external_ip = mapping_move_bstr( &mapping_desc[PM_EXTERNAL_IP].value ); new_mappings[index].external = long_from_bstr( mapping_desc[PM_EXTERNAL].value ); - new_mappings[index].protocol = mapping_desc[PM_PROTOCOL].value; - mapping_desc[PM_PROTOCOL].value = NULL; + new_mappings[index].protocol = mapping_move_bstr( &mapping_desc[PM_PROTOCOL].value ); new_mappings[index].internal = long_from_bstr( mapping_desc[PM_INTERNAL].value ); - new_mappings[index].client = mapping_desc[PM_CLIENT].value; - mapping_desc[PM_CLIENT].value = NULL; - if (!wcsicmp( mapping_desc[PM_ENABLED].value, L"true" ) || long_from_bstr( mapping_desc[PM_ENABLED].value )) + new_mappings[index].client = mapping_move_bstr( &mapping_desc[PM_CLIENT].value ); + if (mapping_desc[PM_ENABLED].value && (!wcsicmp( mapping_desc[PM_ENABLED].value, L"true" ) + || long_from_bstr( mapping_desc[PM_ENABLED].value ))) new_mappings[index].enabled = VARIANT_TRUE; else new_mappings[index].enabled = VARIANT_FALSE; - new_mappings[index].descr = mapping_desc[PM_DESC].value; - mapping_desc[PM_DESC].value = NULL; + new_mappings[index].descr = mapping_move_bstr( &mapping_desc[PM_DESC].value ); TRACE( "%s %s %s:%u -> %s:%u, enabled %d.\n", debugstr_w(new_mappings[index].descr), debugstr_w(new_mappings[index].protocol), debugstr_w(new_mappings[index].external_ip), From 8a9d38351ce922058740fe1c202a2c65a1f79f6e Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 3 Feb 2022 14:28:33 +0300 Subject: [PATCH 25/83] hnetcfg/tests: Don't leak IEnumVARIANT reference in test_static_port_mapping_collection(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 69acffb95424c06e8f9eacfa9fe9969e2ae3261c) CW-Bug-Id: #20062 --- dlls/hnetcfg/tests/policy.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index b6b353ac87d..f344019d1d3 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -188,6 +188,7 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IUnknown_QueryInterface(unk, &IID_IEnumVARIANT, (void **)&enum_ports); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + IUnknown_Release( unk ); refcount2 = get_refcount((IUnknown *)ports); ok(refcount2 == refcount, "Got unexpected refcount %u, refcount2 %u.\n", refcount, refcount2); From ef845615c9d1e3c9884af8944d187f2f085f2bf2 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 3 Feb 2022 14:28:34 +0300 Subject: [PATCH 26/83] hnetcfg/tests: Don't test removing the same mapping twice. Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard (cherry picked from commit 19c2ffe85202859914dfcde7f7b1dbd6bdb1cb41) CW-Bug-Id: #20062 --- dlls/hnetcfg/tests/policy.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dlls/hnetcfg/tests/policy.c b/dlls/hnetcfg/tests/policy.c index f344019d1d3..3b614e6e05a 100644 --- a/dlls/hnetcfg/tests/policy.c +++ b/dlls/hnetcfg/tests/policy.c @@ -278,8 +278,6 @@ static void test_static_port_mapping_collection( IStaticPortMappingCollection *p hr = IEnumVARIANT_Next(enum_ports, 1, &var, &fetched); ok(hr == S_FALSE, "Got unexpected hr %#x.\n", hr); - hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); - ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); hr = IStaticPortMappingCollection_Remove(ports, 12345, (BSTR)L"UDP"); ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); From f4ddb1814d9adfec05b46235a5aa67191660786f Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 27 Jan 2022 10:23:21 -0600 Subject: [PATCH 27/83] winmm: Don't process audio data during waveOutWrite while playing. Signed-off-by: Andrew Eikum Signed-off-by: Alexandre Julliard (cherry picked from commit 362e39a4a7154807c9707331cb5c707ff6c718d9) Fixes occasional crash in Teardown. CW-Bug-Id: #20061 --- dlls/winmm/waveform.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/dlls/winmm/waveform.c b/dlls/winmm/waveform.c index 1159b48b483..ecffa700662 100644 --- a/dlls/winmm/waveform.c +++ b/dlls/winmm/waveform.c @@ -191,6 +191,7 @@ static LRESULT WOD_Close(HWAVEOUT hwave); static LRESULT WID_Open(WINMM_OpenInfo *info); static LRESULT WID_Close(HWAVEIN hwave); static MMRESULT WINMM_BeginPlaying(WINMM_Device *device); +static void WOD_PushData(WINMM_Device *device); void WINMM_DeleteWaveform(void) { @@ -775,8 +776,11 @@ static HRESULT reroute_mapper_device(WINMM_Device *device, BOOL is_out) HeapFree(GetProcessHeap(), 0, info.format); - if(!stopped) + if(!stopped){ + if(is_out) + WOD_PushData(device); WINMM_BeginPlaying(device); + } LeaveCriticalSection(&device->lock); @@ -1948,10 +1952,6 @@ static MMRESULT WINMM_BeginPlaying(WINMM_Device *device) TRACE("(%p)\n", device->handle); - if(device->render) - /* prebuffer data before starting */ - WOD_PushData(device); - if(device->stopped){ device->stopped = FALSE; @@ -2893,6 +2893,9 @@ UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, WAVEHDR *header, UINT uSize) header->dwFlags &= ~WHDR_DONE; header->dwFlags |= WHDR_INQUEUE; + if(device->stopped) + WOD_PushData(device); + mr = WINMM_BeginPlaying(device); LeaveCriticalSection(&device->lock); @@ -2970,6 +2973,9 @@ UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) device->stopped = TRUE; + if(device->render) + WOD_PushData(device); + mr = WINMM_BeginPlaying(device); LeaveCriticalSection(&device->lock); From 778452dece71aa8a4097281a289d3f0b360e9a09 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Feb 2022 16:03:22 +0300 Subject: [PATCH 28/83] fshack: Blit the contents of current framebuffer to the fshack's framebuffer in fs_hack_setup_context(). CW-Bug-Id: #20102 Some games might not clear the framebuffer on each frame and rely on the data in framebuffer to persist through glFlush(), glFinish() etc. That is currently not the case if the fshack is getting turned on after some drawing was performed already. --- dlls/winex11.drv/opengl.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 82906303a85..961f5364f0c 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2408,12 +2408,25 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * if (!ctx->has_been_current) opengl_funcs.gl.p_glViewport(0, 0, width, height); - if(!gl->fs_hack_context_set_up) + if (!gl->fs_hack_context_set_up) { - opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - opengl_funcs.gl.p_glClearDepth( 1.0 ); - opengl_funcs.gl.p_glClearStencil( 0 ); - opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + if (ctx->has_been_current) + { + GLbitfield mask = GL_COLOR_BUFFER_BIT; + + if (attribs.depth_size) mask |= GL_DEPTH_BUFFER_BIT; + if (attribs.stencil_size) mask |= GL_STENCIL_BUFFER_BIT; + + pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); + pglBlitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, GL_NEAREST ); + } + else + { + opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + opengl_funcs.gl.p_glClearDepth( 1.0 ); + opengl_funcs.gl.p_glClearStencil( 0 ); + opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + } } pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); pglDrawBuffer( GL_BACK ); From a8d32400f9b1ed7bac9c411ea14dc5c6f71fce96 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 4 Feb 2022 17:02:41 +0300 Subject: [PATCH 29/83] fshack: HACK: Use specific names for textures for SWJKJA. CW-Bug-Id: #20102 --- dlls/winex11.drv/opengl.c | 50 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 961f5364f0c..cc419c78e14 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -2254,6 +2254,50 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa pglUseProgram( prev_program ); } +enum fshack_texture_type +{ + FSHACK_TEXTURE_COLOUR, + FSHACK_TEXTURE_DEPTH, + FSHACK_TEXTURE_LAST, +}; + +static void gen_texture( struct wgl_context *ctx, GLuint *tex, enum fshack_texture_type type ) +{ + static const GLuint texture_names[FSHACK_TEXTURE_LAST] = + { + 65535, + 65536, + }; + static int texture_name_hack = -1; + static int once; + + if (ctx->is_core) + { + opengl_funcs.gl.p_glGenTextures( 1, tex ); + return; + } + + if (texture_name_hack == -1) + { + const char *sgi = getenv("SteamGameId"); + + texture_name_hack = sgi && !strcmp( sgi, "6020" ); + } + + if (!texture_name_hack || opengl_funcs.gl.p_glIsTexture( texture_names[type] )) + { + if (texture_name_hack) + FIXME( "Texture %u already exists.\n", texture_names[type] ); + opengl_funcs.gl.p_glGenTextures( 1, tex ); + return; + } + /* Star Wars Jedi Knight: Jedi Academy uses texture names without allocating + * them with glGenTextures(). Trying to use a texture name which has low chances + * to overlap with what games may use. */ + if (!once++) FIXME( "Using texture name hack.\n" ); + *tex = texture_names[type]; +} + static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *gl ) { GLuint prev_draw_fbo, prev_read_fbo, prev_texture, prev_renderbuffer; @@ -2325,7 +2369,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * fs_hack_get_attachments_config( gl, &attribs, &config ); if (!ctx->fs_hack_color_texture) - opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); + gen_texture( ctx, &ctx->fs_hack_color_texture, FSHACK_TEXTURE_COLOUR ); + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.color_internalformat, width, height, 0, config.color_format, config.color_type, NULL); @@ -2389,7 +2434,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * else { if (!ctx->fs_hack_ds_texture) - opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_ds_texture ); + gen_texture( ctx, &ctx->fs_hack_ds_texture, FSHACK_TEXTURE_DEPTH ); + opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_ds_texture ); opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.ds_internalformat, width, height, 0, config.ds_format, config.ds_type, NULL); From c1d58f41052ae7ca24a83983bc9dd8ce4a395c72 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Fri, 21 Jan 2022 14:40:43 -0500 Subject: [PATCH 30/83] battleye: Add launcher process instead of redirecting CreateProcess call. Fixes Arma 3 Launcher CW-Bug-Id: #18934 --- configure.ac | 1 + dlls/kernelbase/process.c | 134 ++++---------------------------- programs/belauncher/Makefile.in | 7 ++ programs/belauncher/main.c | 116 +++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 119 deletions(-) create mode 100644 programs/belauncher/Makefile.in create mode 100644 programs/belauncher/main.c diff --git a/configure.ac b/configure.ac index 8e4462b1d4c..bc4f47d9889 100644 --- a/configure.ac +++ b/configure.ac @@ -3579,6 +3579,7 @@ WINE_CONFIG_MAKEFILE(po) WINE_CONFIG_MAKEFILE(programs/arp) WINE_CONFIG_MAKEFILE(programs/aspnet_regiis) WINE_CONFIG_MAKEFILE(programs/attrib) +WINE_CONFIG_MAKEFILE(programs/belauncher) WINE_CONFIG_MAKEFILE(programs/cabarc) WINE_CONFIG_MAKEFILE(programs/cacls) WINE_CONFIG_MAKEFILE(programs/chcp.com) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 22f9115011e..01f4ae08721 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -489,18 +489,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) { - WCHAR full_path[MAX_PATH], config_path[MAX_PATH]; + static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; + + WCHAR full_path[MAX_PATH]; WCHAR *p; DWORD size; void *block; DWORD *translation; char buf[100]; char *product_name; - int launcher_exe_len, game_exe_len, arg_len; - HANDLE launcher_cfg; - LARGE_INTEGER launcher_cfg_size; - char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL; - BOOL wow64; WCHAR *new_cmd_line; if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH ); @@ -541,96 +538,15 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam HeapFree( GetProcessHeap(), 0, block ); - TRACE("Detected launch of a BattlEye Launcher, attempting to launch game executable instead.\n"); - - lstrcpynW(config_path, full_path, MAX_PATH); - - for (p = config_path + wcslen(config_path); p != config_path; --p) - if (*p == '\\') break; - - if (*p == '\\') - { - *p = 0; - launcher_exe_len = wcslen(p + 1); - } - else - launcher_exe_len = wcslen(full_path); - - lstrcatW(config_path, L"\\BattlEye\\BELauncher.ini"); - - launcher_cfg = CreateFileW(config_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (launcher_cfg == INVALID_HANDLE_VALUE) - return 0; - - if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) - { - CloseHandle(launcher_cfg); - return 0; - } - - configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart); - - if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart) - { - CloseHandle(launcher_cfg); - HeapFree( GetProcessHeap(), 0, configs ); - return 0; - } - - CloseHandle(launcher_cfg); - - config = configs; - do - { - if (!strncmp(config, "32BitExe=", 9)) - arch_32_exe = config + 9; - - if (!strncmp(config, "64BitExe=", 9)) - arch_64_exe = config + 9; - - if (!strncmp(config, "BEArg=", 6)) - be_arg = config + 6; - } - while ((config = strchr(config, '\n')) && *(config++)); - - if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64))) - game_exe = arch_64_exe; - else if (arch_32_exe) - game_exe = arch_32_exe; - else - { - HeapFree( GetProcessHeap(), 0, configs ); - WARN("Failed to find game executable name from BattlEye config.\n"); - return 0; - } - - if (strchr(game_exe, '\r')) - *(strchr(game_exe, '\r')) = 0; - if (strchr(game_exe, '\n')) - *(strchr(game_exe, '\n')) = 0; - game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; - - if (be_arg) - { - if (strchr(be_arg, '\r')) - *(strchr(be_arg, '\r')) = 0; - if (strchr(be_arg, '\n')) - *(strchr(be_arg, '\n')) = 0; - arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1; - } - - TRACE("Launching game executable %s for BattlEye.\n", game_exe); + TRACE("Detected launch of a BattlEye Launcher, redirecting to Proton version.\n"); - if ((wcslen(app_name) - launcher_exe_len) + game_exe_len + 1 > new_name_len) + if (new_name_len < wcslen(belauncherW) + 1) { - HeapFree( GetProcessHeap(), 0, configs ); WARN("Game executable path doesn't fit in buffer.\n"); return 0; } - wcscpy(new_name, app_name); - p = new_name + wcslen(new_name) - launcher_exe_len; - MultiByteToWideChar(CP_ACP, 0, game_exe, -1, p, game_exe_len + 1); + wcscpy(new_name, belauncherW); /* find and replace executable name in command line, and add BE argument */ p = *cmd_line; @@ -638,43 +554,23 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam p++; if (!wcsncmp(p, app_name, wcslen(app_name))) - p += wcslen(app_name) - launcher_exe_len; - else - p = NULL; - - if (p || be_arg) { - size = wcslen(*cmd_line) + 1; - if (p) - size += game_exe_len - launcher_exe_len; - if (be_arg) - size += 1 /* space */ + arg_len; - size *= sizeof(WCHAR); + new_cmd_line = HeapAlloc( GetProcessHeap(), 0, ( wcslen(*cmd_line) + wcslen(belauncherW) + 1 - wcslen(app_name) ) * sizeof(WCHAR) ); - /* freed by parent function */ - new_cmd_line = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + wcscpy(new_cmd_line, *cmd_line); + p = new_cmd_line; + if (p[0] == '\"') + p++; - if (p) - { - lstrcpynW(new_cmd_line, *cmd_line, p - *cmd_line); - MultiByteToWideChar(CP_ACP, 0, game_exe, -1, new_cmd_line + wcslen(new_cmd_line), game_exe_len + 1); - wcscat(new_cmd_line, p + launcher_exe_len); - } - else - { - wcscpy(new_cmd_line, *cmd_line); - } + memmove( p + wcslen(belauncherW), p + wcslen(app_name), (wcslen(p) - wcslen(belauncherW)) * sizeof(WCHAR) ); + memcpy( p, belauncherW, wcslen(belauncherW) * sizeof(WCHAR) ); - if (be_arg) - { - wcscat(new_cmd_line, L" "); - MultiByteToWideChar(CP_ACP, 0, be_arg, -1, new_cmd_line + wcslen(new_cmd_line), arg_len + 1); - } + TRACE("old command line %s.\n", debugstr_w(*cmd_line)); + TRACE("new command line %s.\n", debugstr_w(new_cmd_line)); *cmd_line = new_cmd_line; } - HeapFree( GetProcessHeap(), 0, configs ); return 1; } diff --git a/programs/belauncher/Makefile.in b/programs/belauncher/Makefile.in new file mode 100644 index 00000000000..f2dc59b07ce --- /dev/null +++ b/programs/belauncher/Makefile.in @@ -0,0 +1,7 @@ +MODULE = belauncher.exe +IMPORTS = + +EXTRADLLFLAGS = -mwindows -municode + +C_SRCS = \ + main.c \ diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c new file mode 100644 index 00000000000..0f727f3ca7d --- /dev/null +++ b/programs/belauncher/main.c @@ -0,0 +1,116 @@ +#define WIN32_LEAN_AND_MEAN +#include + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(belauncher); + +int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow) +{ + char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL; + LARGE_INTEGER launcher_cfg_size; + unsigned char battleye_status; + int game_exe_len, arg_len; + PROCESS_INFORMATION pi; + HANDLE launcher_cfg; + LPWSTR launch_cmd; + STARTUPINFOW si = {0}; + DWORD size; + BOOL wow64; + + battleye_status = 0x3; /* Starting */ + _write(1, &battleye_status, 1); + + launcher_cfg = CreateFileW(L"Battleye\\BELauncher.ini", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (launcher_cfg == INVALID_HANDLE_VALUE) + goto start_failed; + + if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) + { + CloseHandle(launcher_cfg); + goto start_failed; + } + + configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart); + + if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart) + { + CloseHandle(launcher_cfg); + HeapFree( GetProcessHeap(), 0, configs ); + goto start_failed; + } + + CloseHandle(launcher_cfg); + + config = configs; + do + { + if (!strncmp(config, "32BitExe=", 9)) + arch_32_exe = config + 9; + + if (!strncmp(config, "64BitExe=", 9)) + arch_64_exe = config + 9; + + if (!strncmp(config, "BEArg=", 6)) + be_arg = config + 6; + } + while ((config = strchr(config, '\n')) && *(config++)); + + if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64))) + game_exe = arch_64_exe; + else if (arch_32_exe) + game_exe = arch_32_exe; + else + { + HeapFree( GetProcessHeap(), 0, configs ); + WINE_WARN("Failed to find game executable name from BattlEye config.\n"); + goto start_failed; + } + + if (strchr(game_exe, '\r')) + *(strchr(game_exe, '\r')) = 0; + if (strchr(game_exe, '\n')) + *(strchr(game_exe, '\n')) = 0; + game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; + + if (be_arg) + { + if (strchr(be_arg, '\r')) + *(strchr(be_arg, '\r')) = 0; + if (strchr(be_arg, '\n')) + *(strchr(be_arg, '\n')) = 0; + arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1; + } + + WINE_TRACE("Launching game executable %s for BattlEye.\n", game_exe); + battleye_status = 0x9; /* Launching Game */ + _write(1, &battleye_status, 1); + + launch_cmd = HeapAlloc(GetProcessHeap(), 0, (game_exe_len + 1 + wcslen(cmdline) + 1 + arg_len + 1) * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, game_exe, -1, launch_cmd, game_exe_len + 1); + launch_cmd[game_exe_len] = ' '; + + wcscpy(launch_cmd + game_exe_len + 1, cmdline); + launch_cmd[game_exe_len + 1 + wcslen(cmdline)] = ' '; + + MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1); + + if (!CreateProcessW(NULL, launch_cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) + { + battleye_status = 0xA; /* Launch Failed */ + _write(1, &battleye_status, 1); + + HeapFree( GetProcessHeap(), 0, launch_cmd ); + return GetLastError(); + } + HeapFree( GetProcessHeap(), 0, launch_cmd ); + + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + return 0; + +start_failed: + battleye_status = 0x4; /* Start Failed */ + _write(1, &battleye_status, 1); + return 0; +} From 36b0e9d4bfd8b43bdefb025bf99d530ea74579ad Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 19 Jan 2022 14:19:05 -0600 Subject: [PATCH 31/83] winegstreamer: Add custom allocator for MFMediaBuffer-backed memory --- dlls/winegstreamer/audioconvert.c | 2 +- dlls/winegstreamer/colorconvert.c | 2 +- dlls/winegstreamer/decode_transform.c | 2 +- dlls/winegstreamer/gst_private.h | 23 ++- dlls/winegstreamer/main.c | 228 +++++++++++++++++++- dlls/winegstreamer/media_source.c | 21 +- dlls/winegstreamer/quartz_parser.c | 8 +- dlls/winegstreamer/unixlib.h | 27 +++ dlls/winegstreamer/wg_parser.c | 286 +++++++++++++++++++++++++- dlls/winegstreamer/wm_reader.c | 2 +- 10 files changed, 587 insertions(+), 14 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index aa9a2984806..9086cdf8038 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -916,7 +916,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) return hr; } - if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true))) + if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, false))) { ERR("Failed to create audio converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index 476851fa43a..ae1958c67fc 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -907,7 +907,7 @@ HRESULT color_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true))) + if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, false))) { ERR("Failed to create video converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index 04d46a73c3d..f84c8659491 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -1216,7 +1216,7 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) InitializeConditionVariable(&object->help_cv); InitializeConditionVariable(&object->event_cv); - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE, FALSE))) { ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 3b456aea3a2..877d3016376 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -64,7 +64,7 @@ static inline const char *debugstr_time(REFERENCE_TIME time) #define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) -struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) DECLSPEC_HIDDEN; +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering, bool use_wine_allocator) DECLSPEC_HIDDEN; void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN; HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) DECLSPEC_HIDDEN; @@ -78,6 +78,10 @@ void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) DECLSPEC_HIDDEN; +bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, + DWORD *size, DWORD *align, void **user) DECLSPEC_HIDDEN; +void wg_parser_provide_alloc_buffer(struct wg_parser *parser, void *data, void *user) DECLSPEC_HIDDEN; + uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN; @@ -217,4 +221,21 @@ HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections); +struct wg_mf_buffer +{ + IMFMediaBuffer IMFMediaBuffer_iface; + LONG refcount; + + BYTE *data; + DWORD max_length; + DWORD current_length; +}; + +struct allocator_thread_data { + BOOL done; + struct wg_parser *wg_parser; +}; + +HANDLE start_allocator_thread(struct allocator_thread_data *) DECLSPEC_HIDDEN; + #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 60651541dbc..4c353b4d3fa 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -33,6 +33,202 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); +#define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) + +static inline struct wg_mf_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct wg_mf_buffer, IMFMediaBuffer_iface); +} + +static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaBuffer) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &buffer->IMFMediaBuffer_iface; + IMFMediaBuffer_AddRef(iface); + return S_OK; + } + + FIXME("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI memory_buffer_AddRef(IMFMediaBuffer *iface) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedIncrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", buffer, refcount); + + return refcount; +} + +static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + ULONG refcount = InterlockedDecrement(&buffer->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + free(buffer->data); + free(buffer); + } + + return refcount; +} + +static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p %p, %p.\n", iface, data, max_length, current_length); + + if (!data) + return E_INVALIDARG; + + *data = buffer->data; + if (max_length) + *max_length = buffer->max_length; + if (current_length) + *current_length = buffer->current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_Unlock(IMFMediaBuffer *iface) +{ + TRACE("%p.\n", iface); + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *current_length) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p.\n", iface); + + if (!current_length) + return E_INVALIDARG; + + *current_length = buffer->current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %u.\n", iface, current_length); + + if (current_length > buffer->max_length) + return E_INVALIDARG; + + buffer->current_length = current_length; + + return S_OK; +} + +static HRESULT WINAPI memory_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *max_length) +{ + struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %p.\n", iface, max_length); + + if (!max_length) + return E_INVALIDARG; + + *max_length = buffer->max_length; + + return S_OK; +} + +static const IMFMediaBufferVtbl memory_buffer_vtbl = +{ + memory_buffer_QueryInterface, + memory_buffer_AddRef, + memory_buffer_Release, + memory_buffer_Lock, + memory_buffer_Unlock, + memory_buffer_GetCurrentLength, + memory_buffer_SetCurrentLength, + memory_buffer_GetMaxLength, +}; + +struct wg_mf_buffer *create_memory_buffer(DWORD max_length, DWORD alignment) +{ + struct wg_mf_buffer *buffer; + + if (!(buffer = calloc(1, sizeof(*buffer)))) + return NULL; + + if (!(buffer->data = calloc(1, ALIGN_SIZE(max_length, alignment)))) + { + free(buffer); + return NULL; + } + + buffer->IMFMediaBuffer_iface.lpVtbl = &memory_buffer_vtbl; + buffer->refcount = 1; + buffer->max_length = max_length; + buffer->current_length = 0; + + return buffer; +} + +DWORD CALLBACK allocator_thread(void *arg) +{ + struct allocator_thread_data *data = arg; + enum wg_parser_alloc_req_type type; + + TRACE("Starting alloc thread for parser %p.\n", data->wg_parser); + + while (!data->done) + { + DWORD size, align; + void *user; + + if (!wg_parser_get_next_alloc_req(data->wg_parser, &type, &size, &align, &user)) + continue; + + switch (type) + { + case WG_PARSER_ALLOC_NEW: + { + struct wg_mf_buffer *buf = create_memory_buffer(size, align ? align : 1); + wg_parser_provide_alloc_buffer(data->wg_parser, buf ? buf->data : NULL, buf); + break; + } + case WG_PARSER_ALLOC_FREE: + { + struct wg_mf_buffer *buf = user; + IMFMediaBuffer_Release(&buf->IMFMediaBuffer_iface); + wg_parser_provide_alloc_buffer(data->wg_parser, NULL, NULL); /* mark done */ + break; + } + default: + break; + } + } + + TRACE("Media source is shutting down; exiting alloc thread.\n"); + return 0; +} + +HANDLE start_allocator_thread(struct allocator_thread_data *data) +{ + return CreateThread(NULL, 0, allocator_thread, data, 0, NULL); +} + bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) { unsigned int new_capacity, max_capacity; @@ -60,12 +256,14 @@ bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) return TRUE; } -struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering, + bool use_wine_allocator) { struct wg_parser_create_params params = { .type = type, .unlimited_buffering = unlimited_buffering, + .use_wine_allocator = use_wine_allocator, }; if (__wine_unix_call(unix_handle, unix_wg_parser_create, ¶ms)) @@ -146,6 +344,34 @@ void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, c __wine_unix_call(unix_handle, unix_wg_parser_push_data, ¶ms); } +bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, + DWORD *size, DWORD *align, void **user) +{ + struct wg_parser_get_next_alloc_req_params params = + { + .parser = parser, + }; + if (__wine_unix_call(unix_handle, unix_wg_parser_get_next_alloc_req, ¶ms)) + return false; + *type = params.type; + *size = params.size; + *align = params.align; + *user = params.user; + return true; +} + +void wg_parser_provide_alloc_buffer(struct wg_parser *parser, void *data, void *user) +{ + struct wg_parser_provide_alloc_buffer_params params = + { + .parser = parser, + .data = data, + .user = user, + }; + + __wine_unix_call(unix_handle, unix_wg_parser_provide_alloc_buffer, ¶ms); +} + uint32_t wg_parser_get_stream_count(struct wg_parser *parser) { struct wg_parser_get_stream_count_params params = diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 7d28fb26636..312f9918355 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -106,7 +106,8 @@ struct media_source SOURCE_SHUTDOWN, } state; - HANDLE read_thread; + HANDLE read_thread, alloc_thread; + struct allocator_thread_data alloc_thread_data; bool read_thread_shutdown; }; @@ -665,7 +666,7 @@ static DWORD CALLBACK read_thread(void *arg) } free(data); - TRACE("Media source is shutting down; exiting.\n"); + TRACE("Media source is shutting down; exiting read thread.\n"); return 0; } @@ -1345,6 +1346,10 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) WaitForSingleObject(source->read_thread, INFINITE); CloseHandle(source->read_thread); + source->alloc_thread_data.done = true; + WaitForSingleObject(source->alloc_thread, INFINITE); + CloseHandle(source->alloc_thread); + IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Shutdown(source->event_queue); IMFByteStream_Release(source->byte_stream); @@ -1440,7 +1445,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ * never deselects it). Remove buffering limits from decodebin in order to * account for this. Note that this does leak memory, but the same memory * leak occurs with native. */ - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true, true))) { hr = E_OUTOFMEMORY; goto fail; @@ -1449,6 +1454,10 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); + object->alloc_thread_data.done = FALSE; + object->alloc_thread_data.wg_parser = parser; + object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); + object->state = SOURCE_OPENING; if (FAILED(hr = wg_parser_connect(parser, file_size))) @@ -1575,6 +1584,12 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ WaitForSingleObject(object->read_thread, INFINITE); CloseHandle(object->read_thread); } + if (object->alloc_thread) + { + object->alloc_thread_data.done = true; + WaitForSingleObject(object->alloc_thread, INFINITE); + CloseHandle(object->alloc_thread); + } if (object->wg_parser) wg_parser_destroy(object->wg_parser); if (object->async_commands_queue) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 2782f773beb..e4d448f3767 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1179,7 +1179,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false, false))) { free(object); return E_OUTOFMEMORY; @@ -1710,7 +1710,7 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_WAVPARSE, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_WAVPARSE, false, false))) { free(object); return E_OUTOFMEMORY; @@ -1796,7 +1796,7 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_AVIDEMUX, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_AVIDEMUX, false, false))) { free(object); return E_OUTOFMEMORY; @@ -1903,7 +1903,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false, false))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 79f68695fd8..0a77b4b9741 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -192,6 +192,7 @@ struct wg_parser_create_params struct wg_parser *parser; enum wg_parser_type type; bool unlimited_buffering; + bool use_wine_allocator; }; struct wg_parser_connect_params @@ -216,6 +217,29 @@ struct wg_parser_get_next_read_offset_params UINT64 offset; }; +enum wg_parser_alloc_req_type +{ + WG_PARSER_ALLOC_NONE, + WG_PARSER_ALLOC_NEW, + WG_PARSER_ALLOC_FREE, +}; + +struct wg_parser_get_next_alloc_req_params +{ + struct wg_parser *parser; + enum wg_parser_alloc_req_type type; + DWORD size; + DWORD align; + void *user; +}; + +struct wg_parser_provide_alloc_buffer_params +{ + struct wg_parser *parser; + void *data; + void *user; +}; + struct wg_parser_push_data_params { struct wg_parser *parser; @@ -346,6 +370,9 @@ enum unix_funcs unix_wg_parser_get_next_read_offset, unix_wg_parser_push_data, + unix_wg_parser_get_next_alloc_req, + unix_wg_parser_provide_alloc_buffer, + unix_wg_parser_get_stream_count, unix_wg_parser_get_stream, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 178c47d5d32..80ee1b17e5a 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -63,6 +63,7 @@ struct wg_parser struct wg_parser_stream **streams; unsigned int stream_count, expected_stream_count; + GstAllocator *allocator; GstElement *container, *decodebin; GstBus *bus; GstPad *my_src, *their_sink; @@ -87,9 +88,21 @@ struct wg_parser GstFlowReturn ret; } read_request; + pthread_mutex_t alloc_req_lock, alloc_lock; + pthread_cond_t alloc_cond, alloc_done_cond; + struct + { + enum wg_parser_alloc_req_type type; + DWORD size; + DWORD align; + void *data; + void *user; + bool done; + } alloc_request; + bool flushing, sink_connected, draining; - bool unlimited_buffering; + bool unlimited_buffering, use_wine_allocator; struct wg_format input_format; bool use_mediaconv; @@ -116,6 +129,21 @@ struct wg_parser_stream gchar *language_code; }; +GType WineMemoryAllocator_get_type (void); + +typedef struct +{ + GstAllocator parent; + + struct wg_parser *parser; +} WineMemoryAllocator; + +struct wine_memory { + GstMemory mem; + void *data; + void *user; +}; + static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) { switch (format) @@ -643,6 +671,46 @@ static NTSTATUS wg_parser_push_data(void *args) return S_OK; } +static NTSTATUS wg_parser_get_next_alloc_req(void *args) +{ + struct wg_parser_get_next_alloc_req_params *params = args; + struct wg_parser *parser = params->parser; + + pthread_mutex_lock(&parser->alloc_req_lock); + + while (parser->sink_connected && parser->alloc_request.type == WG_PARSER_ALLOC_NONE) + pthread_cond_wait(&parser->alloc_cond, &parser->alloc_req_lock); + + if (!parser->sink_connected) + { + pthread_mutex_unlock(&parser->alloc_req_lock); + return VFW_E_WRONG_STATE; + } + + params->type = parser->alloc_request.type; + params->size = parser->alloc_request.size; + params->align = parser->alloc_request.align; + params->user = parser->alloc_request.user; + + pthread_mutex_unlock(&parser->alloc_req_lock); + return S_OK; +} + +static NTSTATUS wg_parser_provide_alloc_buffer(void *args) +{ + const struct wg_parser_provide_alloc_buffer_params *params = args; + struct wg_parser *parser = params->parser; + + parser->alloc_request.type = WG_PARSER_ALLOC_NONE; + parser->alloc_request.data = params->data; + parser->alloc_request.user = params->user; + parser->alloc_request.done = true; + + pthread_cond_signal(&parser->alloc_done_cond); + + return S_OK; +} + static NTSTATUS wg_parser_stream_get_preferred_format(void *args) { const struct wg_parser_stream_get_preferred_format_params *params = args; @@ -1229,6 +1297,55 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) return TRUE; } + case GST_QUERY_ALLOCATION: + { + GstCaps *caps; + gboolean need_pool; + + if (stream->parser->allocator) + { + gst_query_parse_allocation(query, &caps, &need_pool); + GST_DEBUG("allocation query, need-pool: %u", need_pool); + + if (need_pool) + { + if (gst_query_get_n_allocation_pools(query) > 0) + { + /* pool exists, so set our allocator on it */ + GstAllocator *old_alloc; + GstAllocationParams old_params; + GstBufferPool *pool; + GstStructure *config; + + GST_DEBUG("adding our alloc to extant pool"); + + gst_query_parse_nth_allocation_pool(query, 0, &pool, NULL, NULL, NULL); + + config = gst_buffer_pool_get_config(pool); + + gst_buffer_pool_config_get_allocator(config, &old_alloc, &old_params); + + gst_buffer_pool_config_set_allocator(config, stream->parser->allocator, &old_params); + + gst_buffer_pool_set_config(pool, config); + } + else + { + /* no pool exists, so return allocator directly for upstream to use */ + GST_DEBUG("no pool, so returning our alloc"); + + assert(gst_query_get_n_allocation_params(query) == 0); /* check that we're using this API correctly */ + + gst_query_add_allocation_param(query, stream->parser->allocator, NULL); + } + } + + return TRUE; + } + + return gst_pad_query_default (pad, parent, query); + } + default: return gst_pad_query_default (pad, parent, query); } @@ -2170,6 +2287,7 @@ static NTSTATUS wg_parser_connect(void *args) parser->sink_connected = false; pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_cond); + pthread_cond_signal(&parser->alloc_cond); if (use_mediaconv) { @@ -2254,6 +2372,7 @@ static NTSTATUS wg_parser_disconnect(void *args) parser->sink_connected = false; pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_cond); + pthread_cond_signal(&parser->alloc_cond); for (i = 0; i < parser->stream_count; ++i) free_stream(parser->streams[i]); @@ -2277,6 +2396,14 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) if (!(element = create_element("decodebin", "base"))) return FALSE; + if (parser->use_wine_allocator) + { + WineMemoryAllocator *alloc; + parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); + alloc = (WineMemoryAllocator *)parser->allocator; + alloc->parser = parser; + } + if (parser->input_format.major_type) g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); @@ -2522,6 +2649,148 @@ static BOOL video_convert_init_gst(struct wg_parser *parser) return TRUE; } +static GstMemory * +wine_memory_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params) +{ + WineMemoryAllocator *alloc = (WineMemoryAllocator *)allocator; + struct wg_parser *parser = alloc->parser; + SIZE_T maxsize = size + params->prefix + params->padding; + struct wine_memory *winemem; + void *data, *user; + + pthread_mutex_lock(&parser->alloc_lock); + pthread_mutex_lock(&parser->alloc_req_lock); + + /* get memory from win32 thread */ + parser->alloc_request.type = WG_PARSER_ALLOC_NEW; + parser->alloc_request.size = maxsize; + parser->alloc_request.align = params ? params->align : 1; + parser->alloc_request.data = NULL; + parser->alloc_request.user = NULL; + pthread_cond_signal(&parser->alloc_cond); + + while (!parser->alloc_request.done) + pthread_cond_wait(&parser->alloc_done_cond, &parser->alloc_req_lock); + + data = parser->alloc_request.data; + user = parser->alloc_request.user; + + parser->alloc_request.done = false; + + pthread_mutex_unlock(&parser->alloc_req_lock); + pthread_mutex_unlock(&parser->alloc_lock); + + if (!data) { + GST_WARNING("Allocating %u bytes failed!", (int)size); + return NULL; + } + + winemem = malloc(sizeof(*winemem)); + winemem->user = user; + winemem->data = data; + + gst_memory_init(&winemem->mem, params->flags, allocator, NULL, + maxsize, params->align, params->prefix, size); + + return &winemem->mem; +} + +static void +wine_memory_free (GstAllocator * allocator, GstMemory * mem) +{ + WineMemoryAllocator *alloc = (WineMemoryAllocator *)allocator; + struct wg_parser *parser = alloc->parser; + struct wine_memory *winemem = (struct wine_memory *)mem; + + if (winemem->user) + { + /* free memory in win32 thread */ + pthread_mutex_lock(&parser->alloc_lock); + pthread_mutex_lock(&parser->alloc_req_lock); + + parser->alloc_request.type = WG_PARSER_ALLOC_FREE; + parser->alloc_request.user = winemem->user; + pthread_cond_signal(&parser->alloc_cond); + + while (!parser->alloc_request.done) + pthread_cond_wait(&parser->alloc_done_cond, &parser->alloc_req_lock); + + parser->alloc_request.type = WG_PARSER_ALLOC_NONE; + parser->alloc_request.done = false; + + pthread_mutex_unlock(&parser->alloc_req_lock); + pthread_mutex_unlock(&parser->alloc_lock); + } + + free(winemem); +} + +static gpointer +wine_memory_mem_map (GstMemory *mem, gsize maxsize, GstMapFlags flags) +{ + struct wine_memory *winemem = (struct wine_memory *)mem; + return winemem->data; +} + +static void +wine_memory_mem_unmap (GstMemory * mem) +{ + /* noop */ +} + +static GstMemory * +wine_memory_mem_share (GstMemory *mem, gssize offset, gssize size) +{ + struct wine_memory *ret = NULL, *winemem = (struct wine_memory *)mem; + GstMemory *parent; + SIZE_T maxsize = sizeof(struct wine_memory); + + ret = malloc(maxsize); + + parent = winemem->mem.parent; + if (!parent) + parent = &winemem->mem; + + ret->user = NULL; + ret->data = winemem->data; + + gst_memory_init(&ret->mem, + GST_MINI_OBJECT_FLAGS(parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY, + winemem->mem.allocator, parent, + winemem->mem.maxsize, winemem->mem.align, winemem->mem.offset + offset, + size); + + return &ret->mem; +} + +typedef struct +{ + GstAllocatorClass parent_class; +} WineMemoryAllocatorClass; + +G_DEFINE_TYPE (WineMemoryAllocator, WineMemoryAllocator, GST_TYPE_ALLOCATOR); + +static void +WineMemoryAllocator_class_init (WineMemoryAllocatorClass * klass) +{ + GstAllocatorClass *allocator_class; + + allocator_class = (GstAllocatorClass *) klass; + + allocator_class->alloc = wine_memory_alloc; + allocator_class->free = wine_memory_free; +} + +static void +WineMemoryAllocator_init (WineMemoryAllocator * allocator) +{ + GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); + alloc->mem_type = "wine_memory"; + alloc->mem_map = wine_memory_mem_map; + alloc->mem_unmap = wine_memory_mem_unmap; + alloc->mem_share = wine_memory_mem_share; +} + static void init_gstreamer_once(void) { char arg0[] = "wine"; @@ -2592,12 +2861,17 @@ static NTSTATUS wg_parser_create(void *args) return E_OUTOFMEMORY; pthread_mutex_init(&parser->mutex, NULL); + pthread_mutex_init(&parser->alloc_req_lock, NULL); + pthread_mutex_init(&parser->alloc_lock, NULL); pthread_cond_init(&parser->init_cond, NULL); pthread_cond_init(&parser->read_cond, NULL); pthread_cond_init(&parser->read_done_cond, NULL); + pthread_cond_init(&parser->alloc_cond, NULL); + pthread_cond_init(&parser->alloc_done_cond, NULL); parser->flushing = true; parser->init_gst = init_funcs[params->type]; parser->unlimited_buffering = params->unlimited_buffering; + parser->use_wine_allocator = params->use_wine_allocator; GST_DEBUG("Created winegstreamer parser %p.\n", parser); params->parser = parser; @@ -2614,10 +2888,17 @@ static NTSTATUS wg_parser_destroy(void *args) gst_object_unref(parser->bus); } + if (parser->allocator) + g_object_unref(parser->allocator); + pthread_mutex_destroy(&parser->mutex); + pthread_mutex_destroy(&parser->alloc_req_lock); + pthread_mutex_destroy(&parser->alloc_lock); pthread_cond_destroy(&parser->init_cond); pthread_cond_destroy(&parser->read_cond); pthread_cond_destroy(&parser->read_done_cond); + pthread_cond_destroy(&parser->alloc_cond); + pthread_cond_destroy(&parser->alloc_done_cond); free(parser); return S_OK; @@ -2639,6 +2920,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_next_read_offset), X(wg_parser_push_data), + X(wg_parser_get_next_alloc_req), + X(wg_parser_provide_alloc_buffer), + X(wg_parser_get_stream_count), X(wg_parser_get_stream), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 905ce7306c8..937376ec5f0 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1455,7 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) HRESULT hr; WORD i; - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true, false))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From a71e8ba0ecfb89575930273d0c4dd179b7582dc6 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Wed, 19 Jan 2022 14:19:29 -0600 Subject: [PATCH 32/83] winegstreamer: Return MFMediaBuffer-backed memory directly to media_source client --- dlls/winegstreamer/audioconvert.c | 9 ++- dlls/winegstreamer/colorconvert.c | 9 ++- dlls/winegstreamer/decode_transform.c | 7 +- dlls/winegstreamer/gst_private.h | 9 ++- dlls/winegstreamer/main.c | 33 ++++++-- dlls/winegstreamer/media_source.c | 86 ++++++++++++++------- dlls/winegstreamer/quartz_parser.c | 10 ++- dlls/winegstreamer/unixlib.h | 16 ++++ dlls/winegstreamer/wg_parser.c | 104 +++++++++++++++++++------- dlls/winegstreamer/wm_reader.c | 11 +-- 10 files changed, 216 insertions(+), 78 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index 9086cdf8038..9e7d8288edc 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -633,7 +633,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME while (event.type != WG_PARSER_EVENT_BUFFER) wg_parser_stream_get_event(converter->stream, &event); - wg_parser_stream_release_buffer(converter->stream); + wg_parser_stream_release_buffer(converter->stream, NULL); converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); @@ -717,6 +717,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f struct wg_parser_event event; unsigned char *buffer_data; DWORD buffer_len; + void *gstcookie; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -825,7 +826,9 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) + wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); + + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) { ERR("Failed to copy buffer.\n"); IMFMediaBuffer_Unlock(buffer); @@ -835,7 +838,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f IMFMediaBuffer_Unlock(buffer); - wg_parser_stream_release_buffer(converter->stream); + wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index ae1958c67fc..b7e65131004 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -629,7 +629,7 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME while (event.type != WG_PARSER_EVENT_BUFFER) wg_parser_stream_get_event(converter->stream, &event); - wg_parser_stream_release_buffer(converter->stream); + wg_parser_stream_release_buffer(converter->stream, NULL); converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); @@ -721,6 +721,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f struct wg_parser_event event; unsigned char *buffer_data; DWORD buffer_len; + void *gstcookie; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -829,7 +830,9 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) + wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); + + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) { ERR("Failed to copy buffer.\n"); IMFMediaBuffer_Unlock(buffer); @@ -839,7 +842,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f IMFMediaBuffer_Unlock(buffer); - wg_parser_stream_release_buffer(converter->stream); + wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index f84c8659491..117c8042d93 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -971,6 +971,7 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, struct pipeline_event pip_event; IMFMediaBuffer *buffer; DWORD buffer_len; + void *gstcookie; unsigned int i; BYTE *data; HRESULT hr; @@ -1120,7 +1121,9 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, goto out; } - if (!wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) + wg_parser_stream_retrieve_buffer(decoder->wg_stream, NULL, NULL, &gstcookie); + + if (!wg_parser_stream_copy_buffer(decoder->wg_stream, gstcookie, data, 0, min(buffer_len, event.u.buffer.size))) { hr = E_FAIL; goto out; @@ -1150,7 +1153,7 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, out: if (SUCCEEDED(hr)) - wg_parser_stream_release_buffer(decoder->wg_stream); + wg_parser_stream_release_buffer(decoder->wg_stream, gstcookie); LeaveCriticalSection(&decoder->cs); if (FAILED(hr)) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 877d3016376..84495184d8a 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -90,9 +90,10 @@ void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_fo void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN; +void wg_parser_stream_retrieve_buffer(struct wg_parser_stream *stream, void **user, uint32_t *offset, void **cookie) DECLSPEC_HIDDEN; bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; -void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; + void *cookie, void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream, void *cookie) DECLSPEC_HIDDEN; void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, bool underflow, double proportion, int64_t diff, uint64_t timestamp) DECLSPEC_HIDDEN; @@ -229,6 +230,10 @@ struct wg_mf_buffer BYTE *data; DWORD max_length; DWORD current_length; + DWORD offset; + + void *gstcookie; + struct wg_parser_stream *wg_stream; }; struct allocator_thread_data { diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 4c353b4d3fa..9a016ea065e 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -76,7 +76,12 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) TRACE("%p, refcount %u.\n", iface, refcount); - if (!refcount) + if (refcount == 1 && buffer->wg_stream && buffer->gstcookie) + { + wg_parser_stream_release_buffer(buffer->wg_stream, buffer->gstcookie); + /* above call may free buffer obj, don't deref past this */ + } + else if (!refcount) { free(buffer->data); free(buffer); @@ -94,7 +99,7 @@ static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWO if (!data) return E_INVALIDARG; - *data = buffer->data; + *data = buffer->data + buffer->offset; if (max_length) *max_length = buffer->max_length; if (current_length) @@ -434,12 +439,25 @@ bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parse return !__wine_unix_call(unix_handle, unix_wg_parser_stream_get_event, ¶ms); } +void wg_parser_stream_retrieve_buffer(struct wg_parser_stream *stream, void **user, uint32_t *offset, void **cookie) +{ + struct wg_parser_stream_retrieve_buffer_params params = + { + .stream = stream, + .user = user, + .cookie = cookie, + .offset = offset, + }; + __wine_unix_call(unix_handle, unix_wg_parser_stream_retrieve_buffer, ¶ms); +} + bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *data, uint32_t offset, uint32_t size) + void *cookie, void *data, uint32_t offset, uint32_t size) { struct wg_parser_stream_copy_buffer_params params = { .stream = stream, + .cookie = cookie, .data = data, .offset = offset, .size = size, @@ -448,9 +466,14 @@ bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, return !__wine_unix_call(unix_handle, unix_wg_parser_stream_copy_buffer, ¶ms); } -void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream, void *cookie) { - __wine_unix_call(unix_handle, unix_wg_parser_stream_release_buffer, stream); + struct wg_parser_stream_release_buffer_params params = + { + .stream = stream, + .cookie = cookie, + }; + __wine_unix_call(unix_handle, unix_wg_parser_stream_release_buffer, ¶ms); } void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 312f9918355..3c58b417ecf 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -459,6 +459,9 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even IMFSample *sample; HRESULT hr; BYTE *data; + struct wg_mf_buffer *ourbuf = NULL; + void *gstcookie; + uint32_t offset; if (FAILED(hr = MFCreateSample(&sample))) { @@ -466,42 +469,71 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even return; } - if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer))) + wg_parser_stream_retrieve_buffer(stream->wg_stream, (void **)&ourbuf, &offset, &gstcookie); + if (ourbuf) { - ERR("Failed to create buffer, hr %#x.\n", hr); - IMFSample_Release(sample); - return; - } + TRACE("fast path\n"); + /* fast path. using our memory, so return straight to app */ + ourbuf->gstcookie = gstcookie; + ourbuf->wg_stream = stream->wg_stream; - if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) - { - ERR("Failed to add buffer, hr %#x.\n", hr); - goto out; - } + /* technically, we should spawn a new MediaBuf with this one as parent; + * a different view into the same buffer. hopefully this is good + * enough... */ + ourbuf->offset = offset; - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto out; - } + buffer = &ourbuf->IMFMediaBuffer_iface; + IMFMediaBuffer_AddRef(buffer); + assert(ourbuf->refcount == 2); - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) - { - ERR("Failed to lock buffer, hr %#x.\n", hr); - goto out; + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto out; + } } - - if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size)) + else { - wg_parser_stream_release_buffer(stream->wg_stream); - IMFMediaBuffer_Unlock(buffer); - goto out; + TRACE("slow path: %u bytes\n", event->u.buffer.size); + /* slow path. gst allocated its own memory, so copy it out */ + if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer))) + { + ERR("Failed to create buffer, hr %#x.\n", hr); + IMFSample_Release(sample); + return; + } + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto out; + } + + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) + { + ERR("Failed to lock buffer, hr %#x.\n", hr); + goto out; + } + + if (!wg_parser_stream_copy_buffer(stream->wg_stream, gstcookie, data, 0, event->u.buffer.size)) + { + wg_parser_stream_release_buffer(stream->wg_stream, gstcookie); + IMFMediaBuffer_Unlock(buffer); + goto out; + } + + wg_parser_stream_release_buffer(stream->wg_stream, gstcookie); + + if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) + { + ERR("Failed to unlock buffer, hr %#x.\n", hr); + goto out; + } } - wg_parser_stream_release_buffer(stream->wg_stream); - if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) + if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) { - ERR("Failed to unlock buffer, hr %#x.\n", hr); + ERR("Failed to add buffer, hr %#x.\n", hr); goto out; } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index e4d448f3767..38cf14ed8a5 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -673,6 +673,7 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, { HRESULT hr; BYTE *ptr = NULL; + void *gstcookie; TRACE("offset %u, size %u, sample size %u\n", offset, size, IMediaSample_GetSize(sample)); @@ -684,12 +685,17 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, IMediaSample_GetPointer(sample, &ptr); - if (!wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size)) + wg_parser_stream_retrieve_buffer(pin->wg_stream, NULL, NULL, &gstcookie); + + if (!wg_parser_stream_copy_buffer(pin->wg_stream, gstcookie, ptr, offset, size)) { + wg_parser_stream_release_buffer(pin->wg_stream, gstcookie); /* The GStreamer pin has been flushed. */ return S_OK; } + wg_parser_stream_release_buffer(pin->wg_stream, gstcookie); + if (event->u.buffer.has_pts) { REFERENCE_TIME start_pts = event->u.buffer.pts; @@ -792,8 +798,6 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_event IMediaSample_Release(sample); } } - - wg_parser_stream_release_buffer(pin->wg_stream); } static DWORD CALLBACK stream_thread(void *arg) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 0a77b4b9741..d5bda43b170 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -280,14 +280,29 @@ struct wg_parser_stream_get_event_params struct wg_parser_event *event; }; +struct wg_parser_stream_retrieve_buffer_params +{ + struct wg_parser_stream *stream; + void **user; + uint32_t *offset; + void **cookie; +}; + struct wg_parser_stream_copy_buffer_params { struct wg_parser_stream *stream; + void *cookie; void *data; UINT32 offset; UINT32 size; }; +struct wg_parser_stream_release_buffer_params +{ + struct wg_parser_stream *stream; + void *cookie; +}; + struct wg_parser_stream_notify_qos_params { struct wg_parser_stream *stream; @@ -381,6 +396,7 @@ enum unix_funcs unix_wg_parser_stream_disable, unix_wg_parser_stream_get_event, + unix_wg_parser_stream_retrieve_buffer, unix_wg_parser_stream_copy_buffer, unix_wg_parser_stream_release_buffer, unix_wg_parser_stream_notify_qos, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 80ee1b17e5a..95e9e850d06 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -121,7 +121,6 @@ struct wg_parser_stream pthread_cond_t event_cond, event_empty_cond; struct wg_parser_event event; GstBuffer *buffer; - GstMapInfo map_info; bool flushing, eos, enabled, has_caps; @@ -144,6 +143,11 @@ struct wine_memory { void *user; }; +struct wg_buffer_cookie_data { + GstBuffer *gstbuf; + GstMapInfo map_info; +}; + static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) { switch (format) @@ -836,13 +840,14 @@ static NTSTATUS wg_parser_stream_get_event(void *args) return S_OK; } -static NTSTATUS wg_parser_stream_copy_buffer(void *args) +/* TODO: can we just put this in wg_parser_event::buffer? */ +static NTSTATUS wg_parser_stream_retrieve_buffer(void *args) { - const struct wg_parser_stream_copy_buffer_params *params = args; + struct wg_parser_stream_retrieve_buffer_params *params = args; struct wg_parser_stream *stream = params->stream; struct wg_parser *parser = stream->parser; - uint32_t offset = params->offset; - uint32_t size = params->size; + struct wine_memory *winemem = NULL; + struct wg_buffer_cookie_data *cookie; pthread_mutex_lock(&parser->mutex); @@ -853,30 +858,83 @@ static NTSTATUS wg_parser_stream_copy_buffer(void *args) } assert(stream->event.type == WG_PARSER_EVENT_BUFFER); - assert(offset < stream->map_info.size); - assert(offset + size <= stream->map_info.size); - memcpy(params->data, stream->map_info.data + offset, size); + cookie = calloc(1, sizeof(*cookie)); + + if (!gst_buffer_map(stream->buffer, &cookie->map_info, GST_MAP_READ)) + { + pthread_mutex_unlock(&parser->mutex); + free(cookie); + GST_ERROR("Failed to map buffer.\n"); + return E_FAIL; + } + + /* transfer ownership */ + cookie->gstbuf = stream->buffer; + stream->buffer = NULL; + + if (params->user) + { + if (!strcmp(cookie->map_info.memory->allocator->mem_type, "wine_memory")) + winemem = (struct wine_memory *)cookie->map_info.memory; + + *params->user = winemem ? winemem->user : NULL; + *params->offset = cookie->map_info.memory->offset; + } + + *params->cookie = cookie; + + stream->event.type = WG_PARSER_EVENT_NONE; + + pthread_cond_signal(&stream->event_empty_cond); pthread_mutex_unlock(&parser->mutex); + return S_OK; } -static NTSTATUS wg_parser_stream_release_buffer(void *args) +static NTSTATUS wg_parser_stream_copy_buffer(void *args) { - struct wg_parser_stream *stream = args; + const struct wg_parser_stream_copy_buffer_params *params = args; + struct wg_parser_stream *stream = params->stream; struct wg_parser *parser = stream->parser; + struct wg_buffer_cookie_data *cookie = params->cookie; + uint32_t offset = params->offset; + uint32_t size = params->size; pthread_mutex_lock(&parser->mutex); - assert(stream->event.type == WG_PARSER_EVENT_BUFFER); - - gst_buffer_unmap(stream->buffer, &stream->map_info); - gst_buffer_unref(stream->buffer); - stream->buffer = NULL; - stream->event.type = WG_PARSER_EVENT_NONE; + assert(offset < cookie->map_info.size); + assert(offset + size <= cookie->map_info.size); + memcpy(params->data, cookie->map_info.data + offset, size); pthread_mutex_unlock(&parser->mutex); - pthread_cond_signal(&stream->event_empty_cond); + return S_OK; +} + +static NTSTATUS wg_parser_stream_release_buffer(void *args) +{ + const struct wg_parser_stream_release_buffer_params *params = args; + struct wg_parser_stream *stream = params->stream; + struct wg_parser *parser = stream->parser; + struct wg_buffer_cookie_data *cookie = params->cookie; + + if (cookie) + { + gst_buffer_unmap(cookie->gstbuf, &cookie->map_info); + gst_buffer_unref(cookie->gstbuf); + free(cookie); + } + else + { + pthread_mutex_lock(&parser->mutex); + + gst_buffer_unref(stream->buffer); + stream->buffer = NULL; + stream->event.type = WG_PARSER_EVENT_NONE; + + pthread_cond_signal(&stream->event_empty_cond); + pthread_mutex_unlock(&parser->mutex); + } return S_OK; } @@ -1073,16 +1131,6 @@ static GstFlowReturn queue_stream_event(struct wg_parser_stream *stream, GST_DEBUG("Filter is flushing; discarding event."); return GST_FLOW_FLUSHING; } - if (buffer) - { - assert(GST_IS_BUFFER(buffer)); - if (!gst_buffer_map(buffer, &stream->map_info, GST_MAP_READ)) - { - pthread_mutex_unlock(&parser->mutex); - GST_ERROR("Failed to map buffer.\n"); - return GST_FLOW_ERROR; - } - } stream->event = *event; stream->buffer = buffer; pthread_mutex_unlock(&parser->mutex); @@ -1151,7 +1199,6 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) if (stream->event.type == WG_PARSER_EVENT_BUFFER) { - gst_buffer_unmap(stream->buffer, &stream->map_info); gst_buffer_unref(stream->buffer); stream->buffer = NULL; } @@ -2931,6 +2978,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_stream_disable), X(wg_parser_stream_get_event), + X(wg_parser_stream_retrieve_buffer), X(wg_parser_stream_copy_buffer), X(wg_parser_stream_release_buffer), X(wg_parser_stream_notify_qos), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 937376ec5f0..59f0930ec47 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1854,6 +1854,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, { DWORD size, capacity; INSSBuffer *sample; + void *gstcookie; HRESULT hr; BYTE *data; @@ -1863,7 +1864,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, stream->index + 1, event.u.buffer.size, &sample, NULL))) { ERR("Failed to allocate stream sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); - wg_parser_stream_release_buffer(wg_stream); return hr; } } @@ -1873,7 +1873,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, stream->index, event.u.buffer.size, &sample, NULL))) { ERR("Failed to allocate output sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); - wg_parser_stream_release_buffer(wg_stream); return hr; } } @@ -1884,7 +1883,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, /* FIXME: Should these be pooled? */ if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size])))) { - wg_parser_stream_release_buffer(wg_stream); return E_OUTOFMEMORY; } @@ -1904,9 +1902,12 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, ERR("Returned capacity %u is less than requested capacity %u.\n", capacity, event.u.buffer.size); - if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, event.u.buffer.size)) + wg_parser_stream_retrieve_buffer(wg_stream, NULL, NULL, &gstcookie); + + if (!wg_parser_stream_copy_buffer(wg_stream, gstcookie, data, 0, event.u.buffer.size)) { /* The GStreamer pin has been flushed. */ + wg_parser_stream_release_buffer(wg_stream, gstcookie); INSSBuffer_Release(sample); break; } @@ -1914,7 +1915,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, if (FAILED(hr = INSSBuffer_SetLength(sample, event.u.buffer.size))) ERR("Failed to set size %u, hr %#x.\n", event.u.buffer.size, hr); - wg_parser_stream_release_buffer(wg_stream); + wg_parser_stream_release_buffer(wg_stream, gstcookie); if (!event.u.buffer.has_pts) FIXME("Missing PTS.\n"); From f8c2c88736277c85304dc55e041c513bd7d38c15 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 21 Jan 2022 08:08:56 -0600 Subject: [PATCH 33/83] winegstreamer: Return MFMediaBuffer-backed memory directly to color converter client --- dlls/winegstreamer/colorconvert.c | 146 ++++++++++++++++++++---------- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 7 +- dlls/winegstreamer/media_source.c | 1 + dlls/winegstreamer/wg_parser.c | 8 ++ 5 files changed, 114 insertions(+), 49 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index b7e65131004..4455a12bb34 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -55,6 +55,8 @@ struct color_converter LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; + HANDLE read_thread, alloc_thread; + struct allocator_thread_data alloc_thread_data; }; static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) @@ -104,6 +106,11 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) IMFMediaType_Release(transform->output_type); if (transform->stream) wg_parser_disconnect(transform->parser); + + transform->alloc_thread_data.done = true; + WaitForSingleObject(transform->alloc_thread, INFINITE); + CloseHandle(transform->alloc_thread); + if (transform->parser) wg_parser_destroy(transform->parser); free(transform); @@ -722,6 +729,8 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f unsigned char *buffer_data; DWORD buffer_len; void *gstcookie; + struct wg_mf_buffer *ourbuf; + uint32_t offset; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -771,78 +780,116 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f break; } - if (!samples[0].pSample) + wg_parser_stream_retrieve_buffer(converter->stream, (void **)&ourbuf, &offset, &gstcookie); + if (samples[0].pSample || !ourbuf) { - if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) + TRACE("slow path: %u bytes\n", event.u.buffer.size); + + if (samples[0].pSample) { - ERR("Failed to create buffer, hr %#x.\n", hr); - goto done; + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) + { + ERR("Failed to get buffer from sample, hr %#x.\n", hr); + goto done; + } + + if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) + { + ERR("Failed to get buffer size, hr %#x.\n", hr); + goto done; + } + + if (buffer_len < event.u.buffer.size) + { + WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", + buffer_len, event.u.buffer.size); + + hr = MF_E_BUFFERTOOSMALL; + goto done; + } } + else + { + if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) + { + ERR("Failed to create buffer, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = MFCreateSample(&allocated_sample))) + if (FAILED(hr = MFCreateSample(&allocated_sample))) + { + ERR("Failed to create sample, hr %#x.\n", hr); + goto done; + } + + if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) + { + ERR("Failed to add buffer, hr %#x.\n", hr); + goto done; + } + + samples[0].pSample = allocated_sample; + } + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) { - ERR("Failed to create sample, hr %#x.\n", hr); + ERR("Failed to set size, hr %#x.\n", hr); goto done; } - samples[0].pSample = allocated_sample; + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + { + ERR("Failed to lock buffer hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) { - ERR("Failed to add buffer, hr %#x.\n", hr); + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); + hr = E_FAIL; goto done; } + IMFMediaBuffer_Unlock(buffer); IMFMediaBuffer_Release(buffer); buffer = NULL; - } - if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) - { - ERR("Failed to get buffer from sample, hr %#x.\n", hr); - goto done; + wg_parser_stream_release_buffer(converter->stream, gstcookie); } - - if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) + else { - ERR("Failed to get buffer size, hr %#x.\n", hr); - goto done; - } + TRACE("fast path\n"); - if (buffer_len < event.u.buffer.size) - { - WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", - buffer_len, event.u.buffer.size); + ourbuf->gstcookie = gstcookie; + ourbuf->wg_stream = converter->stream; + ourbuf->offset = offset; - hr = MF_E_BUFFERTOOSMALL; - goto done; - } + buffer = &ourbuf->IMFMediaBuffer_iface; + IMFMediaBuffer_AddRef(buffer); + assert(ourbuf->refcount == 2); - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) - { - ERR("Failed to lock buffer hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = MFCreateSample(&allocated_sample))) + { + ERR("Failed to create sample, hr %#x.\n", hr); + goto done; + } - wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); + if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) + { + ERR("Failed to add buffer, hr %#x.\n", hr); + goto done; + } - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) - { - ERR("Failed to copy buffer.\n"); - IMFMediaBuffer_Unlock(buffer); - hr = E_FAIL; - goto done; + samples[0].pSample = allocated_sample; } - IMFMediaBuffer_Unlock(buffer); - - wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) @@ -910,13 +957,18 @@ HRESULT color_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, false))) + if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, true))) { ERR("Failed to create video converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); return E_OUTOFMEMORY; } + object->alloc_thread_data.done = FALSE; + object->alloc_thread_data.wg_parser = object->parser; + object->alloc_thread_data.log_pfx = "color_converter"; + object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); + *ret = &object->IMFTransform_iface; return S_OK; } diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 84495184d8a..f80b312c63a 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -239,6 +239,7 @@ struct wg_mf_buffer struct allocator_thread_data { BOOL done; struct wg_parser *wg_parser; + const char *log_pfx; }; HANDLE start_allocator_thread(struct allocator_thread_data *) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 9a016ea065e..eb8c4c61941 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -195,7 +195,7 @@ DWORD CALLBACK allocator_thread(void *arg) struct allocator_thread_data *data = arg; enum wg_parser_alloc_req_type type; - TRACE("Starting alloc thread for parser %p.\n", data->wg_parser); + TRACE("%s: Starting alloc thread for parser %p.\n", data->log_pfx, data->wg_parser); while (!data->done) { @@ -211,21 +211,24 @@ DWORD CALLBACK allocator_thread(void *arg) { struct wg_mf_buffer *buf = create_memory_buffer(size, align ? align : 1); wg_parser_provide_alloc_buffer(data->wg_parser, buf ? buf->data : NULL, buf); + TRACE("%s: Alloc req for %u bytes --> %p\n", data->log_pfx, size, buf); break; } case WG_PARSER_ALLOC_FREE: { struct wg_mf_buffer *buf = user; + TRACE("%s: Free req for %p\n", data->log_pfx, buf); IMFMediaBuffer_Release(&buf->IMFMediaBuffer_iface); wg_parser_provide_alloc_buffer(data->wg_parser, NULL, NULL); /* mark done */ break; } default: + FIXME("%s: Invalid alloc req?!\n", data->log_pfx); break; } } - TRACE("Media source is shutting down; exiting alloc thread.\n"); + TRACE("%s: Media source is shutting down; exiting alloc thread.\n", data->log_pfx); return 0; } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 3c58b417ecf..bc93258945c 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1488,6 +1488,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->alloc_thread_data.done = FALSE; object->alloc_thread_data.wg_parser = parser; + object->alloc_thread_data.log_pfx = "media_source"; object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); object->state = SOURCE_OPENING; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 95e9e850d06..27ff1663cef 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2658,6 +2658,14 @@ static BOOL video_convert_init_gst(struct wg_parser *parser) if (parser->input_format.major_type != WG_MAJOR_TYPE_VIDEO) return FALSE; + if (parser->use_wine_allocator) + { + WineMemoryAllocator *alloc; + parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); + alloc = (WineMemoryAllocator *)parser->allocator; + alloc->parser = parser; + } + if (!(convert = create_element("videoconvert", "base"))) return FALSE; From 4e4a7ee0f569f630b64f53d597eb3eda4ed8af20 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 21 Jan 2022 08:54:40 -0600 Subject: [PATCH 34/83] winegstreamer: Avoid input buffer copy in colorconvert --- dlls/winegstreamer/audioconvert.c | 2 +- dlls/winegstreamer/colorconvert.c | 34 +++++++++++++++++++-------- dlls/winegstreamer/decode_transform.c | 8 +++---- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 ++- dlls/winegstreamer/media_source.c | 4 ++-- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_parser.c | 21 +++++++++++++---- dlls/winegstreamer/wm_reader.c | 8 +++---- 10 files changed, 56 insertions(+), 29 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index 9e7d8288edc..e3514d03ddb 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -692,7 +692,7 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); IMFMediaBuffer_Unlock(buffer); converter->buffer_inflight = TRUE; diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index 4455a12bb34..11199759488 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -51,7 +51,8 @@ struct color_converter IMFMediaType *input_type; IMFMediaType *output_type; CRITICAL_SECTION cs; - BOOL buffer_inflight; + IMFSample *inflight_sample; + IMFMediaBuffer *inflight_buffer; LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; @@ -157,7 +158,7 @@ static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DW if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; info->cbMaxLookahead = 0; info->cbAlignment = 0; info->hnsMaxLatency = 0; @@ -627,7 +628,7 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME case MFT_MESSAGE_COMMAND_FLUSH: { EnterCriticalSection(&converter->cs); - if (!converter->buffer_inflight) + if (!converter->inflight_sample) { LeaveCriticalSection(&converter->cs); return S_OK; @@ -637,7 +638,11 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME wg_parser_stream_get_event(converter->stream, &event); wg_parser_stream_release_buffer(converter->stream, NULL); - converter->buffer_inflight = FALSE; + IMFMediaBuffer_Unlock(converter->inflight_buffer); + IMFMediaBuffer_Release(converter->inflight_buffer); + converter->inflight_buffer = NULL; + IMFSample_Release(converter->inflight_sample); + converter->inflight_sample = NULL; LeaveCriticalSection(&converter->cs); return S_OK; @@ -676,7 +681,7 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - if (converter->buffer_inflight) + if (converter->inflight_sample) { hr = MF_E_NOTACCEPTING; goto done; @@ -696,7 +701,7 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id continue; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size), false); if (buffer_size <= size) break; @@ -705,14 +710,19 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id buffer_size -= size; } - IMFMediaBuffer_Unlock(buffer); - converter->buffer_inflight = TRUE; + IMFSample_AddRef(sample); + converter->inflight_sample = sample; + converter->inflight_buffer = buffer; if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) converter->buffer_pts = -1; if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) converter->buffer_dur = -1; + sample = NULL; + buffer = NULL; done: + if (sample) + IMFSample_Release(sample); if (buffer) IMFMediaBuffer_Release(buffer); LeaveCriticalSection(&converter->cs); @@ -755,7 +765,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!converter->buffer_inflight) + if (!converter->inflight_sample) { hr = MF_E_TRANSFORM_NEED_MORE_INPUT; goto done; @@ -890,7 +900,11 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f samples[0].pSample = allocated_sample; } - converter->buffer_inflight = FALSE; + IMFMediaBuffer_Unlock(converter->inflight_buffer); + IMFMediaBuffer_Release(converter->inflight_buffer); + converter->inflight_buffer = NULL; + IMFSample_Release(converter->inflight_sample); + converter->inflight_sample = NULL; if (converter->buffer_pts != -1) IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index 117c8042d93..8114c25af9c 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -804,7 +804,7 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE pip_event = get_pipeline_event(decoder); assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); - wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0); + wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0, true); EnterCriticalSection(&decoder->event_cs); decoder->event.type = PIPELINE_EVENT_NONE; @@ -829,7 +829,7 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE pip_event = get_pipeline_event(decoder); assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); - wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0); + wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0, true); EnterCriticalSection(&decoder->event_cs); decoder->event.type = PIPELINE_EVENT_NONE; @@ -929,13 +929,13 @@ static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMF if (offset != decoder->offset_tracker) { ERR("A seek is needed, MFTs don't support this!\n"); - wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0); + wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0, true); IMFMediaBuffer_Unlock(buffer); hr = E_FAIL; goto done; } - wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size); + wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); decoder->offset_tracker += copy_size; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index f80b312c63a..8083fa7e129 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -76,7 +76,7 @@ void wg_parser_begin_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; -void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) DECLSPEC_HIDDEN; +void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size, bool need_copy) DECLSPEC_HIDDEN; bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, DWORD *size, DWORD *align, void **user) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index eb8c4c61941..6910756ff7a 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -339,7 +339,7 @@ bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, return true; } -void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) +void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size, bool need_copy) { struct wg_parser_push_data_params params = { @@ -347,6 +347,7 @@ void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, c .result = result, .data = data, .size = size, + .need_copy = need_copy, }; __wine_unix_call(unix_handle, unix_wg_parser_push_data, ¶ms); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index bc93258945c..e005210c6a3 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -676,7 +676,7 @@ static DWORD CALLBACK read_thread(void *arg) * an error when reading past the file size. */ if (!size) { - wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0); + wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0, true); continue; } @@ -694,7 +694,7 @@ static DWORD CALLBACK read_thread(void *arg) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); else if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size); + wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size, true); } free(data); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 38cf14ed8a5..395c36de314 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -885,7 +885,7 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size); + wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size, true); } free(data); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index d5bda43b170..549db0d46b5 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -246,6 +246,7 @@ struct wg_parser_push_data_params enum wg_read_result result; const void *data; UINT32 size; + bool need_copy; }; struct wg_parser_get_stream_count_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 27ff1663cef..45ac051f245 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -650,11 +650,22 @@ static NTSTATUS wg_parser_push_data(void *args) /* Note that we don't allocate the buffer until we have a size. * midiparse passes a NULL buffer and a size of UINT_MAX, in an * apparent attempt to read the whole input stream at once. */ - if (!parser->read_request.buffer) - parser->read_request.buffer = gst_buffer_new_and_alloc(size); - gst_buffer_map(parser->read_request.buffer, &map_info, GST_MAP_WRITE); - memcpy(map_info.data, data, size); - gst_buffer_unmap(parser->read_request.buffer, &map_info); + if (parser->read_request.buffer || params->need_copy) + { + GST_DEBUG("slow path: %u bytes", size); + if (!parser->read_request.buffer) + parser->read_request.buffer = gst_buffer_new_and_alloc(size); + gst_buffer_map(parser->read_request.buffer, &map_info, GST_MAP_WRITE); + memcpy(map_info.data, data, size); + gst_buffer_unmap(parser->read_request.buffer, &map_info); + } + else + { + GST_DEBUG("fast path"); + parser->read_request.buffer = gst_buffer_new_wrapped_full( + GST_MEMORY_FLAG_READONLY, (void*)data, size, 0, size, NULL, NULL); + } + parser->read_request.ret = GST_FLOW_OK; } else diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 59f0930ec47..6b549910b98 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -573,7 +573,7 @@ static DWORD CALLBACK read_thread(void *arg) if (!size) { - wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0); + wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0, true); continue; } @@ -592,7 +592,7 @@ static DWORD CALLBACK read_thread(void *arg) || !ReadFile(file, data, size, &ret_size, NULL)) { ERR("Failed to read %u bytes at offset %I64u, error %u.\n", size, offset, GetLastError()); - wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); + wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0, true); continue; } } @@ -603,14 +603,14 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) { ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); + wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0, true); continue; } } if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size); + wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size, true); } free(data); From 704b64341d08f16cdce148ad15d7040c0ebfdb25 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 21 Jan 2022 11:34:43 -0600 Subject: [PATCH 35/83] winegstreamer: Return MFMediaBuffer-backed memory directly to audio converter client --- dlls/winegstreamer/audioconvert.c | 148 ++++++++++++++++++++---------- dlls/winegstreamer/wg_parser.c | 8 ++ 2 files changed, 108 insertions(+), 48 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index e3514d03ddb..bfc94f69891 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -39,6 +39,8 @@ struct audio_converter LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; + HANDLE read_thread, alloc_thread; + struct allocator_thread_data alloc_thread_data; IMFAttributes *attributes, *output_attributes; }; @@ -91,6 +93,11 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) IMFAttributes_Release(transform->output_attributes); if (transform->stream) wg_parser_disconnect(transform->parser); + + transform->alloc_thread_data.done = true; + WaitForSingleObject(transform->alloc_thread, INFINITE); + CloseHandle(transform->alloc_thread); + if (transform->parser) wg_parser_destroy(transform->parser); free(transform); @@ -718,6 +725,8 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f unsigned char *buffer_data; DWORD buffer_len; void *gstcookie; + struct wg_mf_buffer *ourbuf; + uint32_t offset; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -767,78 +776,116 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f break; } - if (!samples[0].pSample) + wg_parser_stream_retrieve_buffer(converter->stream, (void **)&ourbuf, &offset, &gstcookie); + if (samples[0].pSample || !ourbuf) { - if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) + TRACE("slow path: %u bytes\n", event.u.buffer.size); + + if (samples[0].pSample) { - ERR("Failed to create buffer, hr %#x.\n", hr); - goto done; + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) + { + ERR("Failed to get buffer from sample, hr %#x.\n", hr); + goto done; + } + + if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) + { + ERR("Failed to get buffer size, hr %#x.\n", hr); + goto done; + } + + if (buffer_len < event.u.buffer.size) + { + WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", + buffer_len, event.u.buffer.size); + + hr = MF_E_BUFFERTOOSMALL; + goto done; + } } + else + { + if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) + { + ERR("Failed to create buffer, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = MFCreateSample(&allocated_sample))) + if (FAILED(hr = MFCreateSample(&allocated_sample))) + { + ERR("Failed to create sample, hr %#x.\n", hr); + goto done; + } + + if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) + { + ERR("Failed to add buffer, hr %#x.\n", hr); + goto done; + } + + samples[0].pSample = allocated_sample; + } + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) { - ERR("Failed to create sample, hr %#x.\n", hr); + ERR("Failed to set size, hr %#x.\n", hr); goto done; } - samples[0].pSample = allocated_sample; + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + { + ERR("Failed to lock buffer hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) { - ERR("Failed to add buffer, hr %#x.\n", hr); + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); + hr = E_FAIL; goto done; } + IMFMediaBuffer_Unlock(buffer); IMFMediaBuffer_Release(buffer); buffer = NULL; - } - if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) - { - ERR("Failed to get buffer from sample, hr %#x.\n", hr); - goto done; + wg_parser_stream_release_buffer(converter->stream, gstcookie); } - - if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) + else { - ERR("Failed to get buffer size, hr %#x.\n", hr); - goto done; - } + TRACE("fast path\n"); - if (buffer_len < event.u.buffer.size) - { - WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", - buffer_len, event.u.buffer.size); + ourbuf->gstcookie = gstcookie; + ourbuf->wg_stream = converter->stream; + ourbuf->offset = offset; - hr = MF_E_BUFFERTOOSMALL; - goto done; - } + buffer = &ourbuf->IMFMediaBuffer_iface; + IMFMediaBuffer_AddRef(buffer); + assert(ourbuf->refcount == 2); - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) - { - ERR("Failed to lock buffer hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = MFCreateSample(&allocated_sample))) + { + ERR("Failed to create sample, hr %#x.\n", hr); + goto done; + } - wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); + if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) + { + ERR("Failed to add buffer, hr %#x.\n", hr); + goto done; + } - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) - { - ERR("Failed to copy buffer.\n"); - IMFMediaBuffer_Unlock(buffer); - hr = E_FAIL; - goto done; + samples[0].pSample = allocated_sample; } - IMFMediaBuffer_Unlock(buffer); - - wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) @@ -852,7 +899,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f done: if (buffer) IMFMediaBuffer_Release(buffer); - if (allocated_sample && FAILED(hr)) + if (FAILED(hr) && allocated_sample) { IMFSample_Release(allocated_sample); samples[0].pSample = NULL; @@ -919,13 +966,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) return hr; } - if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, false))) + if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, true))) { ERR("Failed to create audio converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); return E_OUTOFMEMORY; } + object->alloc_thread_data.done = FALSE; + object->alloc_thread_data.wg_parser = object->parser; + object->alloc_thread_data.log_pfx = "audio_converter"; + object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); + *ret = &object->IMFTransform_iface; return S_OK; } diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 45ac051f245..cd2a19ec548 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2609,6 +2609,14 @@ static BOOL audio_convert_init_gst(struct wg_parser *parser) if (parser->input_format.major_type != WG_MAJOR_TYPE_AUDIO) return FALSE; + if (parser->use_wine_allocator) + { + WineMemoryAllocator *alloc; + parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); + alloc = (WineMemoryAllocator *)parser->allocator; + alloc->parser = parser; + } + if (!(convert = create_element("audioconvert", "base"))) return FALSE; From fbea0b362abed4879528bb189011b4ae01f83b76 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Fri, 21 Jan 2022 11:47:24 -0600 Subject: [PATCH 36/83] winegstreamer: Avoid input buffer copy in audio converter --- dlls/winegstreamer/audioconvert.c | 34 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index bfc94f69891..5cd5ba52923 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -35,7 +35,8 @@ struct audio_converter IMFMediaType *input_type; IMFMediaType *output_type; CRITICAL_SECTION cs; - BOOL buffer_inflight; + IMFSample *inflight_sample; + IMFMediaBuffer *inflight_buffer; LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; @@ -142,7 +143,7 @@ static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DW if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES; info->cbMaxLookahead = 0; info->cbAlignment = 0; info->hnsMaxLatency = 0; @@ -631,7 +632,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME case MFT_MESSAGE_COMMAND_FLUSH: { EnterCriticalSection(&converter->cs); - if (!converter->buffer_inflight) + if (!converter->inflight_sample) { LeaveCriticalSection(&converter->cs); return S_OK; @@ -641,7 +642,11 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME wg_parser_stream_get_event(converter->stream, &event); wg_parser_stream_release_buffer(converter->stream, NULL); - converter->buffer_inflight = FALSE; + IMFMediaBuffer_Unlock(converter->inflight_buffer); + IMFMediaBuffer_Release(converter->inflight_buffer); + converter->inflight_buffer = NULL; + IMFSample_Release(converter->inflight_sample); + converter->inflight_sample = NULL; LeaveCriticalSection(&converter->cs); return S_OK; @@ -680,7 +685,7 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - if (converter->buffer_inflight) + if (converter->inflight_sample) { hr = MF_E_NOTACCEPTING; goto done; @@ -699,16 +704,21 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, false); - IMFMediaBuffer_Unlock(buffer); - converter->buffer_inflight = TRUE; + IMFSample_AddRef(sample); + converter->inflight_sample = sample; + converter->inflight_buffer = buffer; if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) converter->buffer_pts = -1; if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) converter->buffer_dur = -1; + sample = NULL; + buffer = NULL; done: + if (sample) + IMFSample_Release(sample); if (buffer) IMFMediaBuffer_Release(buffer); LeaveCriticalSection(&converter->cs); @@ -751,7 +761,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!converter->buffer_inflight) + if (!converter->inflight_sample) { hr = MF_E_TRANSFORM_NEED_MORE_INPUT; goto done; @@ -886,7 +896,11 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f samples[0].pSample = allocated_sample; } - converter->buffer_inflight = FALSE; + IMFMediaBuffer_Unlock(converter->inflight_buffer); + IMFMediaBuffer_Release(converter->inflight_buffer); + converter->inflight_buffer = NULL; + IMFSample_Release(converter->inflight_sample); + converter->inflight_sample = NULL; if (converter->buffer_pts != -1) IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); From 29f3d241c72115d80321cef294e132b0e1f6dde7 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 25 Jan 2022 10:21:28 -0600 Subject: [PATCH 37/83] winegstreamer: Add MFVideoFormat_RGB32 output for the source. --- dlls/winegstreamer/media_source.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index e005210c6a3..a3aa6c0fd69 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -905,7 +905,7 @@ static HRESULT new_media_stream(struct media_source *source, static HRESULT media_stream_init_desc(struct media_stream *stream) { IMFMediaTypeHandler *type_handler = NULL; - IMFMediaType *stream_types[7]; + IMFMediaType *stream_types[8]; struct wg_format format; DWORD type_count = 0; unsigned int i; @@ -925,6 +925,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) &MFVideoFormat_IYUV, &MFVideoFormat_I420, &MFVideoFormat_ARGB32, + &MFVideoFormat_RGB32, }; IMFMediaType *base_type = mf_media_type_from_wg_format(&format); From b11d236a7f1fda63271bbc48c60c512c5fdbe152 Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 25 Jan 2022 10:29:58 -0600 Subject: [PATCH 38/83] HACK: mf: Always allow enumerating source types in topology This lets us connect directly to a source format without a color converter. --- dlls/mf/session.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index c8ec1b5c33f..883b765c348 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -1577,6 +1577,8 @@ static void session_set_topology(struct media_session *session, DWORD flags, IMF { hr = session_bind_output_nodes(topology); + IMFTopology_SetUINT32(topology, &MF_TOPOLOGY_ENUMERATE_SOURCE_TYPES, TRUE); + if (SUCCEEDED(hr)) hr = IMFTopoLoader_Load(session->topo_loader, topology, &resolved_topology, NULL /* FIXME? */); From dc6d87a2110743690a4211cd907c9ab43a80ba9c Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Thu, 27 Jan 2022 12:21:50 -0600 Subject: [PATCH 39/83] winegstreamer: Don't flip RGB for Media Foundation clients --- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 +- dlls/winegstreamer/media_source.c | 2 +- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 3 ++ dlls/winegstreamer/wg_parser.c | 47 ++++++++++++++++-------------- dlls/winegstreamer/wm_reader.c | 6 ++-- 7 files changed, 36 insertions(+), 29 deletions(-) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8083fa7e129..f4f2bf715f5 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -86,7 +86,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN; void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format) DECLSPEC_HIDDEN; -void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) DECLSPEC_HIDDEN; +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture, uint32_t flags) DECLSPEC_HIDDEN; void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6910756ff7a..fd1403396ba 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -415,13 +415,14 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru __wine_unix_call(unix_handle, unix_wg_parser_stream_get_preferred_format, ¶ms); } -void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) +void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture, uint32_t flags) { struct wg_parser_stream_enable_params params = { .stream = stream, .format = format, .aperture = aperture, + .flags = flags, }; __wine_unix_call(unix_handle, unix_wg_parser_stream_enable, ¶ms); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index a3aa6c0fd69..8ea40dd8b1a 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -358,7 +358,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); mf_media_type_to_wg_format(current_mt, &format); - wg_parser_stream_enable(stream->wg_stream, &format, NULL); + wg_parser_stream_enable(stream->wg_stream, &format, NULL, 0); IMFMediaType_Release(current_mt); IMFMediaTypeHandler_Release(mth); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 395c36de314..a7fc3b8ebf5 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1537,7 +1537,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, ret = amt_to_wg_format(&pin->pin.pin.mt, &format); assert(ret); - wg_parser_stream_enable(pin->wg_stream, &format, NULL); + wg_parser_stream_enable(pin->wg_stream, &format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB); /* We do need to drop any buffers that might have been sent with the old * caps, but this will be handled in parser_init_stream(). */ diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 549db0d46b5..0ad9134c495 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -268,11 +268,14 @@ struct wg_parser_stream_get_preferred_format_params struct wg_format *format; }; +#define STREAM_ENABLE_FLAG_FLIP_RGB 0x1 + struct wg_parser_stream_enable_params { struct wg_parser_stream *stream; const struct wg_format *format; const struct wg_rect *aperture; + uint32_t flags; }; struct wg_parser_stream_get_event_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index cd2a19ec548..89a64339413 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -751,31 +751,34 @@ static NTSTATUS wg_parser_stream_enable(void *args) if (format->major_type == WG_MAJOR_TYPE_VIDEO) { - bool flip = (format->u.video.height < 0); - - switch (format->u.video.format) + if (params->flags & STREAM_ENABLE_FLAG_FLIP_RGB) { - case WG_VIDEO_FORMAT_BGRA: - case WG_VIDEO_FORMAT_BGRx: - case WG_VIDEO_FORMAT_BGR: - case WG_VIDEO_FORMAT_RGB15: - case WG_VIDEO_FORMAT_RGB16: - flip = !flip; - break; + bool flip = (format->u.video.height < 0); - case WG_VIDEO_FORMAT_AYUV: - case WG_VIDEO_FORMAT_I420: - case WG_VIDEO_FORMAT_NV12: - case WG_VIDEO_FORMAT_UYVY: - case WG_VIDEO_FORMAT_YUY2: - case WG_VIDEO_FORMAT_YV12: - case WG_VIDEO_FORMAT_YVYU: - case WG_VIDEO_FORMAT_UNKNOWN: - case WG_VIDEO_FORMAT_CINEPAK: - break; - } + switch (format->u.video.format) + { + case WG_VIDEO_FORMAT_BGRA: + case WG_VIDEO_FORMAT_BGRx: + case WG_VIDEO_FORMAT_BGR: + case WG_VIDEO_FORMAT_RGB15: + case WG_VIDEO_FORMAT_RGB16: + flip = !flip; + break; - gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); + case WG_VIDEO_FORMAT_AYUV: + case WG_VIDEO_FORMAT_I420: + case WG_VIDEO_FORMAT_NV12: + case WG_VIDEO_FORMAT_UYVY: + case WG_VIDEO_FORMAT_YUY2: + case WG_VIDEO_FORMAT_YV12: + case WG_VIDEO_FORMAT_YVYU: + case WG_VIDEO_FORMAT_UNKNOWN: + case WG_VIDEO_FORMAT_CINEPAK: + break; + } + + gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); + } if (aperture) { diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 6b549910b98..ebe1ca4b57c 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1520,7 +1520,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; } } - wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); + wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB); } wg_parser_end_flush(reader->wg_parser); @@ -1787,7 +1787,7 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, } stream->format = format; - wg_parser_stream_enable(stream->wg_stream, &format, NULL); + wg_parser_stream_enable(stream->wg_stream, &format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB); /* Re-decode any buffers that might have been generated with the old format. * @@ -2001,7 +2001,7 @@ HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n", selections[i], stream_numbers[i]); TRACE("Enabling stream %u.\n", stream_numbers[i]); - wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); + wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL, STREAM_ENABLE_FLAG_FLIP_RGB); } } From 699e4c9e30694b49ed15c7e613936a717446dc86 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Sun, 6 Feb 2022 17:10:58 +0300 Subject: [PATCH 40/83] mshtml: Implement layerX/layerY properties for mouse event. CW-Bug-Id: #20114 Signed-off-by: Nikolay Sivov Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard (cherry picked from commit eb679a9630c8f0afd905a74c769a1d7b4009bb9d) --- dlls/mshtml/htmlevent.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 7ed1dfd2adc..1bfeeebd5a7 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1685,15 +1685,33 @@ static HRESULT WINAPI DOMMouseEvent_get_pageY(IDOMMouseEvent *iface, LONG *p) static HRESULT WINAPI DOMMouseEvent_get_layerX(IDOMMouseEvent *iface, LONG *p) { DOMEvent *This = impl_from_IDOMMouseEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + nsresult nsres; + LONG r; + + TRACE("(%p)->(%p)\n", This, p); + + nsres = nsIDOMMouseEvent_GetLayerX(This->mouse_event, &r); + if(NS_FAILED(nsres)) + return E_FAIL; + + *p = r; + return S_OK; } static HRESULT WINAPI DOMMouseEvent_get_layerY(IDOMMouseEvent *iface, LONG *p) { DOMEvent *This = impl_from_IDOMMouseEvent(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + nsresult nsres; + LONG r; + + TRACE("(%p)->(%p)\n", This, p); + + nsres = nsIDOMMouseEvent_GetLayerY(This->mouse_event, &r); + if(NS_FAILED(nsres)) + return E_FAIL; + + *p = r; + return S_OK; } static HRESULT WINAPI DOMMouseEvent_get_which(IDOMMouseEvent *iface, USHORT *p) From f273beab420806391e17e0e0ebf4afc3ae9903bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Feb 2022 11:21:39 +0100 Subject: [PATCH 41/83] winegstreamer: Reset internal format on BEGIN_STREAMING message. In order to regenerate a MF_E_TRANSFORM_STREAM_CHANGE status on next successful ProcessOutput. CoD: Black Ops 3 depends on this, or crashes if MF_E_TRANSFORM_STREAM_CHANGE isn't returned when the campaign intro video begins to play. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 CW-Bug-Id: #16839 CW-Bug-Id: #18678 CW-Bug-Id: #19362 --- dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index daa1a738c38..f6a4d47188f 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -520,7 +520,19 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) { + struct h264_decoder *decoder = impl_from_IMFTransform(iface); + FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); + + switch (message) + { + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + memset(&decoder->wg_format, 0, sizeof(decoder->wg_format)); + break; + default: + break; + } + return S_OK; } From 6bc8c9b213a221c685edb028605bb2be9dbded34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 8 Feb 2022 17:27:13 +0100 Subject: [PATCH 42/83] server: Seal shared memory mappings against future writes. So that even if we leak console handles, we will, at least, stop messing with these once and for all. This only prevents write(2) and mmap(2), as we've already mmaped the writable pages we don't need it anymore. This fixes Dead Cells hanging on launch, as it writes its DXVK logs to one of the thread input shared memory handles, causing GetFocus to loop forever as the sequence number got overwritten. CW-Bug-Id: #20128 --- configure.ac | 1 + server/mapping.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/configure.ac b/configure.ac index bc4f47d9889..22229880023 100644 --- a/configure.ac +++ b/configure.ac @@ -1994,6 +1994,7 @@ AC_CHECK_FUNCS(\ getrandom \ kqueue \ mach_continuous_time \ + memfd_create \ pipe2 \ port_create \ posix_fadvise \ diff --git a/server/mapping.c b/server/mapping.c index ecbfbee7ea1..4514a877177 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -268,6 +268,7 @@ int grow_file( int unix_fd, file_pos_t new_size ) return 0; } +#ifndef HAVE_MEMFD_CREATE /* simplified version of mkstemps() */ static int make_temp_file( char name[16] ) { @@ -301,10 +302,23 @@ static int check_current_dir_for_exec(void) unlink( tmpfn ); return (ret != MAP_FAILED); } +#endif /* create a temp file for anonymous mappings */ static int create_temp_file( file_pos_t size ) { +#ifdef HAVE_MEMFD_CREATE + int fd = memfd_create( "wine-mapping", MFD_ALLOW_SEALING ); + if (fd != -1) + { + if (!grow_file( fd, size )) + { + close( fd ); + fd = -1; + } + } + else file_set_error(); +#else static int temp_dir_fd = -1; char tmpfn[16]; int fd; @@ -337,6 +351,7 @@ static int create_temp_file( file_pos_t size ) else file_set_error(); if (temp_dir_fd != server_dir_fd) fchdir( server_dir_fd ); +#endif return fd; } @@ -1103,6 +1118,10 @@ int get_page_size(void) return page_mask + 1; } +#ifndef F_SEAL_FUTURE_WRITE +#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ +#endif + struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) { @@ -1112,6 +1131,7 @@ struct object *create_user_data_mapping( struct object *root, const struct unico if (!(mapping = create_mapping( root, name, attr, sizeof(KSHARED_USER_DATA), SEC_COMMIT, 0, FILE_READ_DATA | FILE_WRITE_DATA, sd ))) return NULL; ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 ); + if (ptr != MAP_FAILED) { user_shared_data = ptr; @@ -1123,11 +1143,15 @@ struct object *create_user_data_mapping( struct object *root, const struct unico struct object *create_shared_mapping( struct object *root, const struct unicode_str *name, mem_size_t size, const struct security_descriptor *sd, void **ptr ) { + static int seals = F_SEAL_FUTURE_WRITE | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL; struct mapping *mapping; if (!(mapping = create_mapping( root, name, OBJ_OPENIF, size, SEC_COMMIT, 0, FILE_READ_DATA | FILE_WRITE_DATA, sd ))) return NULL; *ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 ); + + fcntl( get_unix_fd( mapping->fd ), F_ADD_SEALS, seals ); + if (*ptr == MAP_FAILED) { release_object( &mapping->obj ); From a5ad4a520124e9d8ffe52df0e8163294d1c7308c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 9 Feb 2022 15:13:52 +0100 Subject: [PATCH 43/83] mfreadwrite: Introduce an internal source reader refcount. To decide when to shutdown the media source. Otherwise the references hold by the callbacks from BeginGetEvent and others are keeping the source reader alive and the IMFMediaSource_Shutdown is never called. CW-Bug-Id: #20069 --- dlls/mfreadwrite/reader.c | 41 ++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 0cc3b3c9c54..9c1c6a7d26d 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -153,6 +153,7 @@ struct source_reader IMFAsyncCallback source_events_callback; IMFAsyncCallback stream_events_callback; IMFAsyncCallback async_commands_callback; + LONG internal_refcount; LONG refcount; IMFMediaSource *source; IMFPresentationDescriptor *descriptor; @@ -203,6 +204,9 @@ static struct media_stream *impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVi return CONTAINING_RECORD(iface, struct media_stream, notify_cb); } +static ULONG WINAPI src_reader_internal_addref(struct source_reader *reader); +static ULONG WINAPI src_reader_internal_release(struct source_reader *reader); + static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { if (IsEqualIID(riid, &IID_IUnknown)) @@ -325,13 +329,13 @@ static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *if static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return src_reader_internal_addref(reader); } static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return src_reader_internal_release(reader); } static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface, @@ -611,13 +615,13 @@ static const IMFAsyncCallbackVtbl source_events_callback_vtbl = static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return src_reader_internal_addref(reader); } static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return src_reader_internal_release(reader); } static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream) @@ -888,13 +892,13 @@ static const IMFAsyncCallbackVtbl stream_events_callback_vtbl = static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFSourceReader_AddRef(&reader->IMFSourceReader_iface); + return src_reader_internal_addref(reader); } static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return IMFSourceReader_Release(&reader->IMFSourceReader_iface); + return src_reader_internal_release(reader); } static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response) @@ -1337,16 +1341,34 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); ULONG refcount = InterlockedDecrement(&reader->refcount); - unsigned int i; TRACE("%p, refcount %u.\n", iface, refcount); if (!refcount) { - if (reader->async_callback) - IMFSourceReaderCallback_Release(reader->async_callback); if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); + src_reader_internal_release(reader); + } + + return refcount; +} + +static ULONG WINAPI src_reader_internal_addref(struct source_reader *reader) +{ + ULONG refcount = InterlockedIncrement(&reader->internal_refcount); + return refcount; +} + +static ULONG WINAPI src_reader_internal_release(struct source_reader *reader) +{ + ULONG refcount = InterlockedDecrement(&reader->internal_refcount); + unsigned int i; + + if (!refcount) + { + if (reader->async_callback) + IMFSourceReaderCallback_Release(reader->async_callback); if (reader->descriptor) IMFPresentationDescriptor_Release(reader->descriptor); if (reader->attributes) @@ -2277,6 +2299,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri object->source_events_callback.lpVtbl = &source_events_callback_vtbl; object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl; object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl; + object->internal_refcount = 1; object->refcount = 1; list_init(&object->responses); if (shutdown_on_release) From 6c21f02f218fef833272d9df0d33c5fb11b98bb4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Thu, 10 Feb 2022 16:17:41 +0300 Subject: [PATCH 44/83] ntdll: Guard against syscall stack overrun. --- dlls/ntdll/unix/signal_arm.c | 4 ++++ dlls/ntdll/unix/signal_arm64.c | 4 ++++ dlls/ntdll/unix/signal_i386.c | 4 ++++ dlls/ntdll/unix/signal_x86_64.c | 4 ++++ dlls/ntdll/unix/unix_private.h | 10 +++++++++- dlls/ntdll/unix/virtual.c | 5 +++++ 6 files changed, 30 insertions(+), 1 deletion(-) diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index eaa41d9e139..ff4dbedccac 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -835,6 +835,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) (DWORD)IP_sig(context), (DWORD)SP_sig(context), (DWORD)LR_sig(context), (DWORD)PC_sig(context), (DWORD)CPSR_sig(context) ); + if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 26910173b81..ba3e3564c1a 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -860,6 +860,10 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec ) (DWORD64)REGn_sig(28, context), (DWORD64)FP_sig(context), (DWORD64)LR_sig(context), (DWORD64)SP_sig(context) ); + if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 53da5d3ac59..a0afd33ea13 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1757,6 +1757,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, void *stack_ptr, context->Ebp, context->Esp, context->SegCs, context->SegDs, context->SegEs, context->SegFs, context->SegGs, context->EFlags ); + if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 7d7f9090986..b1cc682649b 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2792,6 +2792,10 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, TRACE_(seh)( " r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n", context->R12, context->R13, context->R14, context->R15 ); + if (rec->ExceptionCode == STATUS_ACCESS_VIOLATION + && is_inside_syscall_stack_guard( (char *)rec->ExceptionInformation[1] )) + ERR_(seh)( "Syscall stack overrun.\n "); + if (ntdll_get_thread_data()->jmp_buf) { TRACE_(seh)( "returning to handler\n" ); diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 5f072956087..d1840de8876 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -88,7 +88,8 @@ static const SIZE_T teb_size = 0x3800; /* TEB64 + TEB32 + debug info */ static const SIZE_T signal_stack_mask = 0xffff; static const SIZE_T signal_stack_size = 0x10000 - 0x3800; static const SIZE_T kernel_stack_size = 0x60000; -static const SIZE_T min_kernel_stack = 0x2000; +static const SIZE_T kernel_stack_guard_size = 0x1000; +static const SIZE_T min_kernel_stack = 0x3000; static const LONG teb_offset = 0x2000; #define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1) @@ -330,6 +331,13 @@ static inline BOOL is_inside_signal_stack( void *ptr ) (char *)ptr < (char *)get_signal_stack() + signal_stack_size); } +static inline BOOL is_inside_syscall_stack_guard( const char *stack_ptr ) +{ + const char *kernel_stack = ntdll_get_thread_data()->kernel_stack; + + return (stack_ptr >= kernel_stack && stack_ptr < kernel_stack + kernel_stack_guard_size); +} + static inline void mutex_lock( pthread_mutex_t *mutex ) { if (!process_exiting) pthread_mutex_lock( mutex ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index e7caf162ee1..10e2bf1477c 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -3225,6 +3225,7 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI SIZE_T commit_size, SIZE_T extra_size ) { struct file_view *view; + char *kernel_stack; NTSTATUS status; sigset_t sigset; SIZE_T size; @@ -3268,6 +3269,10 @@ NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, ULONG_PTR zero_bits, SI delete_view( view ); goto done; } + /* setup kernel stack no access guard page */ + kernel_stack = (char *)view->base + view->size; + set_page_vprot( kernel_stack, kernel_stack_guard_size, VPROT_COMMITTED ); + mprotect_range( kernel_stack, kernel_stack_guard_size, 0, 0 ); } /* note: limit is lower than base since the stack grows down */ From aec9c019919f6d9bbc0c292dd6ccf7359afb3227 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 8 Feb 2022 23:20:35 +0300 Subject: [PATCH 45/83] fixup! ntdll: Implement CPU topology override. CW-Bug-Id: #20108 Also mind overridden topology for converting host affinity and allow setting the affinity on thread creation. --- server/process.c | 23 +++++++++++++++++++++++ server/process.h | 1 + server/thread.c | 21 ++++++++++++++++----- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/server/process.c b/server/process.c index 8203eead9d4..1f9ec4eb619 100644 --- a/server/process.c +++ b/server/process.c @@ -1462,6 +1462,24 @@ DECL_HANDLER(init_process_done) const pe_image_info_t *image_info; const struct cpu_topology_override *cpu_override = get_req_data(); unsigned int have_cpu_override = get_req_data_size() / sizeof(*cpu_override); + unsigned int i; + + if (have_cpu_override) + { + if (cpu_override->cpu_count > ARRAY_SIZE(process->wine_cpu_id_from_host)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + for (i = 0; i < cpu_override->cpu_count; ++i) + { + if (cpu_override->host_cpu_id[i] >= ARRAY_SIZE(process->wine_cpu_id_from_host)) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + } + } if (is_process_init_done(process)) { @@ -1493,7 +1511,12 @@ DECL_HANDLER(init_process_done) reply->suspend = (current->suspend || process->suspend); if (have_cpu_override) + { process->cpu_override = *cpu_override; + memset( process->wine_cpu_id_from_host, 0, sizeof(process->wine_cpu_id_from_host) ); + for (i = 0; i < process->cpu_override.cpu_count; ++i) + process->wine_cpu_id_from_host[process->cpu_override.host_cpu_id[i]] = i; + } } /* open a handle to a process */ diff --git a/server/process.h b/server/process.h index 404bbb12550..60a80be1fc1 100644 --- a/server/process.h +++ b/server/process.h @@ -94,6 +94,7 @@ struct process int esync_fd; /* esync file descriptor (signaled on exit) */ unsigned int fsync_idx; struct cpu_topology_override cpu_override; /* Overridden CPUs to host CPUs mapping. */ + unsigned char wine_cpu_id_from_host[64]; /* Host to overridden CPU mapping. */ }; /* process functions */ diff --git a/server/thread.c b/server/thread.c index 4c51567c286..5163d540531 100644 --- a/server/thread.c +++ b/server/thread.c @@ -758,8 +758,21 @@ affinity_t get_thread_affinity( struct thread *thread ) unsigned int i; if (!sched_getaffinity( thread->unix_tid, sizeof(set), &set )) + { for (i = 0; i < 8 * sizeof(mask); i++) - if (CPU_ISSET( i, &set )) mask |= (affinity_t)1 << i; + if (CPU_ISSET( i, &set )) + { + if (thread->process->cpu_override.cpu_count) + { + if (i < ARRAY_SIZE(thread->process->wine_cpu_id_from_host)) + mask |= (affinity_t)1 << thread->process->wine_cpu_id_from_host[i]; + } + else + { + mask |= (affinity_t)1 << i; + } + } + } } #endif if (!mask) mask = ~(affinity_t)0; @@ -1672,8 +1685,7 @@ DECL_HANDLER(init_first_thread) else { set_thread_priority( current, current->process->priority, current->priority ); - if (!process->cpu_override.cpu_count) - set_thread_affinity( current, current->affinity ); + set_thread_affinity( current, current->affinity ); } debug_level = max( debug_level, req->debug_level ); @@ -1706,8 +1718,7 @@ DECL_HANDLER(init_thread) init_thread_context( current ); generate_debug_event( current, DbgCreateThreadStateChange, &req->entry ); set_thread_priority( current, current->process->priority, current->priority ); - if (!current->process->cpu_override.cpu_count) - set_thread_affinity( current, current->affinity ); + set_thread_affinity( current, current->affinity ); reply->suspend = (current->suspend || current->process->suspend || current->context != NULL); } From c7d9891b5abc904a9dafaa6900b9208ae7ac3081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 11 Feb 2022 12:27:11 +0100 Subject: [PATCH 46/83] mf: Handle MESourceSeeked and MEStreamSeeked state change events. If a session is paused then started again, or if a start position is provided we wait forever for the source to send a MESourceStarted event, when it sends a MESourceSeeked instead. CW-Bug-Id: #19957 --- dlls/mf/session.c | 8 ++++++++ dlls/mfplat/tests/mfplat.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/dlls/mf/session.c b/dlls/mf/session.c index 883b765c348..f2fe2a83ff6 100644 --- a/dlls/mf/session.c +++ b/dlls/mf/session.c @@ -2323,6 +2323,8 @@ static enum object_state session_get_object_state_for_event(MediaEventType event { switch (event) { + case MESourceSeeked: + case MEStreamSeeked: case MESourceStarted: case MEStreamStarted: case MEStreamSinkStarted: @@ -2499,6 +2501,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn switch (event_type) { + case MESourceSeeked: case MESourceStarted: case MESourcePaused: case MESourceStopped: @@ -2513,6 +2516,7 @@ static void session_set_source_object_state(struct media_session *session, IUnkn } } break; + case MEStreamSeeked: case MEStreamStarted: case MEStreamPaused: case MEStreamStopped: @@ -3199,6 +3203,10 @@ static HRESULT WINAPI session_events_callback_Invoke(IMFAsyncCallback *iface, IM switch (event_type) { + case MESourceSeeked: + case MEStreamSeeked: + FIXME("Source/stream seeking, semi-stub!\n"); + /* fallthrough */ case MESourceStarted: case MESourcePaused: case MESourceStopped: diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 207bd61b8dc..1b1c8e90da6 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -942,6 +942,44 @@ todo_wine video_stream = (IMFMediaStream *)var.punkVal; } + hr = IMFMediaSource_Pause(mediasource); + ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr); + if (get_event((IMFMediaEventGenerator *)mediasource, MESourcePaused, &var)) + ok(var.vt == VT_EMPTY, "Unexpected value type.\n"); + + var.vt = VT_EMPTY; + hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var); + ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr); + + if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStarted, &var)) + ok(var.vt == VT_EMPTY, "Unexpected value type.\n"); + + hr = IMFMediaSource_Pause(mediasource); + ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr); + if (get_event((IMFMediaEventGenerator *)mediasource, MESourcePaused, &var)) + ok(var.vt == VT_EMPTY, "Unexpected value type.\n"); + + var.vt = VT_I8; + var.uhVal.QuadPart = 0; + hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var); + ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr); + + if (get_event((IMFMediaEventGenerator *)mediasource, MESourceSeeked, &var)) + ok(var.vt == VT_I8, "Unexpected value type.\n"); + + hr = IMFMediaSource_Stop(mediasource); + ok(hr == S_OK, "Failed to pause media source, hr %#x.\n", hr); + if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStopped, &var)) + ok(var.vt == VT_EMPTY, "Unexpected value type.\n"); + + var.vt = VT_I8; + var.uhVal.QuadPart = 0; + hr = IMFMediaSource_Start(mediasource, descriptor, &GUID_NULL, &var); + ok(hr == S_OK, "Failed to start media source, hr %#x.\n", hr); + + if (get_event((IMFMediaEventGenerator *)mediasource, MESourceStarted, &var)) + ok(var.vt == VT_I8, "Unexpected value type.\n"); + sample_count = 10; for (i = 0; i < sample_count; ++i) From b28ab9ac90448dfd1d3c1671ed184354c1ec7826 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 1 Feb 2022 18:59:07 +0300 Subject: [PATCH 47/83] evr/presenter: Initial implementation of GetCurrentImage(). Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard (cherry picked from commit 22fda5990ffc9b22258e914192d23fedf7d75dd7) CW-Bug-Id: #18995 --- dlls/evr/presenter.c | 94 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/dlls/evr/presenter.c b/dlls/evr/presenter.c index fd02404b7af..507217ffdda 100644 --- a/dlls/evr/presenter.c +++ b/dlls/evr/presenter.c @@ -65,6 +65,7 @@ struct sample_queue unsigned int used; unsigned int front; unsigned int back; + IMFSample *last_presented; }; struct streaming_thread @@ -120,6 +121,7 @@ struct video_presenter struct { int presented; + LONGLONG sampletime; } frame_stats; CRITICAL_SECTION cs; @@ -507,6 +509,13 @@ static void video_presenter_sample_present(struct video_presenter *presenter, IM IDirect3DSwapChain9_Present(presenter->swapchain, NULL, NULL, NULL, NULL, 0); presenter->frame_stats.presented++; + EnterCriticalSection(&presenter->cs); + if (presenter->thread.queue.last_presented) + IMFSample_Release(presenter->thread.queue.last_presented); + presenter->thread.queue.last_presented = sample; + IMFSample_AddRef(presenter->thread.queue.last_presented); + LeaveCriticalSection(&presenter->cs); + IDirect3DDevice9_Release(device); IDirect3DSurface9_Release(backbuffer); IDirect3DSurface9_Release(surface); @@ -739,6 +748,8 @@ static HRESULT video_presenter_end_streaming(struct video_presenter *presenter) TRACE("Terminated streaming thread tid %#x.\n", presenter->thread.tid); + if (presenter->thread.queue.last_presented) + IMFSample_Release(presenter->thread.queue.last_presented); memset(&presenter->thread, 0, sizeof(presenter->thread)); video_presenter_set_allocator_callback(presenter, NULL); @@ -1461,9 +1472,88 @@ static HRESULT WINAPI video_presenter_control_RepaintVideo(IMFVideoDisplayContro static HRESULT WINAPI video_presenter_control_GetCurrentImage(IMFVideoDisplayControl *iface, BITMAPINFOHEADER *header, BYTE **dib, DWORD *dib_size, LONGLONG *timestamp) { - FIXME("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp); + struct video_presenter *presenter = impl_from_IMFVideoDisplayControl(iface); + IDirect3DSurface9 *readback = NULL, *surface; + D3DSURFACE_DESC surface_desc; + D3DLOCKED_RECT mapped_rect; + IDirect3DDevice9 *device; + IMFSample *sample; + LONG stride; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %p, %p, %p, %p.\n", iface, header, dib, dib_size, timestamp); + + EnterCriticalSection(&presenter->cs); + + sample = presenter->thread.queue.last_presented; + presenter->thread.queue.last_presented = NULL; + + if (!presenter->swapchain || !sample) + { + hr = MF_E_INVALIDREQUEST; + } + else if (SUCCEEDED(hr = video_presenter_get_sample_surface(sample, &surface))) + { + IDirect3DSwapChain9_GetDevice(presenter->swapchain, &device); + IDirect3DSurface9_GetDesc(surface, &surface_desc); + + if (surface_desc.Format != D3DFMT_X8R8G8B8) + { + FIXME("Unexpected surface format %d.\n", surface_desc.Format); + hr = E_FAIL; + } + + if (SUCCEEDED(hr)) + { + if (FAILED(hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, surface_desc.Width, + surface_desc.Height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &readback, NULL))) + { + WARN("Failed to create readback surface, hr %#x.\n", hr); + } + } + + if (SUCCEEDED(hr)) + hr = IDirect3DDevice9_GetRenderTargetData(device, surface, readback); + + if (SUCCEEDED(hr)) + { + MFGetStrideForBitmapInfoHeader(D3DFMT_X8R8G8B8, surface_desc.Width, &stride); + *dib_size = abs(stride) * surface_desc.Height; + if (!(*dib = CoTaskMemAlloc(*dib_size))) + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(readback, &mapped_rect, NULL, D3DLOCK_READONLY))) + { + memcpy(*dib, mapped_rect.pBits, *dib_size); + IDirect3DSurface9_UnlockRect(readback); + } + } + + memset(header, 0, sizeof(*header)); + header->biSize = sizeof(*header); + header->biWidth = surface_desc.Width; + header->biHeight = surface_desc.Height; + header->biPlanes = 1; + header->biBitCount = 32; + header->biSizeImage = *dib_size; + IMFSample_GetSampleTime(sample, timestamp); + + if (readback) + IDirect3DSurface9_Release(readback); + IDirect3DSurface9_Release(surface); + + IDirect3DDevice9_Release(device); + } + + if (sample) + IMFSample_Release(sample); + + LeaveCriticalSection(&presenter->cs); + + return hr; } static HRESULT WINAPI video_presenter_control_SetBorderColor(IMFVideoDisplayControl *iface, COLORREF color) From 4682d666fedd9ffb1d2e747cc5a745808b1247ee Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Thu, 3 Feb 2022 09:51:28 +0100 Subject: [PATCH 48/83] HACK: winex11.drv/opengl: Do not trigger a libX11 bug. Sometimes The Last Campfire passes invalid parameters to wglCreateContextAttribsARB, which on the Deck can trigger a libX11 bug and crash Wine. When we see the invalid value we return an error directly, without calling glXCreateContextAttribsARB. This hack can be removed once https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/152 is fixed. CW-Bug-Id: #20026 --- dlls/winex11.drv/opengl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index cc419c78e14..a3377a659c3 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -3287,6 +3287,21 @@ static struct wgl_context *X11DRV_wglCreateContextAttribsARB( HDC hdc, struct wg case WGL_CONTEXT_LAYER_PLANE_ARB: break; case WGL_CONTEXT_FLAGS_ARB: + /* HACK: The Last Campfire sometimes uses an + * invalid value for WGL_CONTEXT_FLAGS_ARB, which + * triggers + * https://gitlab.freedesktop.org/xorg/lib/libx11/-/issues/152 + * on the Deck. If we see the invalid value we + * directly return an error, so that Wine doesn't + * crash. This hack can be removed once that issue + * is fixed. */ + if (attribList[1] == 0x31b3) + { + WARN("return early to avoid triggering a libX11 bug\n"); + HeapFree(GetProcessHeap(), 0, ret); + release_gl_drawable(gl); + return NULL; + } pContextAttribList[0] = GLX_CONTEXT_FLAGS_ARB; pContextAttribList[1] = attribList[1]; pContextAttribList += 2; From 465de7eb498a8bb176eded5eb47ce1d2897b1fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 14 Feb 2022 17:28:39 +0100 Subject: [PATCH 49/83] fixup! winebus.sys: Only call SDL_HapticRumbleInit if supported, as a fallback. --- dlls/winebus.sys/bus_sdl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 26191ccb3a5..c5b45920d2e 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -187,12 +187,13 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick))) impl->effect_support = 0; else + { impl->effect_support = pSDL_HapticQuery(impl->sdl_haptic); - - if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) && - pSDL_HapticRumbleSupported(impl->sdl_haptic) && - pSDL_HapticRumbleInit(impl->sdl_haptic) == 0) - impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE; + if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) && + pSDL_HapticRumbleSupported(impl->sdl_haptic) && + pSDL_HapticRumbleInit(impl->sdl_haptic) == 0) + impl->effect_support |= WINE_SDL_HAPTIC_RUMBLE; + } if (!(impl->effect_support & EFFECT_SUPPORT_HAPTICS) && pSDL_JoystickRumble && !pSDL_JoystickRumble(impl->sdl_joystick, 0, 0, 0)) From a5216de67be482394f68cd0244418fc093f07950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 11 Feb 2022 09:51:20 +0300 Subject: [PATCH 50/83] amend! mfreadwrite/reader: Use separate refcount for events callbacks. mfreadwrite/reader: Use separate refcount for events callbacks. This resolves circular dependency, with source and streams holding references to the callbacks, subscribed to their event queues. CW-Bug-Id: #20069 Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard (cherry picked from commit be85638b5b38f9f07ccd23024485d4f90c57e5de) --- dlls/mfreadwrite/reader.c | 112 ++++++++++++++++---------------- dlls/mfreadwrite/tests/mfplat.c | 3 +- 2 files changed, 57 insertions(+), 58 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 9c1c6a7d26d..4f224480857 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -153,8 +153,8 @@ struct source_reader IMFAsyncCallback source_events_callback; IMFAsyncCallback stream_events_callback; IMFAsyncCallback async_commands_callback; - LONG internal_refcount; LONG refcount; + LONG public_refcount; IMFMediaSource *source; IMFPresentationDescriptor *descriptor; IMFSourceReaderCallback *async_callback; @@ -204,8 +204,50 @@ static struct media_stream *impl_stream_from_IMFVideoSampleAllocatorNotify(IMFVi return CONTAINING_RECORD(iface, struct media_stream, notify_cb); } -static ULONG WINAPI src_reader_internal_addref(struct source_reader *reader); -static ULONG WINAPI src_reader_internal_release(struct source_reader *reader); +static void source_reader_release_responses(struct source_reader *reader, struct media_stream *stream); + +static ULONG source_reader_addref(struct source_reader *reader) +{ + return InterlockedIncrement(&reader->refcount); +} + +static ULONG source_reader_release(struct source_reader *reader) +{ + ULONG refcount = InterlockedDecrement(&reader->refcount); + unsigned int i; + + if (!refcount) + { + if (reader->async_callback) + IMFSourceReaderCallback_Release(reader->async_callback); + if (reader->descriptor) + IMFPresentationDescriptor_Release(reader->descriptor); + if (reader->attributes) + IMFAttributes_Release(reader->attributes); + IMFMediaSource_Release(reader->source); + + for (i = 0; i < reader->stream_count; ++i) + { + struct media_stream *stream = &reader->streams[i]; + + if (stream->stream) + IMFMediaStream_Release(stream->stream); + if (stream->current) + IMFMediaType_Release(stream->current); + if (stream->decoder.transform) + IMFTransform_Release(stream->decoder.transform); + if (stream->allocator) + IMFVideoSampleAllocatorEx_Release(stream->allocator); + } + source_reader_release_responses(reader, NULL); + free(reader->streams); + MFUnlockWorkQueue(reader->queue); + DeleteCriticalSection(&reader->cs); + free(reader); + } + + return refcount; +} static HRESULT WINAPI source_reader_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj) { @@ -329,13 +371,13 @@ static HRESULT WINAPI source_reader_callback_QueryInterface(IMFAsyncCallback *if static ULONG WINAPI source_reader_source_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return src_reader_internal_addref(reader); + return source_reader_addref(reader); } static ULONG WINAPI source_reader_source_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_source_callback_IMFAsyncCallback(iface); - return src_reader_internal_release(reader); + return source_reader_release(reader); } static HRESULT WINAPI source_reader_callback_GetParameters(IMFAsyncCallback *iface, @@ -615,13 +657,13 @@ static const IMFAsyncCallbackVtbl source_events_callback_vtbl = static ULONG WINAPI source_reader_stream_events_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return src_reader_internal_addref(reader); + return source_reader_addref(reader); } static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_stream_callback_IMFAsyncCallback(iface); - return src_reader_internal_release(reader); + return source_reader_release(reader); } static HRESULT source_reader_pull_stream_samples(struct source_reader *reader, struct media_stream *stream) @@ -892,13 +934,13 @@ static const IMFAsyncCallbackVtbl stream_events_callback_vtbl = static ULONG WINAPI source_reader_async_commands_callback_AddRef(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return src_reader_internal_addref(reader); + return source_reader_addref(reader); } static ULONG WINAPI source_reader_async_commands_callback_Release(IMFAsyncCallback *iface) { struct source_reader *reader = impl_from_async_commands_callback_IMFAsyncCallback(iface); - return src_reader_internal_release(reader); + return source_reader_release(reader); } static struct stream_response * media_stream_detach_response(struct source_reader *reader, struct stream_response *response) @@ -1330,7 +1372,7 @@ static HRESULT WINAPI src_reader_QueryInterface(IMFSourceReader *iface, REFIID r static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); - ULONG refcount = InterlockedIncrement(&reader->refcount); + ULONG refcount = InterlockedIncrement(&reader->public_refcount); TRACE("%p, refcount %u.\n", iface, refcount); @@ -1340,7 +1382,7 @@ static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); - ULONG refcount = InterlockedDecrement(&reader->refcount); + ULONG refcount = InterlockedDecrement(&reader->public_refcount); TRACE("%p, refcount %u.\n", iface, refcount); @@ -1348,51 +1390,7 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); - src_reader_internal_release(reader); - } - - return refcount; -} - -static ULONG WINAPI src_reader_internal_addref(struct source_reader *reader) -{ - ULONG refcount = InterlockedIncrement(&reader->internal_refcount); - return refcount; -} - -static ULONG WINAPI src_reader_internal_release(struct source_reader *reader) -{ - ULONG refcount = InterlockedDecrement(&reader->internal_refcount); - unsigned int i; - - if (!refcount) - { - if (reader->async_callback) - IMFSourceReaderCallback_Release(reader->async_callback); - if (reader->descriptor) - IMFPresentationDescriptor_Release(reader->descriptor); - if (reader->attributes) - IMFAttributes_Release(reader->attributes); - IMFMediaSource_Release(reader->source); - - for (i = 0; i < reader->stream_count; ++i) - { - struct media_stream *stream = &reader->streams[i]; - - if (stream->stream) - IMFMediaStream_Release(stream->stream); - if (stream->current) - IMFMediaType_Release(stream->current); - if (stream->decoder.transform) - IMFTransform_Release(stream->decoder.transform); - if (stream->allocator) - IMFVideoSampleAllocatorEx_Release(stream->allocator); - } - source_reader_release_responses(reader, NULL); - free(reader->streams); - MFUnlockWorkQueue(reader->queue); - DeleteCriticalSection(&reader->cs); - free(reader); + source_reader_release(reader); } return refcount; @@ -2299,7 +2297,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri object->source_events_callback.lpVtbl = &source_events_callback_vtbl; object->stream_events_callback.lpVtbl = &stream_events_callback_vtbl; object->async_commands_callback.lpVtbl = &async_commands_callback_vtbl; - object->internal_refcount = 1; + object->public_refcount = 1; object->refcount = 1; list_init(&object->responses); if (shutdown_on_release) diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index e3ff7f6e7aa..aec7d7456ca 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -865,7 +865,8 @@ todo_wine hr = IMFSourceReader_Flush(reader, MF_SOURCE_READER_ALL_STREAMS); ok(hr == S_OK, "Failed to flush all streams, hr %#x.\n", hr); - IMFSourceReader_Release(reader); + refcount = IMFSourceReader_Release(reader); + ok(!refcount, "Unexpected refcount %u.\n", refcount); /* Async mode. */ callback = create_async_callback(); From 7a3fb110d030d1de4d91a50ce31758c672595b6b Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 11 Feb 2022 09:51:21 +0300 Subject: [PATCH 51/83] mfreadwrite/reader: Stop media source when shutdown is not allowed. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard (cherry picked from commit a5770a0402c44586aa2913a7f2e411795f51e567) --- dlls/mfreadwrite/reader.c | 45 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 4f224480857..de6784ecac1 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -72,6 +72,7 @@ enum media_stream_flags STREAM_FLAG_SAMPLE_REQUESTED = 0x1, /* Protects from making multiple sample requests. */ STREAM_FLAG_SELECTED = 0x2, /* Mirrors descriptor, used to simplify tests when starting the source. */ STREAM_FLAG_PRESENTED = 0x4, /* Set if stream was selected last time Start() was called. */ + STREAM_FLAG_STOPPED = 0x8, /* Received MEStreamStopped */ }; struct stream_transform @@ -172,6 +173,7 @@ struct source_reader CRITICAL_SECTION cs; CONDITION_VARIABLE sample_event; CONDITION_VARIABLE state_event; + CONDITION_VARIABLE stop_event; }; static inline struct source_reader *impl_from_IMFSourceReader(IMFSourceReader *iface) @@ -585,6 +587,8 @@ static HRESULT source_reader_source_state_handler(struct source_reader *reader, LeaveCriticalSection(&reader->cs); WakeAllConditionVariable(&reader->state_event); + if (event_type == MESourceStopped) + WakeAllConditionVariable(&reader->stop_event); return S_OK; } @@ -640,7 +644,8 @@ static HRESULT WINAPI source_reader_source_events_callback_Invoke(IMFAsyncCallba IMFMediaEvent_Release(event); - IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source); + if (event_type != MESourceStopped) + IMFMediaSource_BeginGetEvent(source, iface, (IUnknown *)source); return S_OK; } @@ -856,6 +861,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re case MEStreamStarted: stream->state = STREAM_STATE_READY; break; + case MEStreamStopped: + stream->flags |= STREAM_FLAG_STOPPED; + break; case MEStreamTick: value.vt = VT_EMPTY; hr = SUCCEEDED(IMFMediaEvent_GetValue(event, &value)) && value.vt == VT_I8 ? S_OK : E_UNEXPECTED; @@ -875,6 +883,9 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re LeaveCriticalSection(&reader->cs); + if (event_type == MEStreamStopped) + WakeAllConditionVariable(&reader->stop_event); + return S_OK; } @@ -904,6 +915,7 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba break; case MEStreamSeeked: case MEStreamStarted: + case MEStreamStopped: case MEStreamTick: case MEEndOfStream: hr = source_reader_media_stream_state_handler(reader, stream, event); @@ -917,7 +929,8 @@ static HRESULT WINAPI source_reader_stream_events_callback_Invoke(IMFAsyncCallba IMFMediaEvent_Release(event); - IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream); + if (event_type != MEStreamStopped) + IMFMediaStream_BeginGetEvent(stream, iface, (IUnknown *)stream); return S_OK; } @@ -1379,6 +1392,22 @@ static ULONG WINAPI src_reader_AddRef(IMFSourceReader *iface) return refcount; } +static BOOL source_reader_is_source_stopped(const struct source_reader *reader) +{ + unsigned int i; + + if (reader->source_state != SOURCE_STATE_STOPPED) + return FALSE; + + for (i = 0; i < reader->stream_count; ++i) + { + if (reader->streams[i].stream && !(reader->streams[i].flags & STREAM_FLAG_STOPPED)) + return FALSE; + } + + return TRUE; +} + static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { struct source_reader *reader = impl_from_IMFSourceReader(iface); @@ -1390,6 +1419,17 @@ static ULONG WINAPI src_reader_Release(IMFSourceReader *iface) { if (reader->flags & SOURCE_READER_SHUTDOWN_ON_RELEASE) IMFMediaSource_Shutdown(reader->source); + else if (SUCCEEDED(IMFMediaSource_Stop(reader->source))) + { + EnterCriticalSection(&reader->cs); + + while (!source_reader_is_source_stopped(reader)) + { + SleepConditionVariableCS(&reader->stop_event, &reader->cs, INFINITE); + } + + LeaveCriticalSection(&reader->cs); + } source_reader_release(reader); } @@ -2307,6 +2347,7 @@ static HRESULT create_source_reader_from_source(IMFMediaSource *source, IMFAttri InitializeCriticalSection(&object->cs); InitializeConditionVariable(&object->sample_event); InitializeConditionVariable(&object->state_event); + InitializeConditionVariable(&object->stop_event); if (FAILED(hr = IMFMediaSource_CreatePresentationDescriptor(object->source, &object->descriptor))) goto failed; From 58eccf42083c063483f8c072f53a44fb2e193d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 14 Feb 2022 18:15:34 +0100 Subject: [PATCH 52/83] winebus.sys: Flag the Deck touchsceen, mouse and keyboard as Steam controllers. So that we ignore them from the hidraw backend. SDL is already ignoring them as they aren't gamepads or joysticks, but we don't know until we request their report descriptors, which we cannot easily do yet. --- dlls/winebus.sys/unixlib.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c index c2f8e163067..b0043c0de7e 100644 --- a/dlls/winebus.sys/unixlib.c +++ b/dlls/winebus.sys/unixlib.c @@ -72,6 +72,7 @@ BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) BOOL is_steam_controller(WORD vid, WORD pid) { + if (vid == 0x2808 && pid == 0x1015) return TRUE; /* Steam Deck touchscreen */ if (vid != 0x28de) return FALSE; if (pid == 0x1101) return TRUE; /* Valve Legacy Steam Controller */ if (pid == 0x1102) return TRUE; /* Valve wired Steam Controller */ @@ -80,6 +81,7 @@ BOOL is_steam_controller(WORD vid, WORD pid) if (pid == 0x1142) return TRUE; /* Valve wireless Steam Controller */ if (pid == 0x1201) return TRUE; /* Valve wired Steam Controller */ if (pid == 0x1202) return TRUE; /* Valve Bluetooth Steam Controller */ + if (pid == 0x1205) return TRUE; /* Valve Steam Deck Mouse / Keyboard */ return FALSE; } From f072cf6366aa8385efdcb4a7b4c49e122f00b750 Mon Sep 17 00:00:00 2001 From: Derek Lesho Date: Mon, 14 Feb 2022 12:51:27 -0500 Subject: [PATCH 53/83] fsync: Type-check HANDLE in esync_set_event. Signed-off-by: Derek Lesho --- dlls/ntdll/unix/fsync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index 39d969f061d..d468782667a 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -576,6 +576,9 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) if ((ret = get_object( handle, &obj ))) return ret; event = obj->shm; + if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT) + return STATUS_OBJECT_TYPE_MISMATCH; + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) futex_wake( &event->signaled, INT_MAX ); From 6f2c9858d6bb957b807411b28f8ffd77199eafd4 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Feb 2022 22:40:40 +0300 Subject: [PATCH 54/83] fixup! esync, fsync: Yield execution before alertable wait for AC Odyssey. CW-Bug-Id: #18881 --- dlls/ntdll/unix/loader.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 1d4160727e4..301a11c0419 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2241,23 +2241,11 @@ BOOL ac_odyssey; static void hacks_init(void) { static const char ac_odyssey_exe[] = "ACOdyssey.exe"; - char cur_exe[MAX_PATH]; - DWORD cur_exe_len; const char *sgi; - int fd; - - fd = open("/proc/self/comm", O_RDONLY); - cur_exe_len = read(fd, cur_exe, sizeof(cur_exe)); - close(fd); - cur_exe[cur_exe_len - 1] = 0; - if (!strcasecmp(cur_exe, ac_odyssey_exe)) + if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) { - if (do_esync() || do_fsync()) - ERR("HACK: AC Odyssey sync tweak on.\n"); - else - ERR("Not enabling AC Odyssey sync tweak as esync and fsync are disabled.\n"); - + ERR("HACK: AC Odyssey sync tweak on.\n"); ac_odyssey = TRUE; return; } From 17bdb16bd974a6da171ee6dc099e34ad3b596d64 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Mon, 14 Feb 2022 13:15:55 +0300 Subject: [PATCH 55/83] make_requests --- include/wine/server_protocol.h | 381 ++++++++++++++++++++++++++++++++- server/request.h | 135 ++++++++++-- server/trace.c | 206 +++++++++++++++++- 3 files changed, 685 insertions(+), 37 deletions(-) diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 1d17a40530f..d67489de1f0 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -14,6 +14,7 @@ #include #include +#include typedef unsigned int obj_handle_t; typedef unsigned int user_handle_t; @@ -470,7 +471,8 @@ enum apc_type APC_MAP_VIEW, APC_UNMAP_VIEW, APC_CREATE_THREAD, - APC_DUP_HANDLE + APC_DUP_HANDLE, + APC_PROCESS_SET_INFO, }; typedef struct @@ -579,6 +581,11 @@ typedef union unsigned int attributes; unsigned int options; } dup_handle; + struct + { + enum apc_type type; + PROCESSINFOCLASS class; + } process_set_info; } apc_call_t; typedef union @@ -677,6 +684,11 @@ typedef union enum apc_type type; unsigned int status; } break_process; + struct + { + enum apc_type type; + unsigned int status; + } process_set_info; } apc_result_t; enum irp_type @@ -815,6 +827,76 @@ typedef struct lparam_t info; } cursor_pos_t; +struct cpu_topology_override +{ + unsigned int cpu_count; + unsigned char host_cpu_id[64]; +}; + +struct shared_cursor +{ + int x; + int y; + unsigned int last_change; + rectangle_t clip; +}; + +struct ws_watch_entry +{ + client_ptr_t va; + client_ptr_t pc; + thread_id_t tid; + int __pad; +}; + +struct ws_watch_data +{ + data_size_t len; + int __pad; + struct ws_watch_entry entries[1]; +}; + +struct desktop_shared_memory +{ + unsigned int seq; + struct shared_cursor cursor; + unsigned char keystate[256]; + thread_id_t foreground_tid; +}; + +struct queue_shared_memory +{ + unsigned int seq; + int created; + unsigned int wake_bits; + unsigned int changed_bits; + unsigned int wake_mask; + unsigned int changed_mask; + thread_id_t input_tid; +}; + +struct input_shared_memory +{ + unsigned int seq; + int created; + thread_id_t tid; + user_handle_t focus; + user_handle_t capture; + user_handle_t active; + user_handle_t menu_owner; + user_handle_t move_size; + user_handle_t caret; + user_handle_t cursor; + rectangle_t caret_rect; + int cursor_count; + unsigned char keystate[256]; + int keystate_lock; +}; + + +#define SEQUENCE_MASK_BITS 4 +#define SEQUENCE_MASK ((1UL << SEQUENCE_MASK_BITS) - 1) + @@ -907,11 +989,15 @@ struct init_process_done_request client_ptr_t teb; client_ptr_t peb; client_ptr_t ldt_copy; + client_ptr_t kernel_stack; + unsigned int kernel_stack_size; + char __pad_52[4]; }; struct init_process_done_reply { struct reply_header __header; client_ptr_t entry; + /* VARARG(cpu_override,cpu_topology_override); */ int suspend; char __pad_20[4]; }; @@ -926,6 +1012,8 @@ struct init_first_thread_request int debug_level; int reply_fd; int wait_fd; + char nice_limit; + char __pad_33[7]; }; struct init_first_thread_reply { @@ -948,6 +1036,9 @@ struct init_thread_request int wait_fd; client_ptr_t teb; client_ptr_t entry; + client_ptr_t kernel_stack; + unsigned int kernel_stack_size; + char __pad_52[4]; }; struct init_thread_reply { @@ -1748,14 +1839,16 @@ struct recv_socket_request struct request_header __header; int oob; async_data_t async; - unsigned int status; - unsigned int total; + int force_async; + char __pad_60[4]; }; struct recv_socket_reply { struct reply_header __header; obj_handle_t wait; unsigned int options; + int nonblocking; + char __pad_20[4]; }; @@ -2139,7 +2232,9 @@ struct read_process_memory_request struct read_process_memory_reply { struct reply_header __header; + int unix_pid; /* VARARG(data,bytes); */ + char __pad_12[4]; }; @@ -2686,10 +2781,10 @@ struct send_hardware_message_reply int prev_y; int new_x; int new_y; - /* VARARG(keystate,bytes); */ char __pad_28[4]; }; #define SEND_HWMSG_INJECTED 0x01 +#define SEND_HWMSG_RAWINPUT 0x02 @@ -2715,9 +2810,9 @@ struct get_message_reply int x; int y; unsigned int time; - unsigned int active_hooks; data_size_t total; /* VARARG(data,message_data); */ + char __pad_52[4]; }; @@ -2889,6 +2984,23 @@ struct get_async_result_reply +struct set_async_direct_result_request +{ + struct request_header __header; + obj_handle_t handle; + apc_param_t information; + unsigned int status; + char __pad_28[4]; +}; +struct set_async_direct_result_reply +{ + struct reply_header __header; + obj_handle_t handle; + char __pad_12[4]; +}; + + + struct read_request { struct request_header __header; @@ -3769,14 +3881,10 @@ struct get_thread_input_reply user_handle_t focus; user_handle_t capture; user_handle_t active; - user_handle_t foreground; user_handle_t menu_owner; user_handle_t move_size; user_handle_t caret; - user_handle_t cursor; - int show_count; rectangle_t rect; - char __pad_60[4]; }; @@ -3934,6 +4042,20 @@ enum caret_state +struct get_active_hooks_request +{ + struct request_header __header; + char __pad_12[4]; +}; +struct get_active_hooks_reply +{ + struct reply_header __header; + unsigned int active_hooks; + char __pad_12[4]; +}; + + + struct set_hook_request { struct request_header __header; @@ -4985,6 +5107,8 @@ struct remove_completion_request { struct request_header __header; obj_handle_t handle; + int waited; + char __pad_20[4]; }; struct remove_completion_reply { @@ -5388,7 +5512,6 @@ struct resume_process_reply }; - struct get_next_thread_request { struct request_header __header; @@ -5405,6 +5528,200 @@ struct get_next_thread_reply char __pad_12[4]; }; +enum esync_type +{ + ESYNC_SEMAPHORE = 1, + ESYNC_AUTO_EVENT, + ESYNC_MANUAL_EVENT, + ESYNC_MUTEX, + ESYNC_AUTO_SERVER, + ESYNC_MANUAL_SERVER, + ESYNC_QUEUE, +}; + + +struct create_esync_request +{ + struct request_header __header; + unsigned int access; + int initval; + int type; + int max; + /* VARARG(objattr,object_attributes); */ + char __pad_28[4]; +}; +struct create_esync_reply +{ + struct reply_header __header; + obj_handle_t handle; + int type; + unsigned int shm_idx; + char __pad_20[4]; +}; + +struct open_esync_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + int type; + /* VARARG(name,unicode_str); */ + char __pad_28[4]; +}; +struct open_esync_reply +{ + struct reply_header __header; + obj_handle_t handle; + int type; + unsigned int shm_idx; + char __pad_20[4]; +}; + + +struct get_esync_fd_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_esync_fd_reply +{ + struct reply_header __header; + int type; + unsigned int shm_idx; +}; + + +struct esync_msgwait_request +{ + struct request_header __header; + int in_msgwait; +}; +struct esync_msgwait_reply +{ + struct reply_header __header; +}; + + +struct get_esync_apc_fd_request +{ + struct request_header __header; + char __pad_12[4]; +}; +struct get_esync_apc_fd_reply +{ + struct reply_header __header; +}; + +enum fsync_type +{ + FSYNC_SEMAPHORE = 1, + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, + FSYNC_MUTEX, + FSYNC_AUTO_SERVER, + FSYNC_MANUAL_SERVER, + FSYNC_QUEUE, +}; + + +struct create_fsync_request +{ + struct request_header __header; + unsigned int access; + int low; + int high; + int type; + /* VARARG(objattr,object_attributes); */ + char __pad_28[4]; +}; +struct create_fsync_reply +{ + struct reply_header __header; + obj_handle_t handle; + int type; + unsigned int shm_idx; + char __pad_20[4]; +}; + + +struct open_fsync_request +{ + struct request_header __header; + unsigned int access; + unsigned int attributes; + obj_handle_t rootdir; + int type; + /* VARARG(name,unicode_str); */ + char __pad_28[4]; +}; +struct open_fsync_reply +{ + struct reply_header __header; + obj_handle_t handle; + int type; + unsigned int shm_idx; + char __pad_20[4]; +}; + + +struct get_fsync_idx_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct get_fsync_idx_reply +{ + struct reply_header __header; + int type; + unsigned int shm_idx; +}; + +struct fsync_msgwait_request +{ + struct request_header __header; + int in_msgwait; +}; +struct fsync_msgwait_reply +{ + struct reply_header __header; +}; + +struct get_fsync_apc_idx_request +{ + struct request_header __header; + char __pad_12[4]; +}; +struct get_fsync_apc_idx_reply +{ + struct reply_header __header; + unsigned int shm_idx; + char __pad_12[4]; +}; + + +struct init_working_set_watch_request +{ + struct request_header __header; + int fd; +}; +struct init_working_set_watch_reply +{ + struct reply_header __header; +}; + + +struct get_ws_watches_request +{ + struct request_header __header; + obj_handle_t process; +}; +struct get_ws_watches_reply +{ + struct reply_header __header; + /* VARARG(info,ws_watch_data); */ +}; + enum request { @@ -5531,6 +5848,7 @@ enum request REQ_register_async, REQ_cancel_async, REQ_get_async_result, + REQ_set_async_direct_result, REQ_read, REQ_write, REQ_ioctl, @@ -5591,6 +5909,7 @@ enum request REQ_set_capture_window, REQ_set_caret_window, REQ_set_caret_info, + REQ_get_active_hooks, REQ_set_hook, REQ_remove_hook, REQ_start_hook_chain, @@ -5682,6 +6001,18 @@ enum request REQ_suspend_process, REQ_resume_process, REQ_get_next_thread, + REQ_create_esync, + REQ_open_esync, + REQ_get_esync_fd, + REQ_esync_msgwait, + REQ_get_esync_apc_fd, + REQ_create_fsync, + REQ_open_fsync, + REQ_get_fsync_idx, + REQ_fsync_msgwait, + REQ_get_fsync_apc_idx, + REQ_init_working_set_watch, + REQ_get_ws_watches, REQ_NB_REQUESTS }; @@ -5812,6 +6143,7 @@ union generic_request struct register_async_request register_async_request; struct cancel_async_request cancel_async_request; struct get_async_result_request get_async_result_request; + struct set_async_direct_result_request set_async_direct_result_request; struct read_request read_request; struct write_request write_request; struct ioctl_request ioctl_request; @@ -5872,6 +6204,7 @@ union generic_request struct set_capture_window_request set_capture_window_request; struct set_caret_window_request set_caret_window_request; struct set_caret_info_request set_caret_info_request; + struct get_active_hooks_request get_active_hooks_request; struct set_hook_request set_hook_request; struct remove_hook_request remove_hook_request; struct start_hook_chain_request start_hook_chain_request; @@ -5963,6 +6296,18 @@ union generic_request struct suspend_process_request suspend_process_request; struct resume_process_request resume_process_request; struct get_next_thread_request get_next_thread_request; + struct create_esync_request create_esync_request; + struct open_esync_request open_esync_request; + struct get_esync_fd_request get_esync_fd_request; + struct esync_msgwait_request esync_msgwait_request; + struct get_esync_apc_fd_request get_esync_apc_fd_request; + struct create_fsync_request create_fsync_request; + struct open_fsync_request open_fsync_request; + struct get_fsync_idx_request get_fsync_idx_request; + struct fsync_msgwait_request fsync_msgwait_request; + struct get_fsync_apc_idx_request get_fsync_apc_idx_request; + struct init_working_set_watch_request init_working_set_watch_request; + struct get_ws_watches_request get_ws_watches_request; }; union generic_reply { @@ -6091,6 +6436,7 @@ union generic_reply struct register_async_reply register_async_reply; struct cancel_async_reply cancel_async_reply; struct get_async_result_reply get_async_result_reply; + struct set_async_direct_result_reply set_async_direct_result_reply; struct read_reply read_reply; struct write_reply write_reply; struct ioctl_reply ioctl_reply; @@ -6151,6 +6497,7 @@ union generic_reply struct set_capture_window_reply set_capture_window_reply; struct set_caret_window_reply set_caret_window_reply; struct set_caret_info_reply set_caret_info_reply; + struct get_active_hooks_reply get_active_hooks_reply; struct set_hook_reply set_hook_reply; struct remove_hook_reply remove_hook_reply; struct start_hook_chain_reply start_hook_chain_reply; @@ -6242,11 +6589,23 @@ union generic_reply struct suspend_process_reply suspend_process_reply; struct resume_process_reply resume_process_reply; struct get_next_thread_reply get_next_thread_reply; + struct create_esync_reply create_esync_reply; + struct open_esync_reply open_esync_reply; + struct get_esync_fd_reply get_esync_fd_reply; + struct esync_msgwait_reply esync_msgwait_reply; + struct get_esync_apc_fd_reply get_esync_apc_fd_reply; + struct create_fsync_reply create_fsync_reply; + struct open_fsync_reply open_fsync_reply; + struct get_fsync_idx_reply get_fsync_idx_reply; + struct fsync_msgwait_reply fsync_msgwait_reply; + struct get_fsync_apc_idx_reply get_fsync_apc_idx_reply; + struct init_working_set_watch_reply init_working_set_watch_reply; + struct get_ws_watches_reply get_ws_watches_reply; }; /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 739 +#define SERVER_PROTOCOL_VERSION 740 /* ### protocol_version end ### */ diff --git a/server/request.h b/server/request.h index 3c455799d54..8c5da1b3c48 100644 --- a/server/request.h +++ b/server/request.h @@ -242,6 +242,7 @@ DECL_HANDLER(set_serial_info); DECL_HANDLER(register_async); DECL_HANDLER(cancel_async); DECL_HANDLER(get_async_result); +DECL_HANDLER(set_async_direct_result); DECL_HANDLER(read); DECL_HANDLER(write); DECL_HANDLER(ioctl); @@ -302,6 +303,7 @@ DECL_HANDLER(set_active_window); DECL_HANDLER(set_capture_window); DECL_HANDLER(set_caret_window); DECL_HANDLER(set_caret_info); +DECL_HANDLER(get_active_hooks); DECL_HANDLER(set_hook); DECL_HANDLER(remove_hook); DECL_HANDLER(start_hook_chain); @@ -393,6 +395,18 @@ DECL_HANDLER(terminate_job); DECL_HANDLER(suspend_process); DECL_HANDLER(resume_process); DECL_HANDLER(get_next_thread); +DECL_HANDLER(create_esync); +DECL_HANDLER(open_esync); +DECL_HANDLER(get_esync_fd); +DECL_HANDLER(esync_msgwait); +DECL_HANDLER(get_esync_apc_fd); +DECL_HANDLER(create_fsync); +DECL_HANDLER(open_fsync); +DECL_HANDLER(get_fsync_idx); +DECL_HANDLER(fsync_msgwait); +DECL_HANDLER(get_fsync_apc_idx); +DECL_HANDLER(init_working_set_watch); +DECL_HANDLER(get_ws_watches); #ifdef WANT_REQUEST_HANDLERS @@ -522,6 +536,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_register_async, (req_handler)req_cancel_async, (req_handler)req_get_async_result, + (req_handler)req_set_async_direct_result, (req_handler)req_read, (req_handler)req_write, (req_handler)req_ioctl, @@ -582,6 +597,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_capture_window, (req_handler)req_set_caret_window, (req_handler)req_set_caret_info, + (req_handler)req_get_active_hooks, (req_handler)req_set_hook, (req_handler)req_remove_hook, (req_handler)req_start_hook_chain, @@ -673,6 +689,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_suspend_process, (req_handler)req_resume_process, (req_handler)req_get_next_thread, + (req_handler)req_create_esync, + (req_handler)req_open_esync, + (req_handler)req_get_esync_fd, + (req_handler)req_esync_msgwait, + (req_handler)req_get_esync_apc_fd, + (req_handler)req_create_fsync, + (req_handler)req_open_fsync, + (req_handler)req_get_fsync_idx, + (req_handler)req_fsync_msgwait, + (req_handler)req_get_fsync_apc_idx, + (req_handler)req_init_working_set_watch, + (req_handler)req_get_ws_watches, }; C_ASSERT( sizeof(abstime_t) == 8 ); @@ -739,7 +767,9 @@ C_ASSERT( sizeof(struct get_startup_info_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, teb) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, peb) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, ldt_copy) == 32 ); -C_ASSERT( sizeof(struct init_process_done_request) == 40 ); +C_ASSERT( FIELD_OFFSET(struct init_process_done_request, kernel_stack) == 40 ); +C_ASSERT( FIELD_OFFSET(struct init_process_done_request, kernel_stack_size) == 48 ); +C_ASSERT( sizeof(struct init_process_done_request) == 56 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_reply, entry) == 8 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_reply, suspend) == 16 ); C_ASSERT( sizeof(struct init_process_done_reply) == 24 ); @@ -748,7 +778,8 @@ C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, unix_tid) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, debug_level) == 20 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, reply_fd) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, wait_fd) == 28 ); -C_ASSERT( sizeof(struct init_first_thread_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct init_first_thread_request, nice_limit) == 32 ); +C_ASSERT( sizeof(struct init_first_thread_request) == 40 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, pid) == 8 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, tid) == 12 ); C_ASSERT( FIELD_OFFSET(struct init_first_thread_reply, server_start) == 16 ); @@ -760,7 +791,9 @@ C_ASSERT( FIELD_OFFSET(struct init_thread_request, reply_fd) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_thread_request, wait_fd) == 20 ); C_ASSERT( FIELD_OFFSET(struct init_thread_request, teb) == 24 ); C_ASSERT( FIELD_OFFSET(struct init_thread_request, entry) == 32 ); -C_ASSERT( sizeof(struct init_thread_request) == 40 ); +C_ASSERT( FIELD_OFFSET(struct init_thread_request, kernel_stack) == 40 ); +C_ASSERT( FIELD_OFFSET(struct init_thread_request, kernel_stack_size) == 48 ); +C_ASSERT( sizeof(struct init_thread_request) == 56 ); C_ASSERT( FIELD_OFFSET(struct init_thread_reply, suspend) == 8 ); C_ASSERT( sizeof(struct init_thread_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct terminate_process_request, handle) == 12 ); @@ -1042,12 +1075,12 @@ C_ASSERT( FIELD_OFFSET(struct unlock_file_request, count) == 24 ); C_ASSERT( sizeof(struct unlock_file_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_request, oob) == 12 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_request, async) == 16 ); -C_ASSERT( FIELD_OFFSET(struct recv_socket_request, status) == 56 ); -C_ASSERT( FIELD_OFFSET(struct recv_socket_request, total) == 60 ); +C_ASSERT( FIELD_OFFSET(struct recv_socket_request, force_async) == 56 ); C_ASSERT( sizeof(struct recv_socket_request) == 64 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 ); C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 ); -C_ASSERT( sizeof(struct recv_socket_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, nonblocking) == 16 ); +C_ASSERT( sizeof(struct recv_socket_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct send_socket_request, async) == 16 ); C_ASSERT( FIELD_OFFSET(struct send_socket_request, status) == 56 ); C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 ); @@ -1162,7 +1195,8 @@ C_ASSERT( sizeof(struct set_debug_obj_info_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct read_process_memory_request, addr) == 16 ); C_ASSERT( sizeof(struct read_process_memory_request) == 24 ); -C_ASSERT( sizeof(struct read_process_memory_reply) == 8 ); +C_ASSERT( FIELD_OFFSET(struct read_process_memory_reply, unix_pid) == 8 ); +C_ASSERT( sizeof(struct read_process_memory_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct write_process_memory_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct write_process_memory_request, addr) == 16 ); C_ASSERT( sizeof(struct write_process_memory_request) == 24 ); @@ -1347,8 +1381,7 @@ C_ASSERT( FIELD_OFFSET(struct get_message_reply, type) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_message_reply, x) == 36 ); C_ASSERT( FIELD_OFFSET(struct get_message_reply, y) == 40 ); C_ASSERT( FIELD_OFFSET(struct get_message_reply, time) == 44 ); -C_ASSERT( FIELD_OFFSET(struct get_message_reply, active_hooks) == 48 ); -C_ASSERT( FIELD_OFFSET(struct get_message_reply, total) == 52 ); +C_ASSERT( FIELD_OFFSET(struct get_message_reply, total) == 48 ); C_ASSERT( sizeof(struct get_message_reply) == 56 ); C_ASSERT( FIELD_OFFSET(struct reply_message_request, remove) == 12 ); C_ASSERT( FIELD_OFFSET(struct reply_message_request, result) == 16 ); @@ -1396,6 +1429,12 @@ C_ASSERT( sizeof(struct cancel_async_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_async_result_request, user_arg) == 16 ); C_ASSERT( sizeof(struct get_async_result_request) == 24 ); C_ASSERT( sizeof(struct get_async_result_reply) == 8 ); +C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, handle) == 12 ); +C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, information) == 16 ); +C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_request, status) == 24 ); +C_ASSERT( sizeof(struct set_async_direct_result_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct set_async_direct_result_reply, handle) == 8 ); +C_ASSERT( sizeof(struct set_async_direct_result_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct read_request, async) == 16 ); C_ASSERT( FIELD_OFFSET(struct read_request, pos) == 56 ); C_ASSERT( sizeof(struct read_request) == 64 ); @@ -1703,14 +1742,11 @@ C_ASSERT( sizeof(struct get_thread_input_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, focus) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, capture) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, active) == 16 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, foreground) == 20 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, menu_owner) == 24 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, move_size) == 28 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, caret) == 32 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, cursor) == 36 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, show_count) == 40 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, rect) == 44 ); -C_ASSERT( sizeof(struct get_thread_input_reply) == 64 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, menu_owner) == 20 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, move_size) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, caret) == 28 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_input_reply, rect) == 32 ); +C_ASSERT( sizeof(struct get_thread_input_reply) == 48 ); C_ASSERT( sizeof(struct get_last_input_time_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_last_input_time_reply, time) == 8 ); C_ASSERT( sizeof(struct get_last_input_time_reply) == 16 ); @@ -1762,6 +1798,9 @@ C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_rect) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_hide) == 28 ); C_ASSERT( FIELD_OFFSET(struct set_caret_info_reply, old_state) == 32 ); C_ASSERT( sizeof(struct set_caret_info_reply) == 40 ); +C_ASSERT( sizeof(struct get_active_hooks_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_active_hooks_reply, active_hooks) == 8 ); +C_ASSERT( sizeof(struct get_active_hooks_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_hook_request, id) == 12 ); C_ASSERT( FIELD_OFFSET(struct set_hook_request, pid) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_hook_request, tid) == 20 ); @@ -2121,7 +2160,8 @@ C_ASSERT( FIELD_OFFSET(struct add_completion_request, information) == 32 ); C_ASSERT( FIELD_OFFSET(struct add_completion_request, status) == 40 ); C_ASSERT( sizeof(struct add_completion_request) == 48 ); C_ASSERT( FIELD_OFFSET(struct remove_completion_request, handle) == 12 ); -C_ASSERT( sizeof(struct remove_completion_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct remove_completion_request, waited) == 16 ); +C_ASSERT( sizeof(struct remove_completion_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, ckey) == 8 ); C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, cvalue) == 16 ); C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 ); @@ -2244,6 +2284,65 @@ C_ASSERT( FIELD_OFFSET(struct get_next_thread_request, flags) == 28 ); C_ASSERT( sizeof(struct get_next_thread_request) == 32 ); C_ASSERT( FIELD_OFFSET(struct get_next_thread_reply, handle) == 8 ); C_ASSERT( sizeof(struct get_next_thread_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_request, access) == 12 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_request, initval) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_request, type) == 20 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_request, max) == 24 ); +C_ASSERT( sizeof(struct create_esync_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_reply, handle) == 8 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_reply, type) == 12 ); +C_ASSERT( FIELD_OFFSET(struct create_esync_reply, shm_idx) == 16 ); +C_ASSERT( sizeof(struct create_esync_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_request, access) == 12 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_request, attributes) == 16 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_request, rootdir) == 20 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_request, type) == 24 ); +C_ASSERT( sizeof(struct open_esync_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_reply, handle) == 8 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_reply, type) == 12 ); +C_ASSERT( FIELD_OFFSET(struct open_esync_reply, shm_idx) == 16 ); +C_ASSERT( sizeof(struct open_esync_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_esync_fd_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_esync_fd_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, type) == 8 ); +C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, shm_idx) == 12 ); +C_ASSERT( sizeof(struct get_esync_fd_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct esync_msgwait_request, in_msgwait) == 12 ); +C_ASSERT( sizeof(struct esync_msgwait_request) == 16 ); +C_ASSERT( sizeof(struct get_esync_apc_fd_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_request, access) == 12 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_request, low) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_request, high) == 20 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_request, type) == 24 ); +C_ASSERT( sizeof(struct create_fsync_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, handle) == 8 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, type) == 12 ); +C_ASSERT( FIELD_OFFSET(struct create_fsync_reply, shm_idx) == 16 ); +C_ASSERT( sizeof(struct create_fsync_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_request, access) == 12 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_request, attributes) == 16 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_request, rootdir) == 20 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_request, type) == 24 ); +C_ASSERT( sizeof(struct open_fsync_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, handle) == 8 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, type) == 12 ); +C_ASSERT( FIELD_OFFSET(struct open_fsync_reply, shm_idx) == 16 ); +C_ASSERT( sizeof(struct open_fsync_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_request, handle) == 12 ); +C_ASSERT( sizeof(struct get_fsync_idx_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_reply, type) == 8 ); +C_ASSERT( FIELD_OFFSET(struct get_fsync_idx_reply, shm_idx) == 12 ); +C_ASSERT( sizeof(struct get_fsync_idx_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct fsync_msgwait_request, in_msgwait) == 12 ); +C_ASSERT( sizeof(struct fsync_msgwait_request) == 16 ); +C_ASSERT( sizeof(struct get_fsync_apc_idx_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_fsync_apc_idx_reply, shm_idx) == 8 ); +C_ASSERT( sizeof(struct get_fsync_apc_idx_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct init_working_set_watch_request, fd) == 12 ); +C_ASSERT( sizeof(struct init_working_set_watch_request) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_ws_watches_request, process) == 12 ); +C_ASSERT( sizeof(struct get_ws_watches_request) == 16 ); +C_ASSERT( sizeof(struct get_ws_watches_reply) == 8 ); #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/trace.c b/server/trace.c index e971ba20b6f..39afbe199f4 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1487,6 +1487,8 @@ static void dump_init_process_done_request( const struct init_process_done_reque dump_uint64( " teb=", &req->teb ); dump_uint64( ", peb=", &req->peb ); dump_uint64( ", ldt_copy=", &req->ldt_copy ); + dump_uint64( ", kernel_stack=", &req->kernel_stack ); + fprintf( stderr, ", kernel_stack_size=%08x", req->kernel_stack_size ); } static void dump_init_process_done_reply( const struct init_process_done_reply *req ) @@ -1503,6 +1505,7 @@ static void dump_init_first_thread_request( const struct init_first_thread_reque fprintf( stderr, ", debug_level=%d", req->debug_level ); fprintf( stderr, ", reply_fd=%d", req->reply_fd ); fprintf( stderr, ", wait_fd=%d", req->wait_fd ); + fprintf( stderr, ", nice_limit=%c", req->nice_limit ); } static void dump_init_first_thread_reply( const struct init_first_thread_reply *req ) @@ -1522,6 +1525,8 @@ static void dump_init_thread_request( const struct init_thread_request *req ) fprintf( stderr, ", wait_fd=%d", req->wait_fd ); dump_uint64( ", teb=", &req->teb ); dump_uint64( ", entry=", &req->entry ); + dump_uint64( ", kernel_stack=", &req->kernel_stack ); + fprintf( stderr, ", kernel_stack_size=%08x", req->kernel_stack_size ); } static void dump_init_thread_reply( const struct init_thread_reply *req ) @@ -2098,14 +2103,14 @@ static void dump_recv_socket_request( const struct recv_socket_request *req ) { fprintf( stderr, " oob=%d", req->oob ); dump_async_data( ", async=", &req->async ); - fprintf( stderr, ", status=%08x", req->status ); - fprintf( stderr, ", total=%08x", req->total ); + fprintf( stderr, ", force_async=%d", req->force_async ); } static void dump_recv_socket_reply( const struct recv_socket_reply *req ) { fprintf( stderr, " wait=%04x", req->wait ); fprintf( stderr, ", options=%08x", req->options ); + fprintf( stderr, ", nonblocking=%d", req->nonblocking ); } static void dump_send_socket_request( const struct send_socket_request *req ) @@ -2340,7 +2345,8 @@ static void dump_read_process_memory_request( const struct read_process_memory_r static void dump_read_process_memory_reply( const struct read_process_memory_reply *req ) { - dump_varargs_bytes( " data=", cur_size ); + fprintf( stderr, " unix_pid=%d", req->unix_pid ); + dump_varargs_bytes( ", data=", cur_size ); } static void dump_write_process_memory_request( const struct write_process_memory_request *req ) @@ -2698,7 +2704,6 @@ static void dump_send_hardware_message_reply( const struct send_hardware_message fprintf( stderr, ", prev_y=%d", req->prev_y ); fprintf( stderr, ", new_x=%d", req->new_x ); fprintf( stderr, ", new_y=%d", req->new_y ); - dump_varargs_bytes( ", keystate=", cur_size ); } static void dump_get_message_request( const struct get_message_request *req ) @@ -2722,7 +2727,6 @@ static void dump_get_message_reply( const struct get_message_reply *req ) fprintf( stderr, ", x=%d", req->x ); fprintf( stderr, ", y=%d", req->y ); fprintf( stderr, ", time=%08x", req->time ); - fprintf( stderr, ", active_hooks=%08x", req->active_hooks ); fprintf( stderr, ", total=%u", req->total ); dump_varargs_message_data( ", data=", cur_size ); } @@ -2824,6 +2828,18 @@ static void dump_get_async_result_reply( const struct get_async_result_reply *re dump_varargs_bytes( " out_data=", cur_size ); } +static void dump_set_async_direct_result_request( const struct set_async_direct_result_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + dump_uint64( ", information=", &req->information ); + fprintf( stderr, ", status=%08x", req->status ); +} + +static void dump_set_async_direct_result_reply( const struct set_async_direct_result_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + static void dump_read_request( const struct read_request *req ) { dump_async_data( " async=", &req->async ); @@ -3428,12 +3444,9 @@ static void dump_get_thread_input_reply( const struct get_thread_input_reply *re fprintf( stderr, " focus=%08x", req->focus ); fprintf( stderr, ", capture=%08x", req->capture ); fprintf( stderr, ", active=%08x", req->active ); - fprintf( stderr, ", foreground=%08x", req->foreground ); fprintf( stderr, ", menu_owner=%08x", req->menu_owner ); fprintf( stderr, ", move_size=%08x", req->move_size ); fprintf( stderr, ", caret=%08x", req->caret ); - fprintf( stderr, ", cursor=%08x", req->cursor ); - fprintf( stderr, ", show_count=%d", req->show_count ); dump_rectangle( ", rect=", &req->rect ); } @@ -3541,6 +3554,15 @@ static void dump_set_caret_info_reply( const struct set_caret_info_reply *req ) fprintf( stderr, ", old_state=%d", req->old_state ); } +static void dump_get_active_hooks_request( const struct get_active_hooks_request *req ) +{ +} + +static void dump_get_active_hooks_reply( const struct get_active_hooks_reply *req ) +{ + fprintf( stderr, " active_hooks=%08x", req->active_hooks ); +} + static void dump_set_hook_request( const struct set_hook_request *req ) { fprintf( stderr, " id=%d", req->id ); @@ -4286,6 +4308,7 @@ static void dump_add_completion_request( const struct add_completion_request *re static void dump_remove_completion_request( const struct remove_completion_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", waited=%d", req->waited ); } static void dump_remove_completion_reply( const struct remove_completion_reply *req ) @@ -4536,6 +4559,130 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req fprintf( stderr, " handle=%04x", req->handle ); } +static void dump_create_esync_request( const struct create_esync_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", initval=%d", req->initval ); + fprintf( stderr, ", type=%d", req->type ); + fprintf( stderr, ", max=%d", req->max ); + dump_varargs_object_attributes( ", objattr=", cur_size ); +} + +static void dump_create_esync_reply( const struct create_esync_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_open_esync_request( const struct open_esync_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", attributes=%08x", req->attributes ); + fprintf( stderr, ", rootdir=%04x", req->rootdir ); + fprintf( stderr, ", type=%d", req->type ); + dump_varargs_unicode_str( ", name=", cur_size ); +} + +static void dump_open_esync_reply( const struct open_esync_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_get_esync_fd_request( const struct get_esync_fd_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_esync_fd_reply( const struct get_esync_fd_reply *req ) +{ + fprintf( stderr, " type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_esync_msgwait_request( const struct esync_msgwait_request *req ) +{ + fprintf( stderr, " in_msgwait=%d", req->in_msgwait ); +} + +static void dump_get_esync_apc_fd_request( const struct get_esync_apc_fd_request *req ) +{ +} + +static void dump_create_fsync_request( const struct create_fsync_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", low=%d", req->low ); + fprintf( stderr, ", high=%d", req->high ); + fprintf( stderr, ", type=%d", req->type ); + dump_varargs_object_attributes( ", objattr=", cur_size ); +} + +static void dump_create_fsync_reply( const struct create_fsync_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_open_fsync_request( const struct open_fsync_request *req ) +{ + fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", attributes=%08x", req->attributes ); + fprintf( stderr, ", rootdir=%04x", req->rootdir ); + fprintf( stderr, ", type=%d", req->type ); + dump_varargs_unicode_str( ", name=", cur_size ); +} + +static void dump_open_fsync_reply( const struct open_fsync_reply *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); + fprintf( stderr, ", type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_get_fsync_idx_request( const struct get_fsync_idx_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + +static void dump_get_fsync_idx_reply( const struct get_fsync_idx_reply *req ) +{ + fprintf( stderr, " type=%d", req->type ); + fprintf( stderr, ", shm_idx=%08x", req->shm_idx ); +} + +static void dump_fsync_msgwait_request( const struct fsync_msgwait_request *req ) +{ + fprintf( stderr, " in_msgwait=%d", req->in_msgwait ); +} + +static void dump_get_fsync_apc_idx_request( const struct get_fsync_apc_idx_request *req ) +{ +} + +static void dump_get_fsync_apc_idx_reply( const struct get_fsync_apc_idx_reply *req ) +{ + fprintf( stderr, " shm_idx=%08x", req->shm_idx ); +} + +static void dump_init_working_set_watch_request( const struct init_working_set_watch_request *req ) +{ + fprintf( stderr, " fd=%d", req->fd ); +} + +static void dump_get_ws_watches_request( const struct get_ws_watches_request *req ) +{ + fprintf( stderr, " process=%04x", req->process ); +} + +static void dump_get_ws_watches_reply( const struct get_ws_watches_reply *req ) +{ + dump_varargs_ws_watch_data( " info=", cur_size ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -4660,6 +4807,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_register_async_request, (dump_func)dump_cancel_async_request, (dump_func)dump_get_async_result_request, + (dump_func)dump_set_async_direct_result_request, (dump_func)dump_read_request, (dump_func)dump_write_request, (dump_func)dump_ioctl_request, @@ -4720,6 +4868,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_capture_window_request, (dump_func)dump_set_caret_window_request, (dump_func)dump_set_caret_info_request, + (dump_func)dump_get_active_hooks_request, (dump_func)dump_set_hook_request, (dump_func)dump_remove_hook_request, (dump_func)dump_start_hook_chain_request, @@ -4811,6 +4960,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_suspend_process_request, (dump_func)dump_resume_process_request, (dump_func)dump_get_next_thread_request, + (dump_func)dump_create_esync_request, + (dump_func)dump_open_esync_request, + (dump_func)dump_get_esync_fd_request, + (dump_func)dump_esync_msgwait_request, + (dump_func)dump_get_esync_apc_fd_request, + (dump_func)dump_create_fsync_request, + (dump_func)dump_open_fsync_request, + (dump_func)dump_get_fsync_idx_request, + (dump_func)dump_fsync_msgwait_request, + (dump_func)dump_get_fsync_apc_idx_request, + (dump_func)dump_init_working_set_watch_request, + (dump_func)dump_get_ws_watches_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -4937,6 +5098,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, (dump_func)dump_get_async_result_reply, + (dump_func)dump_set_async_direct_result_reply, (dump_func)dump_read_reply, (dump_func)dump_write_reply, (dump_func)dump_ioctl_reply, @@ -4997,6 +5159,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_capture_window_reply, (dump_func)dump_set_caret_window_reply, (dump_func)dump_set_caret_info_reply, + (dump_func)dump_get_active_hooks_reply, (dump_func)dump_set_hook_reply, (dump_func)dump_remove_hook_reply, (dump_func)dump_start_hook_chain_reply, @@ -5088,6 +5251,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { NULL, NULL, (dump_func)dump_get_next_thread_reply, + (dump_func)dump_create_esync_reply, + (dump_func)dump_open_esync_reply, + (dump_func)dump_get_esync_fd_reply, + NULL, + NULL, + (dump_func)dump_create_fsync_reply, + (dump_func)dump_open_fsync_reply, + (dump_func)dump_get_fsync_idx_reply, + NULL, + (dump_func)dump_get_fsync_apc_idx_reply, + NULL, + (dump_func)dump_get_ws_watches_reply, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -5214,6 +5389,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "register_async", "cancel_async", "get_async_result", + "set_async_direct_result", "read", "write", "ioctl", @@ -5274,6 +5450,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_capture_window", "set_caret_window", "set_caret_info", + "get_active_hooks", "set_hook", "remove_hook", "start_hook_chain", @@ -5365,6 +5542,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "suspend_process", "resume_process", "get_next_thread", + "create_esync", + "open_esync", + "get_esync_fd", + "esync_msgwait", + "get_esync_apc_fd", + "create_fsync", + "open_fsync", + "get_fsync_idx", + "fsync_msgwait", + "get_fsync_apc_idx", + "init_working_set_watch", + "get_ws_watches", }; static const struct @@ -5480,6 +5669,7 @@ static const struct { "PIPE_EMPTY", STATUS_PIPE_EMPTY }, { "PIPE_LISTENING", STATUS_PIPE_LISTENING }, { "PIPE_NOT_AVAILABLE", STATUS_PIPE_NOT_AVAILABLE }, + { "PORT_ALREADY_SET", STATUS_PORT_ALREADY_SET }, { "PORT_NOT_SET", STATUS_PORT_NOT_SET }, { "PREDEFINED_HANDLE", STATUS_PREDEFINED_HANDLE }, { "PRIVILEGE_NOT_HELD", STATUS_PRIVILEGE_NOT_HELD }, From 9c934b8a2e19e037724a8e9f3d3f7ccb4314f141 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Feb 2022 15:19:58 +0300 Subject: [PATCH 56/83] wined3d: Use StretchBlt() in swapchain_blit_gdi(). CW-Bug-Id: #20141 Signed-off-by: Paul Gofman Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard (cherry picked from commit 2435f116c3ae527a4b6b52b78a44449a277fd8db) --- dlls/wined3d/swapchain.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 49a40f3e1d6..5fcbfc58779 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -459,8 +459,9 @@ static void swapchain_blit_gdi(struct wined3d_swapchain *swapchain, if (!(dst_dc = GetDCEx(swapchain->win_handle, 0, DCX_USESTYLE | DCX_CACHE))) ERR("Failed to get destination DC.\n"); - if (!BitBlt(dst_dc, dst_rect->left, dst_rect->top, dst_rect->right - dst_rect->left, - dst_rect->bottom - dst_rect->top, src_dc, src_rect->left, src_rect->top, SRCCOPY)) + if (!StretchBlt(dst_dc, dst_rect->left, dst_rect->top, dst_rect->right - dst_rect->left, + dst_rect->bottom - dst_rect->top, src_dc, src_rect->left, src_rect->top, + src_rect->right - src_rect->left, src_rect->bottom - src_rect->top, SRCCOPY)) ERR("Failed to blit.\n"); ReleaseDC(swapchain->win_handle, dst_dc); From af5da6c8de6bcf7b1e68d75b17bb66b4431e3e5b Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Fri, 11 Feb 2022 18:42:28 +0300 Subject: [PATCH 57/83] wined3d: Clear GL backbuffer in wined3d_context_gl_init(). CW-Bug-Id: #20141 Signed-off-by: Paul Gofman Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard (cherry picked from commit b36e4cfe2d7ceef6f6b672811d9481d6c23c0ac9) --- dlls/wined3d/context_gl.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c index 9fd2ed67dcc..8e8305352fe 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -1897,7 +1897,7 @@ HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, } static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context_gl, - struct wined3d_swapchain_gl *swapchain_gl) + struct wined3d_swapchain_gl *swapchain_gl, BOOL *new_drawable) { enum wined3d_swap_effect swap_effect = swapchain_gl->s.state.desc.swap_effect; const struct wined3d_format *colour_format, *ds_format; @@ -1920,6 +1920,8 @@ static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context swap_effect_copy = swap_effect == WINED3D_SWAP_EFFECT_COPY || swap_effect == WINED3D_SWAP_EFFECT_COPY_VSYNC; + *new_drawable = !GetPixelFormat(context_gl->dc); + if (wined3d_settings.offscreen_rendering_mode == ORM_BACKBUFFER) { static const enum wined3d_format_id ds_formats[] = @@ -2018,7 +2020,7 @@ static BOOL wined3d_context_gl_create_wgl_ctx(struct wined3d_context_gl *context } context_gl->dc_is_private = TRUE; - return wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl); + return wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl, new_drawable); } share_ctx = device->context_count ? wined3d_context_gl(device->contexts[0])->gl_ctx : NULL; @@ -2064,6 +2066,7 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi const struct wined3d_d3d_info *d3d_info; const struct wined3d_gl_info *gl_info; struct wined3d_device *device; + BOOL new_drawable; unsigned int i; TRACE("context_gl %p, swapchain %p.\n", context_gl, swapchain_gl); @@ -2142,7 +2145,7 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi sizeof(*context_gl->texture_type)))) goto fail; - if (!wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl)) + if (!wined3d_context_gl_create_wgl_ctx(context_gl, swapchain_gl, &new_drawable)) goto fail; /* Set up the context defaults. */ @@ -2299,6 +2302,14 @@ HRESULT wined3d_context_gl_init(struct wined3d_context_gl *context_gl, struct wi gl_info->gl_ops.gl.p_glScissor(0, 0, 0, 0); checkGLcall("glScissor"); + if (new_drawable) + { + gl_info->gl_ops.gl.p_glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + gl_info->gl_ops.gl.p_glClearDepth(1.0f); + gl_info->gl_ops.gl.p_glClearStencil(0); + gl_info->gl_ops.gl.p_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + checkGLcall("glClear"); + } return WINED3D_OK; fail: From 62f18137cb5ff9b468079d7d1f26a512bdb66c90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 15 Feb 2022 10:51:42 +0100 Subject: [PATCH 58/83] fixup! winegstreamer: After failing to create decodebin parser, try protonvideoconv. --- dlls/winegstreamer/wg_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 89a64339413..337953db78d 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -30,6 +30,7 @@ #include #include +#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 #include #include #include From 0de1a4cb50828f0867253d2fb3d6d679d4b8a39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 15 Feb 2022 10:56:31 +0100 Subject: [PATCH 59/83] fixup! battleye: Add launcher process instead of redirecting CreateProcess call. --- programs/belauncher/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c index 0f727f3ca7d..86ec46ecee4 100644 --- a/programs/belauncher/main.c +++ b/programs/belauncher/main.c @@ -73,7 +73,8 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm *(strchr(game_exe, '\n')) = 0; game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; - if (be_arg) + if (!be_arg) arg_len = 0; + else { if (strchr(be_arg, '\r')) *(strchr(be_arg, '\r')) = 0; From d6a237166626d197b1d642f8f7a71900759df2b6 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Feb 2022 17:20:40 +0300 Subject: [PATCH 60/83] fsync: Add WINE_FSYNC_SIMULATE_SCHED_QUANTUM config option. And auto enable it for Uplay laucher. CW-Bug-Id: #20155 --- dlls/ntdll/unix/fsync.c | 20 +++++++++++++++++++- dlls/ntdll/unix/loader.c | 15 ++++++++++++--- dlls/ntdll/unix/unix_private.h | 1 + 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index d468782667a..f42e30d0245 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -112,6 +112,18 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v waitv->__reserved = 0; } +static void simulate_sched_quantum(void) +{ + LARGE_INTEGER now; + ULONG64 wait_end; + + if (!fsync_simulate_sched_quantum) return; + + NtQuerySystemTime( &now ); + wait_end = (now.QuadPart / 10 + 499) / 500; + usleep( wait_end * 500 - (now.QuadPart / 10) ); +} + static inline int futex_wait_multiple( const struct futex_waitv *futexes, int count, const ULONGLONG *end ) { @@ -756,8 +768,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + BOOL msgwait = FALSE, waited = FALSE; int has_fsync = 0, has_server = 0; - BOOL msgwait = FALSE; int dummy_futex = 0; unsigned int spin; LONGLONG timeleft; @@ -879,6 +891,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) { TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); return i; } small_pause(); @@ -896,6 +909,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->count++; + if (waited) simulate_sched_quantum(); return i; } @@ -905,6 +919,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, { TRACE("Woken up by handle %p [%d].\n", handles[i], i); mutex->count = 1; + if (waited) simulate_sched_quantum(); return i; } else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) @@ -932,6 +947,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, usleep( 0 ); TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); return i; } small_pause(); @@ -954,6 +970,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, usleep( 0 ); TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); return i; } small_pause(); @@ -1008,6 +1025,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, TRACE("Wait timed out.\n"); return STATUS_TIMEOUT; } + else waited = TRUE; } /* while (1) */ } else diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 301a11c0419..f078a967be8 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -2237,11 +2237,13 @@ static struct unix_funcs unix_funcs = }; BOOL ac_odyssey; +BOOL fsync_simulate_sched_quantum; static void hacks_init(void) { + static const char upc_exe[] = "Ubisoft Game Launcher\\upc.exe"; static const char ac_odyssey_exe[] = "ACOdyssey.exe"; - const char *sgi; + const char *env_str; if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) { @@ -2249,9 +2251,16 @@ static void hacks_init(void) ac_odyssey = TRUE; return; } + env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM"); + if (env_str) + fsync_simulate_sched_quantum = !!atoi(env_str); + else if (main_argc > 1) + fsync_simulate_sched_quantum = !!strstr(main_argv[1], upc_exe); + if (fsync_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in fsync.\n"); - sgi = getenv("SteamGameId"); - if (sgi && !strcmp(sgi, "50130")) + env_str = getenv("SteamGameId"); + if (env_str && !strcmp(env_str, "50130")) setenv("WINESTEAMNOEXEC", "1", 0); } diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index d1840de8876..4bf0e7cb84e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -148,6 +148,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; #endif extern BOOL ac_odyssey DECLSPEC_HIDDEN; +extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; extern void init_startup_info(void) DECLSPEC_HIDDEN; From b3fb8a5543db15280952042152f5218ee994b011 Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 15 Feb 2022 22:00:23 +0300 Subject: [PATCH 61/83] fixup! fsync: Add WINE_FSYNC_SIMULATE_SCHED_QUANTUM config option. --- dlls/ntdll/unix/fsync.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c index f42e30d0245..0f19c63a5f2 100644 --- a/dlls/ntdll/unix/fsync.c +++ b/dlls/ntdll/unix/fsync.c @@ -114,14 +114,11 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v static void simulate_sched_quantum(void) { - LARGE_INTEGER now; - ULONG64 wait_end; - if (!fsync_simulate_sched_quantum) return; - - NtQuerySystemTime( &now ); - wait_end = (now.QuadPart / 10 + 499) / 500; - usleep( wait_end * 500 - (now.QuadPart / 10) ); + /* futex wait is often very quick to resume a waiting thread when woken. + * That reveals synchonization bugs in some games which happen to work on + * Windows due to the waiting threads having some minimal delay to wake up. */ + usleep(0); } static inline int futex_wait_multiple( const struct futex_waitv *futexes, From deb036dc4060a96acb99fb53abf553b53b988479 Mon Sep 17 00:00:00 2001 From: Arkadiusz Hiler Date: Wed, 16 Feb 2022 13:01:34 +0200 Subject: [PATCH 62/83] Revert "winevulkan: Allow call of unexposed function vkCmdWriteBufferMarkerAMD." This reverts commit a68c514399374b01d79f9d96ab1daa69380f9a16. Fixed-by: fc8dcb53c2ce ("winevulkan: Return NULL for unavailable device functions.") Link: https://github.com/ValveSoftware/wine/issues/135 --- dlls/winevulkan/make_vulkan | 2 -- dlls/winevulkan/vulkan.c | 26 -------------------------- 2 files changed, 28 deletions(-) diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 16a73a74aeb..a0287c1ff09 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -263,8 +263,6 @@ FUNCTION_OVERRIDES = { # VK_EXT_debug_report "vkCreateDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, "vkDestroyDebugReportCallbackEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, - - "vkCmdWriteBufferMarkerAMD" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, } STRUCT_CHAIN_CONVERSIONS = { diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e0da6849d73..3c8bd452eca 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -2656,32 +2656,6 @@ NTSTATUS wine_vkDestroyDebugReportCallbackEXT(void *args) return STATUS_SUCCESS; } -/* HACK: Rainbow Six Siege tries to call this function regardless of whether the extension is exposed */ -NTSTATUS wine_vkCmdWriteBufferMarkerAMD(void *args) -{ - struct vkCmdWriteBufferMarkerAMD_params *params = args; - VkCommandBuffer commandBuffer = params->commandBuffer; - VkPipelineStageFlagBits pipelineStage = params->pipelineStage; - VkBuffer dstBuffer = params->dstBuffer; - VkDeviceSize dstOffset = params->dstOffset; - uint32_t marker = params->marker; - - TRACE("%p, %#x, 0x%s, 0x%s, %u\n", commandBuffer, pipelineStage, wine_dbgstr_longlong(dstBuffer), wine_dbgstr_longlong(dstOffset), marker); - - if (commandBuffer->device->funcs.p_vkCmdWriteBufferMarkerAMD) - { - commandBuffer->device->funcs.p_vkCmdWriteBufferMarkerAMD(commandBuffer->command_buffer, pipelineStage, dstBuffer, dstOffset, marker); - } - else - { - static unsigned int once; - - if (!once++) - FIXME("HACK: returning success from unexposed function.\n"); - } - return STATUS_SUCCESS; -} - NTSTATUS wine_vkAcquireNextImage2KHR(void *args) { struct vkAcquireNextImage2KHR_params *params = args; From ed289622ea368cea993ad85ac7ae7097b9ad9250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 15:01:24 +0100 Subject: [PATCH 63/83] Revert "mshtml: Always report available data before stop_binding." This reverts commit a08d7daa268d5b86e8165c23af28a88b83e77053. This should not be needed after 7c037c82c8c56539dd03e00628e27e4525b66483 CW-Bug-Id: 18691 --- dlls/urlmon/binding.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dlls/urlmon/binding.c b/dlls/urlmon/binding.c index 708b81194c7..a74970033b3 100644 --- a/dlls/urlmon/binding.c +++ b/dlls/urlmon/binding.c @@ -1177,14 +1177,6 @@ static HRESULT WINAPI InternetProtocolSink_ReportResult(IInternetProtocolSink *i TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult)); - /* Make sure we don't call stop_binding before available data has been reported, - as some custom protocol handlers call ReportResult within LockRequest */ - if (!(This->state & BINDING_LOCKED) && hrResult == S_OK) - { - This->download_state = END_DOWNLOAD; - return S_OK; - } - stop_binding(This, hrResult, szResult); IInternetProtocolEx_Terminate(&This->protocol->IInternetProtocolEx_iface, 0); From 3350eca1c084ebf3c5c5dbb629256012fd597a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 28 Jan 2021 14:05:48 +0100 Subject: [PATCH 64/83] winex11.drv: Fix focus delay issues with desktop clipping. --- dlls/winex11.drv/event.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index ce81dd3c084..27d1fa7fbe0 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -340,6 +340,7 @@ static int try_grab_pointer( Display *display ) return 0; XUngrabPointer( display, CurrentTime ); + XFlush( display ); return 1; } @@ -845,6 +846,14 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) Sleep(100); + if (!try_grab_pointer( event->display )) + { + /* ask the desktop window to release its grab before trying to get ours */ + SendMessageW( GetDesktopWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); + XSendEvent( event->display, event->window, False, 0, xev ); + return FALSE; + } + /* ask the foreground window to re-apply the current ClipCursor rect */ SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); @@ -867,11 +876,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); return TRUE; } - else if (!try_grab_pointer( event->display )) - { - XSendEvent( event->display, event->window, False, 0, xev ); - return FALSE; - } SetForegroundWindow( hwnd ); return TRUE; From 1f3291a794b471a462dab2fb142f7391c67b20c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 14 Sep 2021 14:16:47 +0200 Subject: [PATCH 65/83] msvcrt: Check for ERMS support and use rep stosb for large memset calls. --- dlls/msvcrt/math.c | 13 +++++++++ dlls/msvcrt/msvcrt.h | 1 + dlls/msvcrt/string.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 14afad5fb45..28794d1c7b8 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "msvcrt.h" #include "winternl.h" @@ -64,11 +65,23 @@ typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *); static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL; +BOOL erms_supported; BOOL sse2_supported; static BOOL sse2_enabled; void msvcrt_init_math( void *module ) { +#if defined(__i386__) || defined(__x86_64__) + int regs[4]; + + __cpuid(regs, 0); + if (regs[0] >= 7) + { + __cpuidex(regs, 7, 0); + erms_supported = ((regs[1] >> 9) & 1); + } +#endif + sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE ); #if _MSVCR_VER <=71 sse2_enabled = FALSE; diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h index e50f3e6991b..348eda2afbd 100644 --- a/dlls/msvcrt/msvcrt.h +++ b/dlls/msvcrt/msvcrt.h @@ -33,6 +33,7 @@ #undef strncpy #undef wcsncpy +extern BOOL erms_supported DECLSPEC_HIDDEN; extern BOOL sse2_supported DECLSPEC_HIDDEN; #define DBL80_MAX_10_EXP 4932 diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index d92b7a38d12..3a5b00dd158 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -2941,6 +2941,13 @@ __ASM_GLOBAL_FUNC( sse2_memmove, MEMMOVE_CLEANUP "ret" ) +#undef MEMMOVE_INIT +#undef MEMMOVE_CLEANUP +#undef DEST_REG +#undef SRC_REG +#undef LEN_REG +#undef TMP_REG + #endif /********************************************************************* @@ -3075,6 +3082,55 @@ void * __cdecl _memccpy(void *dst, const void *src, int c, size_t n) return NULL; } +#if defined(__i386__) || defined(__x86_64__) + +#ifdef __i386__ +#define DEST_REG "%edi" +#define LEN_REG "%ecx" +#define VAL_REG "%eax" + +#define MEMSET_INIT \ + "movl " DEST_REG ", %edx\n\t" \ + "movl 4(%esp), " DEST_REG "\n\t" \ + "movl 8(%esp), " VAL_REG "\n\t" \ + "movl 12(%esp), " LEN_REG "\n\t" + +#define MEMSET_RET \ + "movl %edx, " DEST_REG "\n\t" \ + "ret" + +#else + +#define DEST_REG "%rdi" +#define LEN_REG "%rcx" +#define VAL_REG "%eax" + +#define MEMSET_INIT \ + "movq " DEST_REG ", %r9\n\t" \ + "movq %rcx, " DEST_REG "\n\t" \ + "movl %edx, " VAL_REG "\n\t" \ + "movq %r8, " LEN_REG "\n\t" + +#define MEMSET_RET \ + "movq %r9, " DEST_REG "\n\t" \ + "ret" + +#endif + +void __cdecl erms_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); +__ASM_GLOBAL_FUNC( erms_memset_aligned_32, + MEMSET_INIT + "rep\n\t" + "stosb\n\t" + MEMSET_RET ) + +#undef MEMSET_INIT +#undef MEMSET_RET +#undef DEST_REG +#undef LEN_REG +#undef VAL_REG + +#endif static inline void memset_aligned_32(unsigned char *d, uint64_t v, size_t n) { @@ -3116,6 +3172,13 @@ void *__cdecl memset(void *dst, int c, size_t n) if (n <= 64) return dst; n = (n - a) & ~0x1f; +#if defined(__i386__) || defined(__x86_64__) + if (n >= 2048 && erms_supported) + { + erms_memset_aligned_32(d + a, v, n); + return dst; + } +#endif memset_aligned_32(d + a, v, n); return dst; } From 243f46b0b1c68704f0e67f24138458f4dd626bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 14 Sep 2021 14:16:48 +0200 Subject: [PATCH 66/83] msvcrt: Add an SSE2 memset_aligned_32 implementation. This writes memory forward in memset instead of going backward, which may break the Linux kernel transparent huge pages allocation assumptions. --- dlls/msvcrt/string.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c index 3a5b00dd158..01c10cd7e36 100644 --- a/dlls/msvcrt/string.c +++ b/dlls/msvcrt/string.c @@ -3124,6 +3124,29 @@ __ASM_GLOBAL_FUNC( erms_memset_aligned_32, "stosb\n\t" MEMSET_RET ) +void __cdecl sse2_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); +__ASM_GLOBAL_FUNC( sse2_memset_aligned_32, + MEMSET_INIT + "movd " VAL_REG ", %xmm0\n\t" + "pshufd $0, %xmm0, %xmm0\n\t" + "test $0x20, " LEN_REG "\n\t" + "je 1f\n\t" + "add $0x20, " DEST_REG "\n\t" + "sub $0x20, " LEN_REG "\n\t" + "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" + "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" + "je 2f\n\t" + "1:\n\t" + "add $0x40, " DEST_REG "\n\t" + "sub $0x40, " LEN_REG "\n\t" + "movdqa %xmm0, -0x40(" DEST_REG ")\n\t" + "movdqa %xmm0, -0x30(" DEST_REG ")\n\t" + "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" + "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" + "ja 1b\n\t" + "2:\n\t" + MEMSET_RET ) + #undef MEMSET_INIT #undef MEMSET_RET #undef DEST_REG @@ -3178,9 +3201,21 @@ void *__cdecl memset(void *dst, int c, size_t n) erms_memset_aligned_32(d + a, v, n); return dst; } +#ifdef __x86_64__ + sse2_memset_aligned_32(d + a, v, n); + return dst; +#else + if (sse2_supported) + { + sse2_memset_aligned_32(d + a, v, n); + return dst; + } +#endif #endif +#ifndef __x86_64__ memset_aligned_32(d + a, v, n); return dst; +#endif } if (n >= 8) { From dc0e276ee14da510e06bd65397e36a84d07f48b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Fri, 4 Jun 2021 10:24:10 +0200 Subject: [PATCH 67/83] wineboot: Compute and write the TSC frequency to registry ~Mhz. In HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor Squashed with patches from: * Arkadiusz Hiler Check if the kernel trusts TSC before using it for Qpc. Even if the bits are claiming that TSC meets our requirements the hardware implementation may still be broken. The Linux kernel does a lot of quality testing before deciding to use as the clock source. If it (or the user, through an override) does not trust the TSC we should not trust it either. * Joshua Ashton Some games such as Horizon Zero Dawn use this registry value to correlate values from rtdsc to real time. Testing across a few devices, is seems like Windows always returns the TSC frequency in this entry, not the current/maximum frequency of the processor. Returning the nominal/maximum cpu frequency here causes the game to run in slow motion as it may not match the tsc frequency of the processor. Ideally we'd not have to measure this and the kernel would return tsc_khz to userspace, but this is a good enough stop-gap until https://lkml.org/lkml/2020/12/31/72 or something similar is merged. CW-Bug-Id: #18918 CW-Bug-Id: #18958 --- programs/wineboot/wineboot.c | 175 ++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 5 deletions(-) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 16b44ca28ab..012155fccba 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -83,6 +83,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wineboot); +#define TICKSPERSEC 10000000 + extern BOOL shutdown_close_windows( BOOL force ); extern BOOL shutdown_all_desktops( BOOL force ); extern void kill_processes( BOOL kill_desktop ); @@ -242,15 +244,173 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); } +static UINT64 read_tsc_frequency( BOOL has_rdtscp ) +{ + UINT64 freq = 0; + +/* FIXME: Intel provides TSC freq in some CPUID but it's been slightly broken, + fix it properly and test it on real Intel hardware */ + +#if 0 + int regs[4], cpuid_level, tmp; + UINT64 denom, numer; + + __cpuid( regs, 0 ); + tmp = regs[2]; + regs[2] = regs[3]; + regs[3] = tmp; + + /* only available on some intel CPUs */ + if (memcmp( regs + 1, "GenuineIntel", 12 )) freq = 0; + else if ((cpuid_level = regs[0]) < 0x15) freq = 0; + else + { + __cpuid( regs, 0x15 ); + if (!(denom = regs[0]) || !(numer = regs[1])) freq = 0; + else + { + if ((freq = regs[2])) freq = freq * numer / denom; + else if (cpuid_level >= 0x16) + { + __cpuid( regs, 0x16 ); /* eax is base freq in MHz */ + freq = regs[0] * (UINT64)1000000; + } + else freq = 0; + } + + if (!freq) WARN( "Failed to read TSC frequency from CPUID, falling back to calibration.\n" ); + else TRACE( "TSC frequency read from CPUID, found %I64u Hz\n", freq ); + } +#endif + + if (freq == 0) + { + LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; + unsigned int aux; + UINT retries = 50; + int regs[4]; + + do + { + if (has_rdtscp) + { + tsc0 = __rdtscp( &aux ); + time0 = RtlGetSystemTimePrecise(); + tsc1 = __rdtscp( &aux ); + Sleep( 1 ); + tsc2 = __rdtscp( &aux ); + time1 = RtlGetSystemTimePrecise(); + tsc3 = __rdtscp( &aux ); + } + else + { + tsc0 = __rdtsc(); __cpuid( regs, 0 ); + time0 = RtlGetSystemTimePrecise(); + tsc1 = __rdtsc(); __cpuid( regs, 0 ); + Sleep(1); + tsc2 = __rdtsc(); __cpuid( regs, 0 ); + time1 = RtlGetSystemTimePrecise(); + tsc3 = __rdtsc(); __cpuid( regs, 0 ); + } + + freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); + freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); + error = llabs( (freq1 - freq0) * 1000000 / min( freq1, freq0 ) ); + } + while (error > 100 && --retries); + + if (!retries) WARN( "TSC frequency calibration failed, unstable TSC?\n" ); + else + { + freq = (freq0 + freq1) / 2; + TRACE( "TSC frequency calibration complete, found %I64u Hz\n", freq ); + } + } + + return freq; +} + +static BOOL is_tsc_trusted_by_the_kernel(void) +{ + char buf[4] = {}; + DWORD num_read; + HANDLE handle; + BOOL ret = TRUE; + + handle = CreateFileA( "\\??\\unix\\sys\\bus\\clocksource\\devices\\clocksource0\\current_clocksource", + GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) return TRUE; + + if (ReadFile( handle, buf, sizeof(buf) - 1, &num_read, NULL ) && strcmp( "tsc", buf )) + ret = FALSE; + + CloseHandle( handle ); + return ret; +} + +static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency ) +{ + BOOL has_rdtscp = FALSE; + int regs[4]; + + data->QpcBypassEnabled = 0; + data->QpcFrequency = TICKSPERSEC; + data->QpcShift = 0; + data->QpcBias = 0; + *tsc_frequency = 0; + + if (!is_tsc_trusted_by_the_kernel()) + { + WARN( "Failed to compute TSC frequency, not trusted by the kernel.\n" ); + return; + } + + if (!data->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE]) + { + WARN( "Failed to compute TSC frequency, RDTSC instruction not supported.\n" ); + return; + } + + __cpuid( regs, 0x80000000 ); + if (regs[0] < 0x80000007) + { + WARN( "Failed to compute TSC frequency, unable to check invariant TSC.\n" ); + return; + } + + /* check for invariant tsc bit */ + __cpuid( regs, 0x80000007 ); + if (!(regs[3] & (1 << 8))) + { + WARN( "Failed to compute TSC frequency, no invariant TSC.\n" ); + return; + } + + /* check for rdtscp support bit */ + __cpuid( regs, 0x80000001 ); + if ((regs[3] & (1 << 27))) has_rdtscp = TRUE; + + *tsc_frequency = read_tsc_frequency( has_rdtscp ); +} + #else static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) { } +static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency ) +{ + data->QpcBypassEnabled = 0; + data->QpcFrequency = TICKSPERSEC; + data->QpcShift = 0; + data->QpcBias = 0; + *tsc_frequency = 0; +} + #endif -static void create_user_shared_data(void) +static void create_user_shared_data( UINT64 *tsc_frequency ) { struct _KUSER_SHARED_DATA *data; RTL_OSVERSIONINFOEXW version; @@ -337,6 +497,7 @@ static void create_user_shared_data(void) data->ActiveGroupCount = 1; initialize_xstate_features( data ); + initialize_qpc_features( data, tsc_frequency ); UnmapViewOfFile( data ); } @@ -648,7 +809,7 @@ static void create_bios_key( HKEY system_key ) } /* create the volatile hardware registry keys */ -static void create_hardware_registry_keys(void) +static void create_hardware_registry_keys( UINT64 tsc_frequency ) { unsigned int i; HKEY hkey, system_key, cpu_key, fpu_key; @@ -723,12 +884,15 @@ static void create_hardware_registry_keys(void) if (!RegCreateKeyExW( cpu_key, numW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL )) { + DWORD tsc_freq_mhz = (DWORD)(tsc_frequency / 1000000ull); /* Hz -> Mhz */ + if (!tsc_freq_mhz) tsc_freq_mhz = power_info[i].MaxMhz; + RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.ProcessorFeatureBits, sizeof(DWORD) ); set_reg_value( hkey, L"Identifier", id ); /* TODO: report ARM properly */ set_reg_value( hkey, L"ProcessorNameString", namestr ); set_reg_value( hkey, L"VendorIdentifier", vendorid ); - RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&power_info[i].MaxMhz, sizeof(DWORD) ); + RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&tsc_freq_mhz, sizeof(DWORD) ); RegCloseKey( hkey ); } if (sci.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ARM && @@ -1659,6 +1823,7 @@ int __cdecl main( int argc, char *argv[] ) BOOL end_session, force, init, kill, restart, shutdown, update; HANDLE event; OBJECT_ATTRIBUTES attr; + UINT64 tsc_frequency = 0; UNICODE_STRING nameW; BOOL is_wow64; @@ -1745,8 +1910,8 @@ int __cdecl main( int argc, char *argv[] ) ResetEvent( event ); /* in case this is a restart */ - create_user_shared_data(); - create_hardware_registry_keys(); + create_user_shared_data( &tsc_frequency ); + create_hardware_registry_keys( tsc_frequency ); create_dynamic_registry_keys(); create_environment_registry_keys(); create_computer_name_keys(); From 73b6bfa15b2b70ada5c1202dcaa63f67143cc30d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 21 Jun 2021 21:33:09 +0200 Subject: [PATCH 68/83] tools: Add gdbinit helper with LoadSymbolFiles command. To help gdb reload symbol files from /proc//maps, making it possible to load debug info for ELF and PE modules for Wine processes. When sourced (from ~/.gdbinit for instance), this adds a new "load-symbol-files" command (with an "lsf" alias), which automatically calls add-symbol-file on every mapped file that can be read as ELF or PE, with the correct section offset. The command has to be run manually, for instance after executing for a while, to load new modules that may have been loaded, as there's no way for gdb to be notified of such changes automatically. --- tools/Makefile.in | 1 + tools/gdbinit.py | 113 ++++++++++++++++++++++++++++++++++++++++++++ tools/gdbinit.py.in | 1 + 3 files changed, 115 insertions(+) create mode 100644 tools/gdbinit.py create mode 120000 tools/gdbinit.py.in diff --git a/tools/Makefile.in b/tools/Makefile.in index adf53bb2c51..ff2da5e8584 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -5,4 +5,5 @@ C_SRCS = \ make_xftmpl.c IN_SRCS = \ + gdbinit.py.in \ wineapploader.in diff --git a/tools/gdbinit.py b/tools/gdbinit.py new file mode 100644 index 00000000000..ba3b7d003ac --- /dev/null +++ b/tools/gdbinit.py @@ -0,0 +1,113 @@ +#!/bin/env python3 + +# Copyright 2021 Rémi Bernon for CodeWeavers +# +# 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 + +from __future__ import print_function + +import gdb +import re +import subprocess +import sys + +class LoadSymbolFiles(gdb.Command): + 'Command to load symbol files directly from /proc//maps.' + + def __init__(self): + sup = super(LoadSymbolFiles, self) + sup.__init__('load-symbol-files', gdb.COMMAND_FILES, gdb.COMPLETE_NONE, + False) + + self.libs = {} + gdb.execute('alias -a lsf = load-symbol-files', True) + + def invoke(self, arg, from_tty): + pid = gdb.selected_inferior().pid + if not pid in self.libs: self.libs[pid] = {} + + def command(cmd, confirm=from_tty, to_string=not from_tty): + gdb.execute(cmd, from_tty=confirm, to_string=to_string) + + def execute(cmd): + return subprocess.check_output(cmd, stderr=subprocess.STDOUT) \ + .decode('utf-8') + + # load mappings addresses + libs = {} + with open('/proc/{}/maps'.format(pid), 'r') as maps: + for line in maps: + addr, _, _, _, node, path = re.split(r'\s+', line, 5) + path = path.strip() + if node == '0': continue + if path in libs: continue + libs[path] = int(addr.split('-')[0], 16) + + # unload symbol file if address changed + for k in set(libs) & set(self.libs[pid]): + if libs[k] != self.libs[pid][k]: + command('remove-symbol-file "{}"'.format(k), confirm=False) + del self.libs[k] + + # load symbol file for new mappings + for k in set(libs) - set(self.libs[pid]): + if arg is not None and re.search(arg, k) is None: continue + addr = self.libs[pid][k] = libs[k] + has_debug = False + offs = None + + try: + out = execute(['file', k]) + except: + continue + + # try loading mapping as ELF + try: + out = execute(['readelf', '-l', k]) + for line in out.split('\n'): + if not 'LOAD' in line: continue + base = int(line.split()[2], 16) + break + except: + # assume mapping is PE + base = -1 + + try: + name = None + cmd = 'add-symbol-file "{}"'.format(k) + out = execute(['objdump', '-h', k]) + for line in out.split('\n'): + if '2**' in line: + _, name, _, vma, _, off, _ = line.split(maxsplit=6) + if base < 0: offs = int(off, 16) + else: offs = int(vma, 16) - base + if 'ALLOC' in line: + cmd += ' -s {} 0x{:x}'.format(name, addr + offs) + elif name in ['.gnu_debuglink', '.debug_info']: + has_debug = True + elif 'DEBUGGING' in line: + has_debug = True + except: + continue + + if not has_debug: + print('no debugging info found in {}'.format(k)) + continue + + print('loading symbols for {}'.format(k)) + command(cmd, confirm=False, to_string=True) + + +LoadSymbolFiles() diff --git a/tools/gdbinit.py.in b/tools/gdbinit.py.in new file mode 120000 index 00000000000..9fb7fdf9b92 --- /dev/null +++ b/tools/gdbinit.py.in @@ -0,0 +1 @@ +gdbinit.py \ No newline at end of file From 3caf5bfc77d5e6f501a646c97738fdf74d7b650f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Wed, 20 Jan 2021 11:28:46 -0600 Subject: [PATCH 69/83] ntdll: Use clock_gettime64 if supported. --- dlls/ntdll/unix/sync.c | 50 +++++++++++++++++++++++++++++++++++++----- server/request.c | 50 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 90 insertions(+), 10 deletions(-) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index af0c53d441e..58b7502ef06 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -77,6 +77,46 @@ static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) return wine_dbgstr_longlong( timeout->QuadPart ); } +#ifndef __NR_clock_gettime64 +#define __NR_clock_gettime64 403 +#endif + +struct timespec64 +{ + long long tv_sec; + long long tv_nsec; +}; + +static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) +{ + static int clock_gettime64_supported = -1; + struct timespec64 ts64; + struct timespec ts; + int ret; + + if (clock_gettime64_supported < 0) + { + if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) + { + clock_gettime64_supported = 1; + *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; + return 0; + } + clock_gettime64_supported = 0; + } + + if (clock_gettime64_supported) + { + if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) + *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; + return ret; + } + + if (!(ret = clock_gettime( clock_id, &ts ))) + *ticks = ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; + return ret; +} + /* return a monotonic time counter, in Win32 ticks */ static inline ULONGLONG monotonic_counter(void) { @@ -91,13 +131,13 @@ static inline ULONGLONG monotonic_counter(void) #endif return mach_absolute_time() * timebase.numer / timebase.denom / 100; #elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; + ULONGLONG ticks; #if 0 - if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) - return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; + if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) + return ticks; #endif - if (!clock_gettime( CLOCK_MONOTONIC, &ts )) - return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; + if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) + return ticks; #endif gettimeofday( &now, 0 ); return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10 - server_start_time; diff --git a/server/request.c b/server/request.c index 6e1820313d1..a1d646f9643 100644 --- a/server/request.c +++ b/server/request.c @@ -519,6 +519,46 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) return -1; } +#ifndef __NR_clock_gettime64 +#define __NR_clock_gettime64 403 +#endif + +struct timespec64 +{ + long long tv_sec; + long long tv_nsec; +}; + +static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) +{ + static int clock_gettime64_supported = -1; + struct timespec64 ts64; + struct timespec ts; + int ret; + + if (clock_gettime64_supported < 0) + { + if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) + { + clock_gettime64_supported = 1; + *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; + return 0; + } + clock_gettime64_supported = 0; + } + + if (clock_gettime64_supported) + { + if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) + *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; + return ret; + } + + if (!(ret = clock_gettime( clock_id, &ts ))) + *ticks = ts.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts.tv_nsec / 100; + return ret; +} + /* return a monotonic time counter */ timeout_t monotonic_counter(void) { @@ -532,13 +572,13 @@ timeout_t monotonic_counter(void) #endif return mach_absolute_time() * timebase.numer / timebase.denom / 100; #elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; + ULONGLONG ticks; #if 0 - if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) - return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; + if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) + return ticks; #endif - if (!clock_gettime( CLOCK_MONOTONIC, &ts )) - return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; + if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) + return ticks; #endif return current_time - server_start_time; } From 012b37848dacee565e0d0d4c5b38279d8da626e9 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 11 Feb 2022 16:35:11 -0600 Subject: [PATCH 70/83] winegstreamer: Use unlimited buffering for DirectShow as well. Normally this isn't necessary, because DirectShow sends all samples as soon as they are available. However, decodebin won't expose pads until it has a sample (or theoradec won't send a caps event until it has a sample?), and some transcoded videos somehow don't have a sample within the first 2 MB, i.e. the default limit. Two examples are Bloodstained: Ritual of the Night (CW bug 18550), which is a Media Foundation game, and Melty Blood: Type Lumina (CW bug 20149), which is a DirectShow game. To account for the latter we need to raise buffering limits. [Note: a similar commit was in 6.3 with the note that it helped performance in Worms Revolution and Blazblue Centralfiction. Is this still true?] CW-Bug-Id: #20149 CW-Bug-Id: #18550 --- dlls/winegstreamer/quartz_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index a7fc3b8ebf5..54aa15cffac 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1183,7 +1183,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true, false))) { free(object); return E_OUTOFMEMORY; From 20b18413df7164f98136dd9d06214306da153b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:21:29 +0100 Subject: [PATCH 71/83] user32: Prevent a recursive loop with the activation messages. When activating a window and sending activation messages to the window procedure, Windows avoids a recursive loop by not sending more of these messages or hooks while it's still activating the window. CW-Bug-Id: #19612 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46274 --- dlls/user32/focus.c | 21 ++++++++++++++------- dlls/user32/win.h | 1 + 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index 2afe5667a04..976f57f04b2 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -90,7 +90,7 @@ static HWND set_focus_window( HWND hwnd, BOOL from_active ) static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) { HWND previous = GetActiveWindow(); - BOOL ret; + BOOL ret = FALSE; DWORD old_thread, new_thread; CBTACTIVATESTRUCT cbt; @@ -100,10 +100,13 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) return TRUE; } + if (prev) *prev = previous; + if (win_set_flags( hwnd, WIN_IS_ACTIVATING, 0 ) & WIN_IS_ACTIVATING) return TRUE; + /* call CBT hook chain */ cbt.fMouse = mouse; cbt.hWndActive = previous; - if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) return FALSE; + if (HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hwnd, (LPARAM)&cbt, TRUE )) goto done; if (IsWindow(previous)) { @@ -119,9 +122,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) previous = wine_server_ptr_handle( reply->previous ); } SERVER_END_REQ; - if (!ret) return FALSE; + if (!ret) goto done; if (prev) *prev = previous; - if (previous == hwnd) return TRUE; + if (previous == hwnd) goto done; if (hwnd) { @@ -129,7 +132,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (SendMessageW( hwnd, WM_QUERYNEWPALETTE, 0, 0 )) SendMessageTimeoutW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hwnd, 0, SMTO_ABORTIFHUNG, 2000, NULL ); - if (!IsWindow(hwnd)) return FALSE; + if (!(ret = IsWindow( hwnd ))) goto done; } old_thread = previous ? GetWindowThreadProcessId( previous, NULL ) : 0; @@ -163,7 +166,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (IsWindow(hwnd)) { - SendMessageW( hwnd, WM_NCACTIVATE, (hwnd == GetForegroundWindow()), (LPARAM)previous ); + SendMessageW( hwnd, WM_NCACTIVATE, + (hwnd == GetForegroundWindow()) && !(win_get_flags(previous) & WIN_IS_ACTIVATING), + (LPARAM)previous ); SendMessageW( hwnd, WM_ACTIVATE, MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, IsIconic(hwnd) ), (LPARAM)previous ); @@ -192,7 +197,9 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) } } - return TRUE; +done: + win_set_flags( hwnd, 0, WIN_IS_ACTIVATING ); + return ret; } diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 45d3acce7bc..4e9dc9efd38 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -80,6 +80,7 @@ typedef struct tagWND #define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */ #define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */ #define WIN_IS_TOUCH 0x0100 /* the window has been registered for touch input */ +#define WIN_IS_ACTIVATING 0x0200 /* the window is being activated */ /* Window functions */ extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN; From 39d4caba1649dc2f853afc1b275b3656eee38b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:23:08 +0100 Subject: [PATCH 72/83] user32: Use PostMessageW in set_foreground_window. Instead of SendNotifyMessageW for WM_WINE_SETACTIVEWINDOW. CW-Bug-Id: #19612 --- dlls/user32/focus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index 976f57f04b2..f23046a3ea3 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -226,12 +226,12 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) if (ret && previous != hwnd) { if (send_msg_old) /* old window belongs to other thread */ - SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 ); + PostMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 ); else if (send_msg_new) /* old window belongs to us but new one to other thread */ ret = set_active_window( 0, NULL, mouse, TRUE ); if (send_msg_new) /* new window belongs to other thread */ - SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); + PostMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ ret = set_active_window( hwnd, NULL, mouse, TRUE ); } From 082c9751c7e51cd397bab2857912e24d065234b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:24:02 +0100 Subject: [PATCH 73/83] user32: Do not deactivate if thread is foreground. Instead of only checking that the window is foreground. CW-Bug-Id: #19612 --- dlls/user32/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 183912cd653..988ef999edb 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -1876,7 +1876,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR if (is_desktop_window( hwnd )) return 0; return WIN_SetStyle(hwnd, wparam, lparam); case WM_WINE_SETACTIVEWINDOW: - if (!wparam && GetForegroundWindow() == hwnd) return 0; + if (!wparam && GetWindowThreadProcessId( GetForegroundWindow(), NULL ) == GetCurrentThreadId()) + return 0; return (LRESULT)SetActiveWindow( (HWND)wparam ); case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: From c42b365e33ec1c3c1e2e2f5980ff3ebb8f1d739b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:24:57 +0100 Subject: [PATCH 74/83] user32: Send WM_NCACTIVATE on SetForegroundWindow call. When window is already active but has lost foreground, as shown by concurrent SetForegroundWindow tests. CW-Bug-Id: #19612 --- dlls/user32/focus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f23046a3ea3..f658c7f5aa3 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -230,6 +230,10 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse ) else if (send_msg_new) /* old window belongs to us but new one to other thread */ ret = set_active_window( 0, NULL, mouse, TRUE ); + /* already active, set_active_window will do no nothing */ + if (!send_msg_new && hwnd == GetActiveWindow()) + SendMessageW( hwnd, WM_NCACTIVATE, TRUE, (LPARAM)hwnd ); + if (send_msg_new) /* new window belongs to other thread */ PostMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 ); else /* new window belongs to us */ From 513022b844b909fce8134a8b8a9ecab38414f5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:25:44 +0100 Subject: [PATCH 75/83] user32: Send WM_*FOCUS messages even if already focused. CW-Bug-Id: #19612 --- dlls/user32/focus.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f658c7f5aa3..cb59b78577a 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -40,7 +40,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); * * Change the focus window, sending the WM_SETFOCUS and WM_KILLFOCUS messages */ -static HWND set_focus_window( HWND hwnd, BOOL from_active ) +static HWND set_focus_window( HWND hwnd, BOOL from_active, BOOL force ) { HWND previous = 0, ime_default; BOOL ret; @@ -53,7 +53,7 @@ static HWND set_focus_window( HWND hwnd, BOOL from_active ) } SERVER_END_REQ; if (!ret) return 0; - if (previous == hwnd) return previous; + if (!force && hwnd == previous) return previous; if (previous) { @@ -193,7 +193,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (hwnd == info.hwndActive) { if (!info.hwndFocus || !hwnd || GetAncestor( info.hwndFocus, GA_ROOT ) != hwnd) - set_focus_window( hwnd, TRUE ); + set_focus_window( hwnd, TRUE, FALSE ); } } @@ -340,7 +340,7 @@ HWND WINAPI SetFocus( HWND hwnd ) } /* change focus and send messages */ - return set_focus_window( hwnd, FALSE ); + return set_focus_window( hwnd, FALSE, hwnd != previous ); } From b3213cb9e516e989fe601851912a17fc7c4f37a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Thu, 27 Jan 2022 18:26:41 +0100 Subject: [PATCH 76/83] server: Drop pending internal messages in set_active_window. When changing the active window in the foreground thread. CW-Bug-Id: #19612 --- dlls/user32/focus.c | 1 + server/protocol.def | 1 + server/queue.c | 12 ++++++++++++ 3 files changed, 14 insertions(+) diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index cb59b78577a..f081c4b7ee6 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -118,6 +118,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) SERVER_START_REQ( set_active_window ) { req->handle = wine_server_user_handle( hwnd ); + req->internal_msg = WM_WINE_SETACTIVEWINDOW; if ((ret = !wine_server_call_err( req ))) previous = wine_server_ptr_handle( reply->previous ); } diff --git a/server/protocol.def b/server/protocol.def index fbf8a017cd0..4dca9ee3f45 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2821,6 +2821,7 @@ enum coords_relative /* Set the current thread active window */ @REQ(set_active_window) user_handle_t handle; /* handle to the active window */ + unsigned int internal_msg; /* set active window internal message */ @REPLY user_handle_t previous; /* handle to the previous active window */ @END diff --git a/server/queue.c b/server/queue.c index 15c46aea3ab..b07dceb2043 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3503,7 +3503,11 @@ DECL_HANDLER(set_focus_window) /* set the current thread active window */ DECL_HANDLER(set_active_window) { + struct message *msg, *next; struct msg_queue *queue = get_current_queue(); + struct desktop *desktop; + + if (!(desktop = get_thread_desktop( current, 0 ))) return; reply->previous = 0; if (queue && check_queue_input_window( queue, req->handle )) @@ -3514,9 +3518,17 @@ DECL_HANDLER(set_active_window) SHARED_WRITE_BEGIN( &queue->input->shared->seq ); queue->input->shared->active = get_user_full_handle( req->handle ); SHARED_WRITE_END( &queue->input->shared->seq ); + + if (desktop->foreground_input == queue->input && req->handle != reply->previous) + { + LIST_FOR_EACH_ENTRY_SAFE( msg, next, &queue->msg_list[POST_MESSAGE], struct message, entry ) + if (msg->msg == req->internal_msg) remove_queue_message( queue, msg, POST_MESSAGE ); + } } else set_error( STATUS_INVALID_HANDLE ); } + + release_object( desktop ); } From 443b7ac209345bbd4c75ab5913d25a5f12cf090f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:24:24 +0100 Subject: [PATCH 77/83] Revert "winegstreamer: Avoid input buffer copy in audio converter" This reverts commit fbea0b362abed4879528bb189011b4ae01f83b76. --- dlls/winegstreamer/audioconvert.c | 34 +++++++++---------------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index 5cd5ba52923..bfc94f69891 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -35,8 +35,7 @@ struct audio_converter IMFMediaType *input_type; IMFMediaType *output_type; CRITICAL_SECTION cs; - IMFSample *inflight_sample; - IMFMediaBuffer *inflight_buffer; + BOOL buffer_inflight; LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; @@ -143,7 +142,7 @@ static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DW if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES; + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; info->cbMaxLookahead = 0; info->cbAlignment = 0; info->hnsMaxLatency = 0; @@ -632,7 +631,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME case MFT_MESSAGE_COMMAND_FLUSH: { EnterCriticalSection(&converter->cs); - if (!converter->inflight_sample) + if (!converter->buffer_inflight) { LeaveCriticalSection(&converter->cs); return S_OK; @@ -642,11 +641,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME wg_parser_stream_get_event(converter->stream, &event); wg_parser_stream_release_buffer(converter->stream, NULL); - IMFMediaBuffer_Unlock(converter->inflight_buffer); - IMFMediaBuffer_Release(converter->inflight_buffer); - converter->inflight_buffer = NULL; - IMFSample_Release(converter->inflight_sample); - converter->inflight_sample = NULL; + converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); return S_OK; @@ -685,7 +680,7 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - if (converter->inflight_sample) + if (converter->buffer_inflight) { hr = MF_E_NOTACCEPTING; goto done; @@ -704,21 +699,16 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, false); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); - IMFSample_AddRef(sample); - converter->inflight_sample = sample; - converter->inflight_buffer = buffer; + IMFMediaBuffer_Unlock(buffer); + converter->buffer_inflight = TRUE; if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) converter->buffer_pts = -1; if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) converter->buffer_dur = -1; - sample = NULL; - buffer = NULL; done: - if (sample) - IMFSample_Release(sample); if (buffer) IMFMediaBuffer_Release(buffer); LeaveCriticalSection(&converter->cs); @@ -761,7 +751,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!converter->inflight_sample) + if (!converter->buffer_inflight) { hr = MF_E_TRANSFORM_NEED_MORE_INPUT; goto done; @@ -896,11 +886,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f samples[0].pSample = allocated_sample; } - IMFMediaBuffer_Unlock(converter->inflight_buffer); - IMFMediaBuffer_Release(converter->inflight_buffer); - converter->inflight_buffer = NULL; - IMFSample_Release(converter->inflight_sample); - converter->inflight_sample = NULL; + converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); From a9559c1832189df7ca460258228a4a609d79b5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:24:25 +0100 Subject: [PATCH 78/83] Revert "winegstreamer: Return MFMediaBuffer-backed memory directly to audio converter client" This reverts commit 704b64341d08f16cdce148ad15d7040c0ebfdb25. --- dlls/winegstreamer/audioconvert.c | 148 ++++++++++-------------------- dlls/winegstreamer/wg_parser.c | 8 -- 2 files changed, 48 insertions(+), 108 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index bfc94f69891..e3514d03ddb 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -39,8 +39,6 @@ struct audio_converter LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; - HANDLE read_thread, alloc_thread; - struct allocator_thread_data alloc_thread_data; IMFAttributes *attributes, *output_attributes; }; @@ -93,11 +91,6 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) IMFAttributes_Release(transform->output_attributes); if (transform->stream) wg_parser_disconnect(transform->parser); - - transform->alloc_thread_data.done = true; - WaitForSingleObject(transform->alloc_thread, INFINITE); - CloseHandle(transform->alloc_thread); - if (transform->parser) wg_parser_destroy(transform->parser); free(transform); @@ -725,8 +718,6 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f unsigned char *buffer_data; DWORD buffer_len; void *gstcookie; - struct wg_mf_buffer *ourbuf; - uint32_t offset; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -776,116 +767,78 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f break; } - wg_parser_stream_retrieve_buffer(converter->stream, (void **)&ourbuf, &offset, &gstcookie); - if (samples[0].pSample || !ourbuf) + if (!samples[0].pSample) { - TRACE("slow path: %u bytes\n", event.u.buffer.size); - - if (samples[0].pSample) - { - if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) - { - ERR("Failed to get buffer from sample, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) - { - ERR("Failed to get buffer size, hr %#x.\n", hr); - goto done; - } - - if (buffer_len < event.u.buffer.size) - { - WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", - buffer_len, event.u.buffer.size); - - hr = MF_E_BUFFERTOOSMALL; - goto done; - } - } - else - { - if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) - { - ERR("Failed to create buffer, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = MFCreateSample(&allocated_sample))) - { - ERR("Failed to create sample, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) - { - ERR("Failed to add buffer, hr %#x.\n", hr); - goto done; - } - - samples[0].pSample = allocated_sample; - } - - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) { - ERR("Failed to set size, hr %#x.\n", hr); + ERR("Failed to create buffer, hr %#x.\n", hr); goto done; } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + if (FAILED(hr = MFCreateSample(&allocated_sample))) { - ERR("Failed to lock buffer hr %#x.\n", hr); + ERR("Failed to create sample, hr %#x.\n", hr); goto done; } - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + samples[0].pSample = allocated_sample; + + if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) { - ERR("Failed to copy buffer.\n"); - IMFMediaBuffer_Unlock(buffer); - hr = E_FAIL; + ERR("Failed to add buffer, hr %#x.\n", hr); goto done; } - IMFMediaBuffer_Unlock(buffer); IMFMediaBuffer_Release(buffer); buffer = NULL; + } - wg_parser_stream_release_buffer(converter->stream, gstcookie); + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) + { + ERR("Failed to get buffer from sample, hr %#x.\n", hr); + goto done; } - else + + if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) { - TRACE("fast path\n"); + ERR("Failed to get buffer size, hr %#x.\n", hr); + goto done; + } - ourbuf->gstcookie = gstcookie; - ourbuf->wg_stream = converter->stream; - ourbuf->offset = offset; + if (buffer_len < event.u.buffer.size) + { + WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", + buffer_len, event.u.buffer.size); - buffer = &ourbuf->IMFMediaBuffer_iface; - IMFMediaBuffer_AddRef(buffer); - assert(ourbuf->refcount == 2); + hr = MF_E_BUFFERTOOSMALL; + goto done; + } - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = MFCreateSample(&allocated_sample))) - { - ERR("Failed to create sample, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + { + ERR("Failed to lock buffer hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) - { - ERR("Failed to add buffer, hr %#x.\n", hr); - goto done; - } + wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); - samples[0].pSample = allocated_sample; + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + { + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); + hr = E_FAIL; + goto done; } + IMFMediaBuffer_Unlock(buffer); + + wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) @@ -899,7 +852,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f done: if (buffer) IMFMediaBuffer_Release(buffer); - if (FAILED(hr) && allocated_sample) + if (allocated_sample && FAILED(hr)) { IMFSample_Release(allocated_sample); samples[0].pSample = NULL; @@ -966,18 +919,13 @@ HRESULT audio_converter_create(REFIID riid, void **ret) return hr; } - if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, true))) + if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, false))) { ERR("Failed to create audio converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); return E_OUTOFMEMORY; } - object->alloc_thread_data.done = FALSE; - object->alloc_thread_data.wg_parser = object->parser; - object->alloc_thread_data.log_pfx = "audio_converter"; - object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); - *ret = &object->IMFTransform_iface; return S_OK; } diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 337953db78d..068d52daefd 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2613,14 +2613,6 @@ static BOOL audio_convert_init_gst(struct wg_parser *parser) if (parser->input_format.major_type != WG_MAJOR_TYPE_AUDIO) return FALSE; - if (parser->use_wine_allocator) - { - WineMemoryAllocator *alloc; - parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); - alloc = (WineMemoryAllocator *)parser->allocator; - alloc->parser = parser; - } - if (!(convert = create_element("audioconvert", "base"))) return FALSE; From 098076a66243bc756dec6317b36968bd7403cecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:24:25 +0100 Subject: [PATCH 79/83] Revert "winegstreamer: Avoid input buffer copy in colorconvert" This reverts commit 4e4a7ee0f569f630b64f53d597eb3eda4ed8af20. --- dlls/winegstreamer/audioconvert.c | 2 +- dlls/winegstreamer/colorconvert.c | 34 ++++++++------------------- dlls/winegstreamer/decode_transform.c | 8 +++---- dlls/winegstreamer/gst_private.h | 2 +- dlls/winegstreamer/main.c | 3 +-- dlls/winegstreamer/media_source.c | 4 ++-- dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/unixlib.h | 1 - dlls/winegstreamer/wg_parser.c | 21 ++++------------- dlls/winegstreamer/wm_reader.c | 8 +++---- 10 files changed, 29 insertions(+), 56 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index e3514d03ddb..9e7d8288edc 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -692,7 +692,7 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size); IMFMediaBuffer_Unlock(buffer); converter->buffer_inflight = TRUE; diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index 11199759488..4455a12bb34 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -51,8 +51,7 @@ struct color_converter IMFMediaType *input_type; IMFMediaType *output_type; CRITICAL_SECTION cs; - IMFSample *inflight_sample; - IMFMediaBuffer *inflight_buffer; + BOOL buffer_inflight; LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; @@ -158,7 +157,7 @@ static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DW if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; + info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; info->cbMaxLookahead = 0; info->cbAlignment = 0; info->hnsMaxLatency = 0; @@ -628,7 +627,7 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME case MFT_MESSAGE_COMMAND_FLUSH: { EnterCriticalSection(&converter->cs); - if (!converter->inflight_sample) + if (!converter->buffer_inflight) { LeaveCriticalSection(&converter->cs); return S_OK; @@ -638,11 +637,7 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME wg_parser_stream_get_event(converter->stream, &event); wg_parser_stream_release_buffer(converter->stream, NULL); - IMFMediaBuffer_Unlock(converter->inflight_buffer); - IMFMediaBuffer_Release(converter->inflight_buffer); - converter->inflight_buffer = NULL; - IMFSample_Release(converter->inflight_sample); - converter->inflight_sample = NULL; + converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); return S_OK; @@ -681,7 +676,7 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id goto done; } - if (converter->inflight_sample) + if (converter->buffer_inflight) { hr = MF_E_NOTACCEPTING; goto done; @@ -701,7 +696,7 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id continue; } - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size), false); + wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); if (buffer_size <= size) break; @@ -710,19 +705,14 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id buffer_size -= size; } - IMFSample_AddRef(sample); - converter->inflight_sample = sample; - converter->inflight_buffer = buffer; + IMFMediaBuffer_Unlock(buffer); + converter->buffer_inflight = TRUE; if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) converter->buffer_pts = -1; if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) converter->buffer_dur = -1; - sample = NULL; - buffer = NULL; done: - if (sample) - IMFSample_Release(sample); if (buffer) IMFMediaBuffer_Release(buffer); LeaveCriticalSection(&converter->cs); @@ -765,7 +755,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - if (!converter->inflight_sample) + if (!converter->buffer_inflight) { hr = MF_E_TRANSFORM_NEED_MORE_INPUT; goto done; @@ -900,11 +890,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f samples[0].pSample = allocated_sample; } - IMFMediaBuffer_Unlock(converter->inflight_buffer); - IMFMediaBuffer_Release(converter->inflight_buffer); - converter->inflight_buffer = NULL; - IMFSample_Release(converter->inflight_sample); - converter->inflight_sample = NULL; + converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index 8114c25af9c..117c8042d93 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -804,7 +804,7 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE pip_event = get_pipeline_event(decoder); assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); - wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0, true); + wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0); EnterCriticalSection(&decoder->event_cs); decoder->event.type = PIPELINE_EVENT_NONE; @@ -829,7 +829,7 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE pip_event = get_pipeline_event(decoder); assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); - wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0, true); + wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0); EnterCriticalSection(&decoder->event_cs); decoder->event.type = PIPELINE_EVENT_NONE; @@ -929,13 +929,13 @@ static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMF if (offset != decoder->offset_tracker) { ERR("A seek is needed, MFTs don't support this!\n"); - wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0, true); + wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0); IMFMediaBuffer_Unlock(buffer); hr = E_FAIL; goto done; } - wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size, true); + wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size); decoder->offset_tracker += copy_size; diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index f4f2bf715f5..aa9564eaff9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -76,7 +76,7 @@ void wg_parser_begin_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; -void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size, bool need_copy) DECLSPEC_HIDDEN; +void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) DECLSPEC_HIDDEN; bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, DWORD *size, DWORD *align, void **user) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index fd1403396ba..2fbf2dc2d78 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -339,7 +339,7 @@ bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, return true; } -void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size, bool need_copy) +void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) { struct wg_parser_push_data_params params = { @@ -347,7 +347,6 @@ void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, c .result = result, .data = data, .size = size, - .need_copy = need_copy, }; __wine_unix_call(unix_handle, unix_wg_parser_push_data, ¶ms); diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 8ea40dd8b1a..9bd85dd6c57 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -676,7 +676,7 @@ static DWORD CALLBACK read_thread(void *arg) * an error when reading past the file size. */ if (!size) { - wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0, true); + wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0); continue; } @@ -694,7 +694,7 @@ static DWORD CALLBACK read_thread(void *arg) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); else if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size, true); + wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size); } free(data); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 54aa15cffac..5ebda720eef 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -885,7 +885,7 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size, true); + wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size); } free(data); diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 0ad9134c495..707bfe65c0b 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -246,7 +246,6 @@ struct wg_parser_push_data_params enum wg_read_result result; const void *data; UINT32 size; - bool need_copy; }; struct wg_parser_get_stream_count_params diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 068d52daefd..b8096148028 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -651,22 +651,11 @@ static NTSTATUS wg_parser_push_data(void *args) /* Note that we don't allocate the buffer until we have a size. * midiparse passes a NULL buffer and a size of UINT_MAX, in an * apparent attempt to read the whole input stream at once. */ - if (parser->read_request.buffer || params->need_copy) - { - GST_DEBUG("slow path: %u bytes", size); - if (!parser->read_request.buffer) - parser->read_request.buffer = gst_buffer_new_and_alloc(size); - gst_buffer_map(parser->read_request.buffer, &map_info, GST_MAP_WRITE); - memcpy(map_info.data, data, size); - gst_buffer_unmap(parser->read_request.buffer, &map_info); - } - else - { - GST_DEBUG("fast path"); - parser->read_request.buffer = gst_buffer_new_wrapped_full( - GST_MEMORY_FLAG_READONLY, (void*)data, size, 0, size, NULL, NULL); - } - + if (!parser->read_request.buffer) + parser->read_request.buffer = gst_buffer_new_and_alloc(size); + gst_buffer_map(parser->read_request.buffer, &map_info, GST_MAP_WRITE); + memcpy(map_info.data, data, size); + gst_buffer_unmap(parser->read_request.buffer, &map_info); parser->read_request.ret = GST_FLOW_OK; } else diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index ebe1ca4b57c..1e088803b8f 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -573,7 +573,7 @@ static DWORD CALLBACK read_thread(void *arg) if (!size) { - wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0, true); + wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0); continue; } @@ -592,7 +592,7 @@ static DWORD CALLBACK read_thread(void *arg) || !ReadFile(file, data, size, &ret_size, NULL)) { ERR("Failed to read %u bytes at offset %I64u, error %u.\n", size, offset, GetLastError()); - wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0, true); + wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); continue; } } @@ -603,14 +603,14 @@ static DWORD CALLBACK read_thread(void *arg) if (FAILED(hr)) { ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0, true); + wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); continue; } } if (ret_size != size) ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size); - wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size, true); + wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size); } free(data); From 0db2a8c7011bc8fcd0f5516e21aec55e0ca0624e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:24:25 +0100 Subject: [PATCH 80/83] Revert "winegstreamer: Return MFMediaBuffer-backed memory directly to color converter client" This reverts commit f8c2c88736277c85304dc55e041c513bd7d38c15. --- dlls/winegstreamer/colorconvert.c | 146 ++++++++++-------------------- dlls/winegstreamer/gst_private.h | 1 - dlls/winegstreamer/main.c | 7 +- dlls/winegstreamer/media_source.c | 1 - dlls/winegstreamer/wg_parser.c | 8 -- 5 files changed, 49 insertions(+), 114 deletions(-) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index 4455a12bb34..b7e65131004 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -55,8 +55,6 @@ struct color_converter LONGLONG buffer_pts, buffer_dur; struct wg_parser *parser; struct wg_parser_stream *stream; - HANDLE read_thread, alloc_thread; - struct allocator_thread_data alloc_thread_data; }; static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) @@ -106,11 +104,6 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) IMFMediaType_Release(transform->output_type); if (transform->stream) wg_parser_disconnect(transform->parser); - - transform->alloc_thread_data.done = true; - WaitForSingleObject(transform->alloc_thread, INFINITE); - CloseHandle(transform->alloc_thread); - if (transform->parser) wg_parser_destroy(transform->parser); free(transform); @@ -729,8 +722,6 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f unsigned char *buffer_data; DWORD buffer_len; void *gstcookie; - struct wg_mf_buffer *ourbuf; - uint32_t offset; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -780,116 +771,78 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f break; } - wg_parser_stream_retrieve_buffer(converter->stream, (void **)&ourbuf, &offset, &gstcookie); - if (samples[0].pSample || !ourbuf) + if (!samples[0].pSample) { - TRACE("slow path: %u bytes\n", event.u.buffer.size); - - if (samples[0].pSample) - { - if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) - { - ERR("Failed to get buffer from sample, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) - { - ERR("Failed to get buffer size, hr %#x.\n", hr); - goto done; - } - - if (buffer_len < event.u.buffer.size) - { - WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", - buffer_len, event.u.buffer.size); - - hr = MF_E_BUFFERTOOSMALL; - goto done; - } - } - else - { - if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) - { - ERR("Failed to create buffer, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = MFCreateSample(&allocated_sample))) - { - ERR("Failed to create sample, hr %#x.\n", hr); - goto done; - } - - if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) - { - ERR("Failed to add buffer, hr %#x.\n", hr); - goto done; - } - - samples[0].pSample = allocated_sample; - } - - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) { - ERR("Failed to set size, hr %#x.\n", hr); + ERR("Failed to create buffer, hr %#x.\n", hr); goto done; } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + if (FAILED(hr = MFCreateSample(&allocated_sample))) { - ERR("Failed to lock buffer hr %#x.\n", hr); + ERR("Failed to create sample, hr %#x.\n", hr); goto done; } - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + samples[0].pSample = allocated_sample; + + if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) { - ERR("Failed to copy buffer.\n"); - IMFMediaBuffer_Unlock(buffer); - hr = E_FAIL; + ERR("Failed to add buffer, hr %#x.\n", hr); goto done; } - IMFMediaBuffer_Unlock(buffer); IMFMediaBuffer_Release(buffer); buffer = NULL; + } - wg_parser_stream_release_buffer(converter->stream, gstcookie); + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) + { + ERR("Failed to get buffer from sample, hr %#x.\n", hr); + goto done; } - else + + if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) { - TRACE("fast path\n"); + ERR("Failed to get buffer size, hr %#x.\n", hr); + goto done; + } - ourbuf->gstcookie = gstcookie; - ourbuf->wg_stream = converter->stream; - ourbuf->offset = offset; + if (buffer_len < event.u.buffer.size) + { + WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", + buffer_len, event.u.buffer.size); - buffer = &ourbuf->IMFMediaBuffer_iface; - IMFMediaBuffer_AddRef(buffer); - assert(ourbuf->refcount == 2); + hr = MF_E_BUFFERTOOSMALL; + goto done; + } - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = MFCreateSample(&allocated_sample))) - { - ERR("Failed to create sample, hr %#x.\n", hr); - goto done; - } + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) + { + ERR("Failed to lock buffer hr %#x.\n", hr); + goto done; + } - if (FAILED(hr = IMFSample_AddBuffer(allocated_sample, buffer))) - { - ERR("Failed to add buffer, hr %#x.\n", hr); - goto done; - } + wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); - samples[0].pSample = allocated_sample; + if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + { + ERR("Failed to copy buffer.\n"); + IMFMediaBuffer_Unlock(buffer); + hr = E_FAIL; + goto done; } + IMFMediaBuffer_Unlock(buffer); + + wg_parser_stream_release_buffer(converter->stream, gstcookie); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) @@ -957,18 +910,13 @@ HRESULT color_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, true))) + if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, false))) { ERR("Failed to create video converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); return E_OUTOFMEMORY; } - object->alloc_thread_data.done = FALSE; - object->alloc_thread_data.wg_parser = object->parser; - object->alloc_thread_data.log_pfx = "color_converter"; - object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); - *ret = &object->IMFTransform_iface; return S_OK; } diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index aa9564eaff9..0343c75a997 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -239,7 +239,6 @@ struct wg_mf_buffer struct allocator_thread_data { BOOL done; struct wg_parser *wg_parser; - const char *log_pfx; }; HANDLE start_allocator_thread(struct allocator_thread_data *) DECLSPEC_HIDDEN; diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2fbf2dc2d78..6c58f07205c 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -195,7 +195,7 @@ DWORD CALLBACK allocator_thread(void *arg) struct allocator_thread_data *data = arg; enum wg_parser_alloc_req_type type; - TRACE("%s: Starting alloc thread for parser %p.\n", data->log_pfx, data->wg_parser); + TRACE("Starting alloc thread for parser %p.\n", data->wg_parser); while (!data->done) { @@ -211,24 +211,21 @@ DWORD CALLBACK allocator_thread(void *arg) { struct wg_mf_buffer *buf = create_memory_buffer(size, align ? align : 1); wg_parser_provide_alloc_buffer(data->wg_parser, buf ? buf->data : NULL, buf); - TRACE("%s: Alloc req for %u bytes --> %p\n", data->log_pfx, size, buf); break; } case WG_PARSER_ALLOC_FREE: { struct wg_mf_buffer *buf = user; - TRACE("%s: Free req for %p\n", data->log_pfx, buf); IMFMediaBuffer_Release(&buf->IMFMediaBuffer_iface); wg_parser_provide_alloc_buffer(data->wg_parser, NULL, NULL); /* mark done */ break; } default: - FIXME("%s: Invalid alloc req?!\n", data->log_pfx); break; } } - TRACE("%s: Media source is shutting down; exiting alloc thread.\n", data->log_pfx); + TRACE("Media source is shutting down; exiting alloc thread.\n"); return 0; } diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 9bd85dd6c57..0f33e2b62a8 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -1489,7 +1489,6 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->alloc_thread_data.done = FALSE; object->alloc_thread_data.wg_parser = parser; - object->alloc_thread_data.log_pfx = "media_source"; object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); object->state = SOURCE_OPENING; diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index b8096148028..da9a63510c3 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -2662,14 +2662,6 @@ static BOOL video_convert_init_gst(struct wg_parser *parser) if (parser->input_format.major_type != WG_MAJOR_TYPE_VIDEO) return FALSE; - if (parser->use_wine_allocator) - { - WineMemoryAllocator *alloc; - parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); - alloc = (WineMemoryAllocator *)parser->allocator; - alloc->parser = parser; - } - if (!(convert = create_element("videoconvert", "base"))) return FALSE; From b1e9a55656a7f6d059fdf2b787029fd52091c13a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:24:25 +0100 Subject: [PATCH 81/83] Revert "winegstreamer: Return MFMediaBuffer-backed memory directly to media_source client" This reverts commit a71e8ba0ecfb89575930273d0c4dd179b7582dc6. --- dlls/winegstreamer/audioconvert.c | 9 +-- dlls/winegstreamer/colorconvert.c | 9 +-- dlls/winegstreamer/decode_transform.c | 7 +- dlls/winegstreamer/gst_private.h | 9 +-- dlls/winegstreamer/main.c | 33 ++------ dlls/winegstreamer/media_source.c | 86 +++++++-------------- dlls/winegstreamer/quartz_parser.c | 10 +-- dlls/winegstreamer/unixlib.h | 16 ---- dlls/winegstreamer/wg_parser.c | 104 +++++++------------------- dlls/winegstreamer/wm_reader.c | 11 ++- 10 files changed, 78 insertions(+), 216 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index 9e7d8288edc..9086cdf8038 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -633,7 +633,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME while (event.type != WG_PARSER_EVENT_BUFFER) wg_parser_stream_get_event(converter->stream, &event); - wg_parser_stream_release_buffer(converter->stream, NULL); + wg_parser_stream_release_buffer(converter->stream); converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); @@ -717,7 +717,6 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f struct wg_parser_event event; unsigned char *buffer_data; DWORD buffer_len; - void *gstcookie; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -826,9 +825,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); - - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) { ERR("Failed to copy buffer.\n"); IMFMediaBuffer_Unlock(buffer); @@ -838,7 +835,7 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f IMFMediaBuffer_Unlock(buffer); - wg_parser_stream_release_buffer(converter->stream, gstcookie); + wg_parser_stream_release_buffer(converter->stream); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index b7e65131004..ae1958c67fc 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -629,7 +629,7 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME while (event.type != WG_PARSER_EVENT_BUFFER) wg_parser_stream_get_event(converter->stream, &event); - wg_parser_stream_release_buffer(converter->stream, NULL); + wg_parser_stream_release_buffer(converter->stream); converter->buffer_inflight = FALSE; LeaveCriticalSection(&converter->cs); @@ -721,7 +721,6 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f struct wg_parser_event event; unsigned char *buffer_data; DWORD buffer_len; - void *gstcookie; HRESULT hr = S_OK; TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); @@ -830,9 +829,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f goto done; } - wg_parser_stream_retrieve_buffer(converter->stream, NULL, NULL, &gstcookie); - - if (!wg_parser_stream_copy_buffer(converter->stream, gstcookie, buffer_data, 0, event.u.buffer.size)) + if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) { ERR("Failed to copy buffer.\n"); IMFMediaBuffer_Unlock(buffer); @@ -842,7 +839,7 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f IMFMediaBuffer_Unlock(buffer); - wg_parser_stream_release_buffer(converter->stream, gstcookie); + wg_parser_stream_release_buffer(converter->stream); converter->buffer_inflight = FALSE; if (converter->buffer_pts != -1) diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index 117c8042d93..f84c8659491 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -971,7 +971,6 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, struct pipeline_event pip_event; IMFMediaBuffer *buffer; DWORD buffer_len; - void *gstcookie; unsigned int i; BYTE *data; HRESULT hr; @@ -1121,9 +1120,7 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, goto out; } - wg_parser_stream_retrieve_buffer(decoder->wg_stream, NULL, NULL, &gstcookie); - - if (!wg_parser_stream_copy_buffer(decoder->wg_stream, gstcookie, data, 0, min(buffer_len, event.u.buffer.size))) + if (!wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) { hr = E_FAIL; goto out; @@ -1153,7 +1150,7 @@ static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, out: if (SUCCEEDED(hr)) - wg_parser_stream_release_buffer(decoder->wg_stream, gstcookie); + wg_parser_stream_release_buffer(decoder->wg_stream); LeaveCriticalSection(&decoder->cs); if (FAILED(hr)) diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 0343c75a997..063415ca15f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -90,10 +90,9 @@ void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_fo void wg_parser_stream_disable(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event) DECLSPEC_HIDDEN; -void wg_parser_stream_retrieve_buffer(struct wg_parser_stream *stream, void **user, uint32_t *offset, void **cookie) DECLSPEC_HIDDEN; bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *cookie, void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; -void wg_parser_stream_release_buffer(struct wg_parser_stream *stream, void *cookie) DECLSPEC_HIDDEN; + void *data, uint32_t offset, uint32_t size) DECLSPEC_HIDDEN; +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) DECLSPEC_HIDDEN; void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, bool underflow, double proportion, int64_t diff, uint64_t timestamp) DECLSPEC_HIDDEN; @@ -230,10 +229,6 @@ struct wg_mf_buffer BYTE *data; DWORD max_length; DWORD current_length; - DWORD offset; - - void *gstcookie; - struct wg_parser_stream *wg_stream; }; struct allocator_thread_data { diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 6c58f07205c..211b75e8f3f 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -76,12 +76,7 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) TRACE("%p, refcount %u.\n", iface, refcount); - if (refcount == 1 && buffer->wg_stream && buffer->gstcookie) - { - wg_parser_stream_release_buffer(buffer->wg_stream, buffer->gstcookie); - /* above call may free buffer obj, don't deref past this */ - } - else if (!refcount) + if (!refcount) { free(buffer->data); free(buffer); @@ -99,7 +94,7 @@ static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWO if (!data) return E_INVALIDARG; - *data = buffer->data + buffer->offset; + *data = buffer->data; if (max_length) *max_length = buffer->max_length; if (current_length) @@ -440,25 +435,12 @@ bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parse return !__wine_unix_call(unix_handle, unix_wg_parser_stream_get_event, ¶ms); } -void wg_parser_stream_retrieve_buffer(struct wg_parser_stream *stream, void **user, uint32_t *offset, void **cookie) -{ - struct wg_parser_stream_retrieve_buffer_params params = - { - .stream = stream, - .user = user, - .cookie = cookie, - .offset = offset, - }; - __wine_unix_call(unix_handle, unix_wg_parser_stream_retrieve_buffer, ¶ms); -} - bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, - void *cookie, void *data, uint32_t offset, uint32_t size) + void *data, uint32_t offset, uint32_t size) { struct wg_parser_stream_copy_buffer_params params = { .stream = stream, - .cookie = cookie, .data = data, .offset = offset, .size = size, @@ -467,14 +449,9 @@ bool wg_parser_stream_copy_buffer(struct wg_parser_stream *stream, return !__wine_unix_call(unix_handle, unix_wg_parser_stream_copy_buffer, ¶ms); } -void wg_parser_stream_release_buffer(struct wg_parser_stream *stream, void *cookie) +void wg_parser_stream_release_buffer(struct wg_parser_stream *stream) { - struct wg_parser_stream_release_buffer_params params = - { - .stream = stream, - .cookie = cookie, - }; - __wine_unix_call(unix_handle, unix_wg_parser_stream_release_buffer, ¶ms); + __wine_unix_call(unix_handle, unix_wg_parser_stream_release_buffer, stream); } void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index 0f33e2b62a8..a72d9696894 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -459,9 +459,6 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even IMFSample *sample; HRESULT hr; BYTE *data; - struct wg_mf_buffer *ourbuf = NULL; - void *gstcookie; - uint32_t offset; if (FAILED(hr = MFCreateSample(&sample))) { @@ -469,71 +466,42 @@ static void send_buffer(struct media_stream *stream, const struct wg_parser_even return; } - wg_parser_stream_retrieve_buffer(stream->wg_stream, (void **)&ourbuf, &offset, &gstcookie); - if (ourbuf) + if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer))) { - TRACE("fast path\n"); - /* fast path. using our memory, so return straight to app */ - ourbuf->gstcookie = gstcookie; - ourbuf->wg_stream = stream->wg_stream; - - /* technically, we should spawn a new MediaBuf with this one as parent; - * a different view into the same buffer. hopefully this is good - * enough... */ - ourbuf->offset = offset; - - buffer = &ourbuf->IMFMediaBuffer_iface; - IMFMediaBuffer_AddRef(buffer); - assert(ourbuf->refcount == 2); - - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto out; - } + ERR("Failed to create buffer, hr %#x.\n", hr); + IMFSample_Release(sample); + return; } - else - { - TRACE("slow path: %u bytes\n", event->u.buffer.size); - /* slow path. gst allocated its own memory, so copy it out */ - if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer))) - { - ERR("Failed to create buffer, hr %#x.\n", hr); - IMFSample_Release(sample); - return; - } - - if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) - { - ERR("Failed to set size, hr %#x.\n", hr); - goto out; - } - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) - { - ERR("Failed to lock buffer, hr %#x.\n", hr); - goto out; - } + if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) + { + ERR("Failed to add buffer, hr %#x.\n", hr); + goto out; + } - if (!wg_parser_stream_copy_buffer(stream->wg_stream, gstcookie, data, 0, event->u.buffer.size)) - { - wg_parser_stream_release_buffer(stream->wg_stream, gstcookie); - IMFMediaBuffer_Unlock(buffer); - goto out; - } + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size))) + { + ERR("Failed to set size, hr %#x.\n", hr); + goto out; + } - wg_parser_stream_release_buffer(stream->wg_stream, gstcookie); + if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) + { + ERR("Failed to lock buffer, hr %#x.\n", hr); + goto out; + } - if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) - { - ERR("Failed to unlock buffer, hr %#x.\n", hr); - goto out; - } + if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size)) + { + wg_parser_stream_release_buffer(stream->wg_stream); + IMFMediaBuffer_Unlock(buffer); + goto out; } + wg_parser_stream_release_buffer(stream->wg_stream); - if (FAILED(hr = IMFSample_AddBuffer(sample, buffer))) + if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) { - ERR("Failed to add buffer, hr %#x.\n", hr); + ERR("Failed to unlock buffer, hr %#x.\n", hr); goto out; } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 5ebda720eef..fbbf832af98 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -673,7 +673,6 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, { HRESULT hr; BYTE *ptr = NULL; - void *gstcookie; TRACE("offset %u, size %u, sample size %u\n", offset, size, IMediaSample_GetSize(sample)); @@ -685,17 +684,12 @@ static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, IMediaSample_GetPointer(sample, &ptr); - wg_parser_stream_retrieve_buffer(pin->wg_stream, NULL, NULL, &gstcookie); - - if (!wg_parser_stream_copy_buffer(pin->wg_stream, gstcookie, ptr, offset, size)) + if (!wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size)) { - wg_parser_stream_release_buffer(pin->wg_stream, gstcookie); /* The GStreamer pin has been flushed. */ return S_OK; } - wg_parser_stream_release_buffer(pin->wg_stream, gstcookie); - if (event->u.buffer.has_pts) { REFERENCE_TIME start_pts = event->u.buffer.pts; @@ -798,6 +792,8 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_event IMediaSample_Release(sample); } } + + wg_parser_stream_release_buffer(pin->wg_stream); } static DWORD CALLBACK stream_thread(void *arg) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 707bfe65c0b..576a9f5332a 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -283,29 +283,14 @@ struct wg_parser_stream_get_event_params struct wg_parser_event *event; }; -struct wg_parser_stream_retrieve_buffer_params -{ - struct wg_parser_stream *stream; - void **user; - uint32_t *offset; - void **cookie; -}; - struct wg_parser_stream_copy_buffer_params { struct wg_parser_stream *stream; - void *cookie; void *data; UINT32 offset; UINT32 size; }; -struct wg_parser_stream_release_buffer_params -{ - struct wg_parser_stream *stream; - void *cookie; -}; - struct wg_parser_stream_notify_qos_params { struct wg_parser_stream *stream; @@ -399,7 +384,6 @@ enum unix_funcs unix_wg_parser_stream_disable, unix_wg_parser_stream_get_event, - unix_wg_parser_stream_retrieve_buffer, unix_wg_parser_stream_copy_buffer, unix_wg_parser_stream_release_buffer, unix_wg_parser_stream_notify_qos, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index da9a63510c3..c6c6c369a5e 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -122,6 +122,7 @@ struct wg_parser_stream pthread_cond_t event_cond, event_empty_cond; struct wg_parser_event event; GstBuffer *buffer; + GstMapInfo map_info; bool flushing, eos, enabled, has_caps; @@ -144,11 +145,6 @@ struct wine_memory { void *user; }; -struct wg_buffer_cookie_data { - GstBuffer *gstbuf; - GstMapInfo map_info; -}; - static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) { switch (format) @@ -844,14 +840,13 @@ static NTSTATUS wg_parser_stream_get_event(void *args) return S_OK; } -/* TODO: can we just put this in wg_parser_event::buffer? */ -static NTSTATUS wg_parser_stream_retrieve_buffer(void *args) +static NTSTATUS wg_parser_stream_copy_buffer(void *args) { - struct wg_parser_stream_retrieve_buffer_params *params = args; + const struct wg_parser_stream_copy_buffer_params *params = args; struct wg_parser_stream *stream = params->stream; struct wg_parser *parser = stream->parser; - struct wine_memory *winemem = NULL; - struct wg_buffer_cookie_data *cookie; + uint32_t offset = params->offset; + uint32_t size = params->size; pthread_mutex_lock(&parser->mutex); @@ -862,83 +857,30 @@ static NTSTATUS wg_parser_stream_retrieve_buffer(void *args) } assert(stream->event.type == WG_PARSER_EVENT_BUFFER); + assert(offset < stream->map_info.size); + assert(offset + size <= stream->map_info.size); + memcpy(params->data, stream->map_info.data + offset, size); - cookie = calloc(1, sizeof(*cookie)); - - if (!gst_buffer_map(stream->buffer, &cookie->map_info, GST_MAP_READ)) - { - pthread_mutex_unlock(&parser->mutex); - free(cookie); - GST_ERROR("Failed to map buffer.\n"); - return E_FAIL; - } - - /* transfer ownership */ - cookie->gstbuf = stream->buffer; - stream->buffer = NULL; - - if (params->user) - { - if (!strcmp(cookie->map_info.memory->allocator->mem_type, "wine_memory")) - winemem = (struct wine_memory *)cookie->map_info.memory; - - *params->user = winemem ? winemem->user : NULL; - *params->offset = cookie->map_info.memory->offset; - } - - *params->cookie = cookie; - - stream->event.type = WG_PARSER_EVENT_NONE; - - pthread_cond_signal(&stream->event_empty_cond); pthread_mutex_unlock(&parser->mutex); - return S_OK; } -static NTSTATUS wg_parser_stream_copy_buffer(void *args) +static NTSTATUS wg_parser_stream_release_buffer(void *args) { - const struct wg_parser_stream_copy_buffer_params *params = args; - struct wg_parser_stream *stream = params->stream; + struct wg_parser_stream *stream = args; struct wg_parser *parser = stream->parser; - struct wg_buffer_cookie_data *cookie = params->cookie; - uint32_t offset = params->offset; - uint32_t size = params->size; pthread_mutex_lock(&parser->mutex); - assert(offset < cookie->map_info.size); - assert(offset + size <= cookie->map_info.size); - memcpy(params->data, cookie->map_info.data + offset, size); - - pthread_mutex_unlock(&parser->mutex); - return S_OK; -} - -static NTSTATUS wg_parser_stream_release_buffer(void *args) -{ - const struct wg_parser_stream_release_buffer_params *params = args; - struct wg_parser_stream *stream = params->stream; - struct wg_parser *parser = stream->parser; - struct wg_buffer_cookie_data *cookie = params->cookie; - - if (cookie) - { - gst_buffer_unmap(cookie->gstbuf, &cookie->map_info); - gst_buffer_unref(cookie->gstbuf); - free(cookie); - } - else - { - pthread_mutex_lock(&parser->mutex); + assert(stream->event.type == WG_PARSER_EVENT_BUFFER); - gst_buffer_unref(stream->buffer); - stream->buffer = NULL; - stream->event.type = WG_PARSER_EVENT_NONE; + gst_buffer_unmap(stream->buffer, &stream->map_info); + gst_buffer_unref(stream->buffer); + stream->buffer = NULL; + stream->event.type = WG_PARSER_EVENT_NONE; - pthread_cond_signal(&stream->event_empty_cond); - pthread_mutex_unlock(&parser->mutex); - } + pthread_mutex_unlock(&parser->mutex); + pthread_cond_signal(&stream->event_empty_cond); return S_OK; } @@ -1135,6 +1077,16 @@ static GstFlowReturn queue_stream_event(struct wg_parser_stream *stream, GST_DEBUG("Filter is flushing; discarding event."); return GST_FLOW_FLUSHING; } + if (buffer) + { + assert(GST_IS_BUFFER(buffer)); + if (!gst_buffer_map(buffer, &stream->map_info, GST_MAP_READ)) + { + pthread_mutex_unlock(&parser->mutex); + GST_ERROR("Failed to map buffer.\n"); + return GST_FLOW_ERROR; + } + } stream->event = *event; stream->buffer = buffer; pthread_mutex_unlock(&parser->mutex); @@ -1203,6 +1155,7 @@ static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) if (stream->event.type == WG_PARSER_EVENT_BUFFER) { + gst_buffer_unmap(stream->buffer, &stream->map_info); gst_buffer_unref(stream->buffer); stream->buffer = NULL; } @@ -2982,7 +2935,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_stream_disable), X(wg_parser_stream_get_event), - X(wg_parser_stream_retrieve_buffer), X(wg_parser_stream_copy_buffer), X(wg_parser_stream_release_buffer), X(wg_parser_stream_notify_qos), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 1e088803b8f..489eca05886 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1854,7 +1854,6 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, { DWORD size, capacity; INSSBuffer *sample; - void *gstcookie; HRESULT hr; BYTE *data; @@ -1864,6 +1863,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, stream->index + 1, event.u.buffer.size, &sample, NULL))) { ERR("Failed to allocate stream sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); + wg_parser_stream_release_buffer(wg_stream); return hr; } } @@ -1873,6 +1873,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, stream->index, event.u.buffer.size, &sample, NULL))) { ERR("Failed to allocate output sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr); + wg_parser_stream_release_buffer(wg_stream); return hr; } } @@ -1883,6 +1884,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, /* FIXME: Should these be pooled? */ if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size])))) { + wg_parser_stream_release_buffer(wg_stream); return E_OUTOFMEMORY; } @@ -1902,12 +1904,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, ERR("Returned capacity %u is less than requested capacity %u.\n", capacity, event.u.buffer.size); - wg_parser_stream_retrieve_buffer(wg_stream, NULL, NULL, &gstcookie); - - if (!wg_parser_stream_copy_buffer(wg_stream, gstcookie, data, 0, event.u.buffer.size)) + if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, event.u.buffer.size)) { /* The GStreamer pin has been flushed. */ - wg_parser_stream_release_buffer(wg_stream, gstcookie); INSSBuffer_Release(sample); break; } @@ -1915,7 +1914,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, if (FAILED(hr = INSSBuffer_SetLength(sample, event.u.buffer.size))) ERR("Failed to set size %u, hr %#x.\n", event.u.buffer.size, hr); - wg_parser_stream_release_buffer(wg_stream, gstcookie); + wg_parser_stream_release_buffer(wg_stream); if (!event.u.buffer.has_pts) FIXME("Missing PTS.\n"); From 9417252548ec1ee8b35815b46bea379a7e16ce80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Wed, 16 Feb 2022 10:26:07 +0100 Subject: [PATCH 82/83] Revert "winegstreamer: Add custom allocator for MFMediaBuffer-backed memory" This reverts commit 36b0e9d4bfd8b43bdefb025bf99d530ea74579ad. --- dlls/winegstreamer/audioconvert.c | 2 +- dlls/winegstreamer/colorconvert.c | 2 +- dlls/winegstreamer/decode_transform.c | 2 +- dlls/winegstreamer/gst_private.h | 23 +-- dlls/winegstreamer/main.c | 228 +------------------- dlls/winegstreamer/media_source.c | 21 +- dlls/winegstreamer/quartz_parser.c | 8 +- dlls/winegstreamer/unixlib.h | 27 --- dlls/winegstreamer/wg_parser.c | 286 +------------------------- dlls/winegstreamer/wm_reader.c | 2 +- 10 files changed, 14 insertions(+), 587 deletions(-) diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c index 9086cdf8038..aa9a2984806 100644 --- a/dlls/winegstreamer/audioconvert.c +++ b/dlls/winegstreamer/audioconvert.c @@ -916,7 +916,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) return hr; } - if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true, false))) + if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true))) { ERR("Failed to create audio converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c index ae1958c67fc..476851fa43a 100644 --- a/dlls/winegstreamer/colorconvert.c +++ b/dlls/winegstreamer/colorconvert.c @@ -907,7 +907,7 @@ HRESULT color_converter_create(REFIID riid, void **ret) InitializeCriticalSection(&object->cs); object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true, false))) + if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true))) { ERR("Failed to create video converter due to GStreamer error.\n"); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c index f84c8659491..04d46a73c3d 100644 --- a/dlls/winegstreamer/decode_transform.c +++ b/dlls/winegstreamer/decode_transform.c @@ -1216,7 +1216,7 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) InitializeConditionVariable(&object->help_cv); InitializeConditionVariable(&object->event_cv); - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE, FALSE))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE))) { ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type); IMFTransform_Release(&object->IMFTransform_iface); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 063415ca15f..4d9b9cb10fe 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -64,7 +64,7 @@ static inline const char *debugstr_time(REFERENCE_TIME time) #define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) -struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering, bool use_wine_allocator) DECLSPEC_HIDDEN; +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) DECLSPEC_HIDDEN; void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN; HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) DECLSPEC_HIDDEN; @@ -78,10 +78,6 @@ void wg_parser_end_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size) DECLSPEC_HIDDEN; void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) DECLSPEC_HIDDEN; -bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, - DWORD *size, DWORD *align, void **user) DECLSPEC_HIDDEN; -void wg_parser_provide_alloc_buffer(struct wg_parser *parser, void *data, void *user) DECLSPEC_HIDDEN; - uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index) DECLSPEC_HIDDEN; @@ -221,21 +217,4 @@ HRESULT wm_reader_set_read_compressed(struct wm_reader *reader, HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, const WORD *stream_numbers, const WMT_STREAM_SELECTION *selections); -struct wg_mf_buffer -{ - IMFMediaBuffer IMFMediaBuffer_iface; - LONG refcount; - - BYTE *data; - DWORD max_length; - DWORD current_length; -}; - -struct allocator_thread_data { - BOOL done; - struct wg_parser *wg_parser; -}; - -HANDLE start_allocator_thread(struct allocator_thread_data *) DECLSPEC_HIDDEN; - #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 211b75e8f3f..8c6d8268541 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -33,202 +33,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); DEFINE_GUID(GUID_NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); -#define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment))) - -static inline struct wg_mf_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) -{ - return CONTAINING_RECORD(iface, struct wg_mf_buffer, IMFMediaBuffer_iface); -} - -static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IMFMediaBuffer) || - IsEqualIID(riid, &IID_IUnknown)) - { - *out = &buffer->IMFMediaBuffer_iface; - IMFMediaBuffer_AddRef(iface); - return S_OK; - } - - FIXME("Unsupported %s.\n", debugstr_guid(riid)); - *out = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI memory_buffer_AddRef(IMFMediaBuffer *iface) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - ULONG refcount = InterlockedIncrement(&buffer->refcount); - - TRACE("%p, refcount %u.\n", buffer, refcount); - - return refcount; -} - -static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - ULONG refcount = InterlockedDecrement(&buffer->refcount); - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - { - free(buffer->data); - free(buffer); - } - - return refcount; -} - -static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - - TRACE("%p, %p %p, %p.\n", iface, data, max_length, current_length); - - if (!data) - return E_INVALIDARG; - - *data = buffer->data; - if (max_length) - *max_length = buffer->max_length; - if (current_length) - *current_length = buffer->current_length; - - return S_OK; -} - -static HRESULT WINAPI memory_buffer_Unlock(IMFMediaBuffer *iface) -{ - TRACE("%p.\n", iface); - - return S_OK; -} - -static HRESULT WINAPI memory_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *current_length) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - - TRACE("%p.\n", iface); - - if (!current_length) - return E_INVALIDARG; - - *current_length = buffer->current_length; - - return S_OK; -} - -static HRESULT WINAPI memory_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - - TRACE("%p, %u.\n", iface, current_length); - - if (current_length > buffer->max_length) - return E_INVALIDARG; - - buffer->current_length = current_length; - - return S_OK; -} - -static HRESULT WINAPI memory_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *max_length) -{ - struct wg_mf_buffer *buffer = impl_from_IMFMediaBuffer(iface); - - TRACE("%p, %p.\n", iface, max_length); - - if (!max_length) - return E_INVALIDARG; - - *max_length = buffer->max_length; - - return S_OK; -} - -static const IMFMediaBufferVtbl memory_buffer_vtbl = -{ - memory_buffer_QueryInterface, - memory_buffer_AddRef, - memory_buffer_Release, - memory_buffer_Lock, - memory_buffer_Unlock, - memory_buffer_GetCurrentLength, - memory_buffer_SetCurrentLength, - memory_buffer_GetMaxLength, -}; - -struct wg_mf_buffer *create_memory_buffer(DWORD max_length, DWORD alignment) -{ - struct wg_mf_buffer *buffer; - - if (!(buffer = calloc(1, sizeof(*buffer)))) - return NULL; - - if (!(buffer->data = calloc(1, ALIGN_SIZE(max_length, alignment)))) - { - free(buffer); - return NULL; - } - - buffer->IMFMediaBuffer_iface.lpVtbl = &memory_buffer_vtbl; - buffer->refcount = 1; - buffer->max_length = max_length; - buffer->current_length = 0; - - return buffer; -} - -DWORD CALLBACK allocator_thread(void *arg) -{ - struct allocator_thread_data *data = arg; - enum wg_parser_alloc_req_type type; - - TRACE("Starting alloc thread for parser %p.\n", data->wg_parser); - - while (!data->done) - { - DWORD size, align; - void *user; - - if (!wg_parser_get_next_alloc_req(data->wg_parser, &type, &size, &align, &user)) - continue; - - switch (type) - { - case WG_PARSER_ALLOC_NEW: - { - struct wg_mf_buffer *buf = create_memory_buffer(size, align ? align : 1); - wg_parser_provide_alloc_buffer(data->wg_parser, buf ? buf->data : NULL, buf); - break; - } - case WG_PARSER_ALLOC_FREE: - { - struct wg_mf_buffer *buf = user; - IMFMediaBuffer_Release(&buf->IMFMediaBuffer_iface); - wg_parser_provide_alloc_buffer(data->wg_parser, NULL, NULL); /* mark done */ - break; - } - default: - break; - } - } - - TRACE("Media source is shutting down; exiting alloc thread.\n"); - return 0; -} - -HANDLE start_allocator_thread(struct allocator_thread_data *data) -{ - return CreateThread(NULL, 0, allocator_thread, data, 0, NULL); -} - bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) { unsigned int new_capacity, max_capacity; @@ -256,14 +60,12 @@ bool array_reserve(void **elements, size_t *capacity, size_t count, size_t size) return TRUE; } -struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering, - bool use_wine_allocator) +struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buffering) { struct wg_parser_create_params params = { .type = type, .unlimited_buffering = unlimited_buffering, - .use_wine_allocator = use_wine_allocator, }; if (__wine_unix_call(unix_handle, unix_wg_parser_create, ¶ms)) @@ -344,34 +146,6 @@ void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, c __wine_unix_call(unix_handle, unix_wg_parser_push_data, ¶ms); } -bool wg_parser_get_next_alloc_req(struct wg_parser *parser, enum wg_parser_alloc_req_type *type, - DWORD *size, DWORD *align, void **user) -{ - struct wg_parser_get_next_alloc_req_params params = - { - .parser = parser, - }; - if (__wine_unix_call(unix_handle, unix_wg_parser_get_next_alloc_req, ¶ms)) - return false; - *type = params.type; - *size = params.size; - *align = params.align; - *user = params.user; - return true; -} - -void wg_parser_provide_alloc_buffer(struct wg_parser *parser, void *data, void *user) -{ - struct wg_parser_provide_alloc_buffer_params params = - { - .parser = parser, - .data = data, - .user = user, - }; - - __wine_unix_call(unix_handle, unix_wg_parser_provide_alloc_buffer, ¶ms); -} - uint32_t wg_parser_get_stream_count(struct wg_parser *parser) { struct wg_parser_get_stream_count_params params = diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index a72d9696894..a41205c6e34 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -106,8 +106,7 @@ struct media_source SOURCE_SHUTDOWN, } state; - HANDLE read_thread, alloc_thread; - struct allocator_thread_data alloc_thread_data; + HANDLE read_thread; bool read_thread_shutdown; }; @@ -666,7 +665,7 @@ static DWORD CALLBACK read_thread(void *arg) } free(data); - TRACE("Media source is shutting down; exiting read thread.\n"); + TRACE("Media source is shutting down; exiting.\n"); return 0; } @@ -1347,10 +1346,6 @@ static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface) WaitForSingleObject(source->read_thread, INFINITE); CloseHandle(source->read_thread); - source->alloc_thread_data.done = true; - WaitForSingleObject(source->alloc_thread, INFINITE); - CloseHandle(source->alloc_thread); - IMFPresentationDescriptor_Release(source->pres_desc); IMFMediaEventQueue_Shutdown(source->event_queue); IMFByteStream_Release(source->byte_stream); @@ -1446,7 +1441,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ * never deselects it). Remove buffering limits from decodebin in order to * account for this. Note that this does leak memory, but the same memory * leak occurs with native. */ - if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true, true))) + if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) { hr = E_OUTOFMEMORY; goto fail; @@ -1455,10 +1450,6 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL); - object->alloc_thread_data.done = FALSE; - object->alloc_thread_data.wg_parser = parser; - object->alloc_thread = start_allocator_thread(&object->alloc_thread_data); - object->state = SOURCE_OPENING; if (FAILED(hr = wg_parser_connect(parser, file_size))) @@ -1585,12 +1576,6 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ WaitForSingleObject(object->read_thread, INFINITE); CloseHandle(object->read_thread); } - if (object->alloc_thread) - { - object->alloc_thread_data.done = true; - WaitForSingleObject(object->alloc_thread, INFINITE); - CloseHandle(object->alloc_thread); - } if (object->wg_parser) wg_parser_destroy(object->wg_parser); if (object->async_commands_queue) diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index fbbf832af98..a58fa39e87e 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -1179,7 +1179,7 @@ HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) { free(object); return E_OUTOFMEMORY; @@ -1710,7 +1710,7 @@ HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_WAVPARSE, false, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_WAVPARSE, false))) { free(object); return E_OUTOFMEMORY; @@ -1796,7 +1796,7 @@ HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_AVIDEMUX, false, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_AVIDEMUX, false))) { free(object); return E_OUTOFMEMORY; @@ -1903,7 +1903,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; - if (!(object->wg_parser = wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false, false))) + if (!(object->wg_parser = wg_parser_create(WG_PARSER_MPEGAUDIOPARSE, false))) { free(object); return E_OUTOFMEMORY; diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 576a9f5332a..0be6d267c1f 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -192,7 +192,6 @@ struct wg_parser_create_params struct wg_parser *parser; enum wg_parser_type type; bool unlimited_buffering; - bool use_wine_allocator; }; struct wg_parser_connect_params @@ -217,29 +216,6 @@ struct wg_parser_get_next_read_offset_params UINT64 offset; }; -enum wg_parser_alloc_req_type -{ - WG_PARSER_ALLOC_NONE, - WG_PARSER_ALLOC_NEW, - WG_PARSER_ALLOC_FREE, -}; - -struct wg_parser_get_next_alloc_req_params -{ - struct wg_parser *parser; - enum wg_parser_alloc_req_type type; - DWORD size; - DWORD align; - void *user; -}; - -struct wg_parser_provide_alloc_buffer_params -{ - struct wg_parser *parser; - void *data; - void *user; -}; - struct wg_parser_push_data_params { struct wg_parser *parser; @@ -373,9 +349,6 @@ enum unix_funcs unix_wg_parser_get_next_read_offset, unix_wg_parser_push_data, - unix_wg_parser_get_next_alloc_req, - unix_wg_parser_provide_alloc_buffer, - unix_wg_parser_get_stream_count, unix_wg_parser_get_stream, diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index c6c6c369a5e..f7c319d3c8f 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -64,7 +64,6 @@ struct wg_parser struct wg_parser_stream **streams; unsigned int stream_count, expected_stream_count; - GstAllocator *allocator; GstElement *container, *decodebin; GstBus *bus; GstPad *my_src, *their_sink; @@ -89,21 +88,9 @@ struct wg_parser GstFlowReturn ret; } read_request; - pthread_mutex_t alloc_req_lock, alloc_lock; - pthread_cond_t alloc_cond, alloc_done_cond; - struct - { - enum wg_parser_alloc_req_type type; - DWORD size; - DWORD align; - void *data; - void *user; - bool done; - } alloc_request; - bool flushing, sink_connected, draining; - bool unlimited_buffering, use_wine_allocator; + bool unlimited_buffering; struct wg_format input_format; bool use_mediaconv; @@ -130,21 +117,6 @@ struct wg_parser_stream gchar *language_code; }; -GType WineMemoryAllocator_get_type (void); - -typedef struct -{ - GstAllocator parent; - - struct wg_parser *parser; -} WineMemoryAllocator; - -struct wine_memory { - GstMemory mem; - void *data; - void *user; -}; - static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) { switch (format) @@ -672,46 +644,6 @@ static NTSTATUS wg_parser_push_data(void *args) return S_OK; } -static NTSTATUS wg_parser_get_next_alloc_req(void *args) -{ - struct wg_parser_get_next_alloc_req_params *params = args; - struct wg_parser *parser = params->parser; - - pthread_mutex_lock(&parser->alloc_req_lock); - - while (parser->sink_connected && parser->alloc_request.type == WG_PARSER_ALLOC_NONE) - pthread_cond_wait(&parser->alloc_cond, &parser->alloc_req_lock); - - if (!parser->sink_connected) - { - pthread_mutex_unlock(&parser->alloc_req_lock); - return VFW_E_WRONG_STATE; - } - - params->type = parser->alloc_request.type; - params->size = parser->alloc_request.size; - params->align = parser->alloc_request.align; - params->user = parser->alloc_request.user; - - pthread_mutex_unlock(&parser->alloc_req_lock); - return S_OK; -} - -static NTSTATUS wg_parser_provide_alloc_buffer(void *args) -{ - const struct wg_parser_provide_alloc_buffer_params *params = args; - struct wg_parser *parser = params->parser; - - parser->alloc_request.type = WG_PARSER_ALLOC_NONE; - parser->alloc_request.data = params->data; - parser->alloc_request.user = params->user; - parser->alloc_request.done = true; - - pthread_cond_signal(&parser->alloc_done_cond); - - return S_OK; -} - static NTSTATUS wg_parser_stream_get_preferred_format(void *args) { const struct wg_parser_stream_get_preferred_format_params *params = args; @@ -1301,55 +1233,6 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) return TRUE; } - case GST_QUERY_ALLOCATION: - { - GstCaps *caps; - gboolean need_pool; - - if (stream->parser->allocator) - { - gst_query_parse_allocation(query, &caps, &need_pool); - GST_DEBUG("allocation query, need-pool: %u", need_pool); - - if (need_pool) - { - if (gst_query_get_n_allocation_pools(query) > 0) - { - /* pool exists, so set our allocator on it */ - GstAllocator *old_alloc; - GstAllocationParams old_params; - GstBufferPool *pool; - GstStructure *config; - - GST_DEBUG("adding our alloc to extant pool"); - - gst_query_parse_nth_allocation_pool(query, 0, &pool, NULL, NULL, NULL); - - config = gst_buffer_pool_get_config(pool); - - gst_buffer_pool_config_get_allocator(config, &old_alloc, &old_params); - - gst_buffer_pool_config_set_allocator(config, stream->parser->allocator, &old_params); - - gst_buffer_pool_set_config(pool, config); - } - else - { - /* no pool exists, so return allocator directly for upstream to use */ - GST_DEBUG("no pool, so returning our alloc"); - - assert(gst_query_get_n_allocation_params(query) == 0); /* check that we're using this API correctly */ - - gst_query_add_allocation_param(query, stream->parser->allocator, NULL); - } - } - - return TRUE; - } - - return gst_pad_query_default (pad, parent, query); - } - default: return gst_pad_query_default (pad, parent, query); } @@ -2291,7 +2174,6 @@ static NTSTATUS wg_parser_connect(void *args) parser->sink_connected = false; pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_cond); - pthread_cond_signal(&parser->alloc_cond); if (use_mediaconv) { @@ -2376,7 +2258,6 @@ static NTSTATUS wg_parser_disconnect(void *args) parser->sink_connected = false; pthread_mutex_unlock(&parser->mutex); pthread_cond_signal(&parser->read_cond); - pthread_cond_signal(&parser->alloc_cond); for (i = 0; i < parser->stream_count; ++i) free_stream(parser->streams[i]); @@ -2400,14 +2281,6 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) if (!(element = create_element("decodebin", "base"))) return FALSE; - if (parser->use_wine_allocator) - { - WineMemoryAllocator *alloc; - parser->allocator = g_object_new(WineMemoryAllocator_get_type(), NULL); - alloc = (WineMemoryAllocator *)parser->allocator; - alloc->parser = parser; - } - if (parser->input_format.major_type) g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); @@ -2653,148 +2526,6 @@ static BOOL video_convert_init_gst(struct wg_parser *parser) return TRUE; } -static GstMemory * -wine_memory_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params) -{ - WineMemoryAllocator *alloc = (WineMemoryAllocator *)allocator; - struct wg_parser *parser = alloc->parser; - SIZE_T maxsize = size + params->prefix + params->padding; - struct wine_memory *winemem; - void *data, *user; - - pthread_mutex_lock(&parser->alloc_lock); - pthread_mutex_lock(&parser->alloc_req_lock); - - /* get memory from win32 thread */ - parser->alloc_request.type = WG_PARSER_ALLOC_NEW; - parser->alloc_request.size = maxsize; - parser->alloc_request.align = params ? params->align : 1; - parser->alloc_request.data = NULL; - parser->alloc_request.user = NULL; - pthread_cond_signal(&parser->alloc_cond); - - while (!parser->alloc_request.done) - pthread_cond_wait(&parser->alloc_done_cond, &parser->alloc_req_lock); - - data = parser->alloc_request.data; - user = parser->alloc_request.user; - - parser->alloc_request.done = false; - - pthread_mutex_unlock(&parser->alloc_req_lock); - pthread_mutex_unlock(&parser->alloc_lock); - - if (!data) { - GST_WARNING("Allocating %u bytes failed!", (int)size); - return NULL; - } - - winemem = malloc(sizeof(*winemem)); - winemem->user = user; - winemem->data = data; - - gst_memory_init(&winemem->mem, params->flags, allocator, NULL, - maxsize, params->align, params->prefix, size); - - return &winemem->mem; -} - -static void -wine_memory_free (GstAllocator * allocator, GstMemory * mem) -{ - WineMemoryAllocator *alloc = (WineMemoryAllocator *)allocator; - struct wg_parser *parser = alloc->parser; - struct wine_memory *winemem = (struct wine_memory *)mem; - - if (winemem->user) - { - /* free memory in win32 thread */ - pthread_mutex_lock(&parser->alloc_lock); - pthread_mutex_lock(&parser->alloc_req_lock); - - parser->alloc_request.type = WG_PARSER_ALLOC_FREE; - parser->alloc_request.user = winemem->user; - pthread_cond_signal(&parser->alloc_cond); - - while (!parser->alloc_request.done) - pthread_cond_wait(&parser->alloc_done_cond, &parser->alloc_req_lock); - - parser->alloc_request.type = WG_PARSER_ALLOC_NONE; - parser->alloc_request.done = false; - - pthread_mutex_unlock(&parser->alloc_req_lock); - pthread_mutex_unlock(&parser->alloc_lock); - } - - free(winemem); -} - -static gpointer -wine_memory_mem_map (GstMemory *mem, gsize maxsize, GstMapFlags flags) -{ - struct wine_memory *winemem = (struct wine_memory *)mem; - return winemem->data; -} - -static void -wine_memory_mem_unmap (GstMemory * mem) -{ - /* noop */ -} - -static GstMemory * -wine_memory_mem_share (GstMemory *mem, gssize offset, gssize size) -{ - struct wine_memory *ret = NULL, *winemem = (struct wine_memory *)mem; - GstMemory *parent; - SIZE_T maxsize = sizeof(struct wine_memory); - - ret = malloc(maxsize); - - parent = winemem->mem.parent; - if (!parent) - parent = &winemem->mem; - - ret->user = NULL; - ret->data = winemem->data; - - gst_memory_init(&ret->mem, - GST_MINI_OBJECT_FLAGS(parent) | GST_MINI_OBJECT_FLAG_LOCK_READONLY, - winemem->mem.allocator, parent, - winemem->mem.maxsize, winemem->mem.align, winemem->mem.offset + offset, - size); - - return &ret->mem; -} - -typedef struct -{ - GstAllocatorClass parent_class; -} WineMemoryAllocatorClass; - -G_DEFINE_TYPE (WineMemoryAllocator, WineMemoryAllocator, GST_TYPE_ALLOCATOR); - -static void -WineMemoryAllocator_class_init (WineMemoryAllocatorClass * klass) -{ - GstAllocatorClass *allocator_class; - - allocator_class = (GstAllocatorClass *) klass; - - allocator_class->alloc = wine_memory_alloc; - allocator_class->free = wine_memory_free; -} - -static void -WineMemoryAllocator_init (WineMemoryAllocator * allocator) -{ - GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); - alloc->mem_type = "wine_memory"; - alloc->mem_map = wine_memory_mem_map; - alloc->mem_unmap = wine_memory_mem_unmap; - alloc->mem_share = wine_memory_mem_share; -} - static void init_gstreamer_once(void) { char arg0[] = "wine"; @@ -2865,17 +2596,12 @@ static NTSTATUS wg_parser_create(void *args) return E_OUTOFMEMORY; pthread_mutex_init(&parser->mutex, NULL); - pthread_mutex_init(&parser->alloc_req_lock, NULL); - pthread_mutex_init(&parser->alloc_lock, NULL); pthread_cond_init(&parser->init_cond, NULL); pthread_cond_init(&parser->read_cond, NULL); pthread_cond_init(&parser->read_done_cond, NULL); - pthread_cond_init(&parser->alloc_cond, NULL); - pthread_cond_init(&parser->alloc_done_cond, NULL); parser->flushing = true; parser->init_gst = init_funcs[params->type]; parser->unlimited_buffering = params->unlimited_buffering; - parser->use_wine_allocator = params->use_wine_allocator; GST_DEBUG("Created winegstreamer parser %p.\n", parser); params->parser = parser; @@ -2892,17 +2618,10 @@ static NTSTATUS wg_parser_destroy(void *args) gst_object_unref(parser->bus); } - if (parser->allocator) - g_object_unref(parser->allocator); - pthread_mutex_destroy(&parser->mutex); - pthread_mutex_destroy(&parser->alloc_req_lock); - pthread_mutex_destroy(&parser->alloc_lock); pthread_cond_destroy(&parser->init_cond); pthread_cond_destroy(&parser->read_cond); pthread_cond_destroy(&parser->read_done_cond); - pthread_cond_destroy(&parser->alloc_cond); - pthread_cond_destroy(&parser->alloc_done_cond); free(parser); return S_OK; @@ -2924,9 +2643,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_next_read_offset), X(wg_parser_push_data), - X(wg_parser_get_next_alloc_req), - X(wg_parser_provide_alloc_buffer), - X(wg_parser_get_stream_count), X(wg_parser_get_stream), diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 489eca05886..98847c4b306 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1455,7 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) HRESULT hr; WORD i; - if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true, false))) + if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) return E_OUTOFMEMORY; reader->wg_parser = wg_parser; From eaad88a40bde6507b8839ff72207fa3a619532f5 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 23 Feb 2022 21:06:16 +0000 Subject: [PATCH 83/83] kernelbase: HACK: Force swiftshader + in-process-gpu for Rockstar Social Club 'Fixes' it being one frame behind in all of its rendering. Using WineD3D etc, doesn't help here either, but this works for now. --- dlls/kernelbase/process.c | 1 + 1 file changed, 1 insertion(+) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 01f4ae08721..601164a82a8 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -586,6 +586,7 @@ static const WCHAR *hack_append_command_line( const WCHAR *cmd ) {L"UplayWebCore.exe", L" --use-gl=swiftshader"}, {L"Paradox Launcher.exe", L" --use-gl=swiftshader --in-process-gpu"}, {L"UnrealCEFSubProcess.exe", L" --use-gl=swiftshader"}, + {L"SocialClubHelper.exe", L" --use-gl=swiftshader --in-process-gpu"}, }; unsigned int i;